iOS:使用证书和签名验证文件 - 公钥错误,验证失败

时间:2013-03-15 17:09:09

标签: ios objective-c encryption keychain

我有三件事:文件,签名文件和X509证书文件.cer。必须使用证书中的公钥和签名文件验证该文件。我想使用Security.h / CommonCrypto。

到目前为止我尝试了什么:

// load all the files
NSData* fileData = [NSData dataWithContentsOfFile:(...)];
NSData* signatureData = [NSData dataWithContentsOfFile:(...)];
NSData* certificateData = [NSData dataWithContentsOfFile:(...)];  

SecCertificateRef certificate = SecCertificateCreateWithData(NULL, CFBridgingRetain(certificateData)); // load the certificate

证书加载得很好。可以使用

检查其名称
CFStringRef certificateDescription = SecCertificateCopySubjectSummary(certificate);

哪个有效。 由于iOS上似乎没有直接复制公钥的方法,我首先创建一个信任。

SecTrustRef trust;
OSStatus statusTrust = SecTrustCreateWithCertificates( certificate, secPolicy, &trust);
SecTrustResultType resultType;
OSStatus statusTrustEval =  SecTrustEvaluate(trust, &resultType);

这一切都可以正常使用errSecSuccess结果。

现在我尝试获取公钥。

SecKeyRef publicKey;
publicKey = SecTrustCopyPublicKey(trust);
size_t keysize = SecKeyGetBlockSize(publicKey);

但是publicKey的内容

NSData* keyData = [NSData dataWithBytes:publicKey length:keysize];

与打开.cer文件时看到的公钥不同。所以这是第一个问题。

然后我尝试验证签名,即使我知道公钥是错误的。填充是正确的。

OSStatus verficationResult = SecKeyRawVerify(publicKey,  kSecPaddingPKCS1, [fileData bytes], [fileData length], [signatureData bytes], [signatureData length]);

这失败,OSStatus为-9809(操作无法完成)。我希望它是-25293 errSecAuthFailed。

我做了一些根本错误的事情吗?

2 个答案:

答案 0 :(得分:9)

我在a hint from Apple Dev Forums的帮助下解决了这个问题。

这个问题与钥匙串无关。但我将错误的参数传递给验证功能。它需要数据的摘要(哈希),而不是直接数据。

NSData* fileData = [NSData dataWithContentsOfFile:(...)];
NSData* signatureData = [NSData dataWithContentsOfFile:(...)];
NSData* certificateData = [NSData dataWithContentsOfFile:(...)];  

SecCertificateRef certificateFromFile = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); // load the certificate

SecPolicyRef secPolicy = SecPolicyCreateBasicX509();

SecTrustRef trust;
OSStatus statusTrust = SecTrustCreateWithCertificates( certificateFromFile, secPolicy, &trust);
SecTrustResultType resultType;
OSStatus statusTrustEval =  SecTrustEvaluate(trust, &resultType);
SecKeyRef publicKey = SecTrustCopyPublicKey(trust);

uint8_t sha1HashDigest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1([fileData bytes], [fileData length], sha1HashDigest);

OSStatus verficationResult = SecKeyRawVerify(publicKey,  kSecPaddingPKCS1SHA1, sha1HashDigest, CC_SHA1_DIGEST_LENGTH, [signatureData bytes], [signatureData length]);
CFRelease(publicKey);
CFRelease(trust);
CFRelease(secPolicy);
CFRelease(certificateFromFile);
if (verficationResult == errSecSuccess) NSLog(@"Verified");

答案 1 :(得分:0)

您的问题是在您尝试获取关键数据时:

SecKeyRef publicKey;
publicKey = SecTrustCopyPublicKey(trust);
size_t keysize = SecKeyGetBlockSize(publicKey);
But the content of publicKey

NSData* keyData = [NSData dataWithBytes:publicKey length:keysize];

这不是公钥。这是SecKeyRef数据结构的第一个“X”字节(“X”是公钥的大小)。这没什么特别有用的。

很遗憾,我知道无法直接从SecKeyRef转到NSData。您需要做的是将SecKeyRef放入钥匙串(SecItemAdd),然后将其取回(SecItemCopyMatching并设置kSecReturnData)。当您取回它时,您将公钥作为NSData

(我不知道为什么Apple使Security.framework使用起来非常复杂......)