0

我有一个代码,它在安全框架的帮助下在 MacOS 上构造了一个 RSA 公钥。这在 10.11/10.12/10.13 上运行良好,但今天我发现这在 10.9 上失败了。下面是包装密钥的类的构造函数:

CRSAPublicKey(const unsigned char* pExponent, const std::size_t nExponentSize, const unsigned char* pModulus, const std::size_t nModulusSize)
{
    static const SecAsn1Template kRsaPublicKeyTemplate[] = {
        { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ASN1_RSA_PUBLIC_KEY) },
        { SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Modulus), 0, 0 },
        { SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Exponent), 0, 0 },
        { 0, 0, 0, 0 },
    };
    ASN1_RSA_PUBLIC_KEY Asn1Key;
    Asn1Key.m_Modulus.Data = const_cast<unsigned char*>(pModulus);
    Asn1Key.m_Modulus.Length = nModulusSize;
    Asn1Key.m_Exponent.Data = const_cast<unsigned char*>(pExponent);
    Asn1Key.m_Exponent.Length = nExponentSize;
    MacOS::CAsn1CoderReference pAsn1Coder;
    OSStatus nStatus = SecAsn1CoderCreate(&pAsn1Coder);
    // Check nStatus
    SecAsn1Item DerKey;
    nStatus = SecAsn1EncodeItem(pAsn1Coder, &Asn1Key, kRsaPublicKeyTemplate, &DerKey);
    // Check nStatus
    const void* pKeys[] = { kSecAttrKeyType, kSecAttrKeyClass };
    const void* pValues[] = { kSecAttrKeyTypeRSA, kSecAttrKeyClassPublic };
    MacOS::CReference<CFDictionaryRef> pParameters(CFDictionaryCreate(kCFAllocatorDefault, pKeys, pValues, 2, nullptr, nullptr));
    // Check pParameters
    MacOS::CReference<CFDataRef> pKeyData(CFDataCreate(kCFAllocatorDefault, DerKey.Data, static_cast<CFIndex>(DerKey.Length)));
    // Check pKeyData
    MacOS::CReference<CFErrorRef> pError;
    m_PublicKey = SecKeyCreateFromData(pParameters, pKeyData, &pError);
    // Check m_PublicKey - this fails with "The operation couldn’t be completed. (OSStatus error -2147415792.)"
}

我删除了一些检查宏等,但这应该说明调用顺序。在 10.9 上,我得到一个空指针,SecKeyCreateFromData错误代码为 -2147415792。我尝试添加kSecAttrKeySizeInBits但没有帮助。同时SecKeyGeneratePair,同样的pParameters工作正常,所以我认为问题出在实际数据上。是否仅从 10.10 或类似版本支持 ASN.1 编码?

更新

我在测试中搞砸了,这实际上在 10.11 上也不起作用,这似乎与 add 相关SecKeyCreateWithData

更新 2

查看cssmerr.h这个错误代码似乎是CSSMERR_CSP_INVALID_KEY

4

1 回答 1

0

由于我在任何地方都没有找到答案,所以我必须自己解决这个问题,所以我希望这对其他人有帮助。

我没有找到对 的行为变化的直接解释SecKeyCreateFromData,但由于文档指出:

为对称密钥构造一个 SecKeyRef 对象。

10.12 添加了一个SecKeyCreateWithData,它没有提到任何关于对称密钥的内容,也许他们也添加了一些额外SecKeyCreateFromData的功能,这可能就是为什么它在 10.12 及更高版本上对我有用。

尽管如此,为了获得 10.9 的兼容性,我使用了具有相同 ASN.1 编码序列的SecItemImport :

static SecKeyRef ImportPkcs1PublicKey(const unsigned char* pExponent, const std::size_t nExponentSize, const unsigned char* pModulus, const std::size_t nModulusSize)
{
    static const SecAsn1Template kRsaPublicKeyTemplate[] = {
        { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ASN1_RSA_PUBLIC_KEY) },
        { SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Modulus), 0, 0 },
        { SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Exponent), 0, 0 },
        { 0, 0, 0, 0 },
    };
    ASN1_RSA_PUBLIC_KEY Asn1Key;
    Asn1Key.m_Modulus.Data = const_cast<unsigned char*>(pModulus);
    Asn1Key.m_Modulus.Length = nModulusSize;
    Asn1Key.m_Exponent.Data = const_cast<unsigned char*>(pExponent);
    Asn1Key.m_Exponent.Length = nExponentSize;
    MacOS::CAsn1CoderReference pAsn1Coder;
    OSStatus nStatus = SecAsn1CoderCreate(&pAsn1Coder);
    // Check nStatus and pAsn1Coder
    SecAsn1Item DerKey;
    nStatus = SecAsn1EncodeItem(pAsn1Coder, &Asn1Key, kRsaPublicKeyTemplate, &DerKey);
    // Check nStatus
    MacOS::CReference<CFDataRef> pKeyData(CFDataCreate(kCFAllocatorDefault, DerKey.Data, static_cast<CFIndex>(DerKey.Length)));
    // Check pKeyData
    SecExternalFormat nFormat = kSecFormatBSAFE;
    SecExternalItemType nType = kSecItemTypePublicKey;
    MacOS::CReference<CFArrayRef> pItems;
    nStatus = SecItemImport(pKeyData, NULL, &nFormat, &nType, 0, NULL, NULL, &pItems);
    // Check nStatus
    SecKeyRef pKey = reinterpret_cast<SecKeyRef>(const_cast<void*>(CFArrayGetValueAtIndex(pItems, 0)));
    // Check pKey
    CFRetain(pKey);
    return pKey;
}

这里的技巧是猜测nFormatand nType,但幸运的是我在 Apple 开源源代码和 Github 中的 [CocoaCryptoMac] 中找到了一个映射表。如问题片段中所示,我的密钥已经有了 PKCS1 版本,剩下的工作就是相应地设置格式。这个答案有很多关于 PKCS1/PKCS8 的有价值的信息。另外,最初我不确定pKeyData键是字符串形式还是二进制形式,因为有很多示例将字符串形式与SecKeyCreateFromData函数一起使用。我只是尝试了所有选项,直到二进制版本工作。

于 2018-04-23T17:09:16.687 回答