4

我有三样东西:一个文件、一个签名文件和一个 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。

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

4

2 回答 2

10

我在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");
于 2013-03-20T14:35:10.170 回答
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”是公钥的大小)。这没什么特别有用的。

不幸的是,我不知道直接从 aSecKeyRef到 a 的方法NSData。你要做的就是把它SecKeyRef放入钥匙串(SecItemAdd),然后取回它(SecItemCopyMatchingkSecReturnDataset)。当您取回它时,您将拥有公钥作为NSData.

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

于 2013-03-15T20:20:09.050 回答