0

我有一个适用于 OSX 安全框架的程序。我以两种模式启动我的程序。

在第一种模式下,程序调用几个安全框架函数:

  1. 调用 SecPCS12Import 函数并成功导入带有私钥的证书并创建身份参考。

        CFStringRef passwordRef = CFStringCreateWithCString(0, password.c_str(), kCFStringEncodingUTF8);
        const void *keys[] = { kSecImportExportPassphrase, kSecReturnRef };
        const void *values[] = { passwordRef, kCFBooleanTrue };
        CFDictionaryRef optionsDictionary = CFDictionaryCreate(0, keys, values, 2, 0, 0);
        CFDataRef inPKCS12Data = CFDataCreate(0, (const UInt8*)data.data(), data.size());
        CFArrayRef items = 0;
        OSStatus status = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
        CFRelease(passwordRef);
        CFRelease(optionsDictionary);
        CFRelease(inPKCS12Data);
    
        throwIfError(errSecSuccess != status);
    
        CFDictionaryRef myIdentityAndTrust = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
        SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
        KeyInfo info(alias, OSStoreImplementation::getCertificate(identity));
        IKey::Ptr result = new OSKey(info, new OSKeyImplementation(identity, false));
        CFRelease(items);
        return result;
    
  2. 使用上一步中的身份引用调用 CMSEncodeContent 并成功签署消息。

        CFDataRef content = 0;
        CMSSignedAttributes signedAttributes = kCMSAttrSmimeCapabilities | kCMSAttrSmimeMSEncryptionKeyPrefs;
        throwIfError(errSecSuccess == CMSEncodeContent(_identity, 0, 0, FALSE, signedAttributes, message.data(), message.size(), &content));
        char* buf = (char*)CFDataGetBytePtr(content);
        const ByteArray result(buf, buf + CFDataGetLength(content));
        CFRelease(content);
        return result;
    

在所有程序结束之后。

在第二种模式下,程序会创建另一个调用列表:

  1. 从程序的第一次启动开始,使用与私钥对应的 DER 格式的证书调用 SecCertificateCreateWithData 并成功创建证书引用。
  2. 使用上一步中获得的证书 ref 调用 SecIdentityCreateWithCertificate 并成功创建身份 ref。

        CFDataRef content = CFCreateData(0, info.certificate.getData().data(), info.certificate.getData().size());
        SecCertificateRef cert = SecCertificateCreateWithData(0, content);
        CFRelease(content);
        SecIdentityRef identity = 0;
        OSStatus status = SecIdentityCreateWithCertificate(0, cert, &identity);
        CFRelease(cert);
    
        throwIfError(errSecSuccess != status);
    
        KeyPtr result = new OSKey(info, new OSKeyImplementation(identity, true));
        CFReleases(identity);
        return result;
    
  3. 使用上一步中的标识 ref 调用 CMSEncodeContent 并且无法使用 errSecNoSuchKeychain (-25294) 签署消息。源代码与程序的第一种模式完全相同。

如何修复此错误以及为什么每次以第二种模式启动程序时都会发生此错误?

4

1 回答 1

0

我以第二种模式重写我的代码。我在 SecItemCopyMatching 上更改了 SecIdentityCreateWithCertificate。

        CFDataRef content = CFCreateData(0, info.certificate.getData().data(), info.certificate.getData().size());
        SecCertificateRef cert = SecCertificateCreateWithData(0, content);
        CFRelease(content);
        const void* data[] = { cert };
        CFArrayRef secItemOrArray = CFArrayCreate(0, data, 1, 0);
        const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchItemList };
        const void *values[] = { kSecClassIdentity, kCFBooleanTrue, secItemOrArray };
        CFDictionaryRef attributes = CFDictionaryCreate(0, keys, values, 3, 0, 0);
        SecIdentityRef identity = 0;
        OSStatus status = SecItemCopyMatching(attributes, (CFTypeRef*)&identity));
        CFRelease(attributes);
        throwIfError(errSecSuccess != status);
        KeyPtr result = new OSKey(info, new OSKeyImplementation(identity, true));
        CFReleases(identity);
        return result;

新版本正常工作。所以我找到了满足我需要的解决方案,但我仍然不明白为什么我以前的代码不起作用。

于 2012-10-23T08:32:58.577 回答