Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos CMSEncodeContent失败,错误为errSecNoSuchKeychain(-25294)_Macos_Cryptography - Fatal编程技术网

Macos CMSEncodeContent失败,错误为errSecNoSuchKeychain(-25294)

Macos CMSEncodeContent失败,错误为errSecNoSuchKeychain(-25294),macos,cryptography,Macos,Cryptography,我有一个使用OSX安全框架的程序。我以两种模式启动程序 在第一种模式下,程序调用几个安全框架函数: 调用SecPCS12Import函数并成功导入带有私钥的证书并创建标识引用 CFStringRef passwordRef = CFStringCreateWithCString(0, password.c_str(), kCFStringEncodingUTF8); const void *keys[] = { kSecImportExportPassphrase, kSecRe

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

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

  • 调用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;
    
        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;
    
  • 在上一步中使用标识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;
    
  • 在所有节目结束后

    在第二种模式下,程序进行另一些调用列表:

  • 调用SecCertificateCreateWithData,并使用与程序第一次启动时的私钥对应的DER格式的证书,并成功创建证书引用
  • 使用上一步中获得的证书引用调用SecIdentityCreateWithCertificate,并成功创建标识引用

        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;
    
        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;
    
  • 在上一步中调用标识为ref的CMSEncodeContent,但无法使用errSecNoSuchKeychain(-25294)对消息进行签名。源代码与程序的第一种模式完全相同


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

    我在第二种模式下重写代码。我在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;
    

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

    要签名,您需要一个私钥。您说您在“第二种模式”下创建了一个证书,但私钥在哪里?SecIdentityCreateWithCertificate函数的文档说明:如果在指定的密钥链之一中找不到相关的私钥,则此函数将失败,并出现相应的错误代码(通常为errSecItemNotFound),并且不会在identityRef参数中返回任何内容。但你在这个函数中遇到了一个正确的问题。我想我找到了解决办法。