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

我有三件事:文件,签名文件和X509证书文件.cer。 必须使用证书中的公钥和签名文件来validation文件。 我想用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文件时看到的公钥不同。 所以这是第一个问题。

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

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

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

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

我借助Apple Dev Forums的提示解决了这个问题。

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

 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"); 

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

 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如此疯狂地使用……)