0

OSX Security フレームワークで動作するプログラムがあります。プログラムを 2 つのモードで開始します。

最初のモードでは、プログラムはいくつかのセキュリティ フレームワーク関数を呼び出します。

  1. SecPCS12Import 関数を呼び出し、秘密鍵を使用して証明書を正常にインポートし、ID ref を作成します。

        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. 前のステップで取得した ID ref を使用して 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;
    

すべてのプログラムが終了した後。

2 番目のモードでは、プログラムは呼び出しの別のリストを作成します。

  1. プログラムの最初の起動からの秘密鍵に対応する DER 形式の証明書を使用して SecCertificateCreateWithData を呼び出し、証明書 ref を正常に作成します。
  2. 前の手順で取得した証明書参照を使用して SecIdentityCreateWithCertificate を呼び出し、ID 参照を正常に作成します。

        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. 前のステップで取得した ID ref を使用して CMSEncodeContent を呼び出し、errSecNoSuchKeychain (-25294) を使用してメッセージの署名に失敗します。ソース コードは、プログラムの最初のモードとまったく同じです。

このバグを修正するにはどうすればよいですか? また、プログラムを 2 番目のモードで起動するたびにこのエラーが発生するのはなぜですか?

4

1 に答える 1

0

コードを 2 番目のモードで書き直します。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 に答える