我有一个代码,可以在安全框架的帮助下在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
的{{1}}可以正常工作,因此我假设问题与实际数据有关。 ASN.1编码仅支持10.10或类似的东西吗?
更新
我在测试中搞砸了,这实际上也不适用于10.11,这似乎与添加pParameters
有关。
更新2
查看cssmerr.h此错误代码似乎是SecKeyCreateWithData
。
答案 0 :(得分:0)
由于我无法在任何地方找到答案,所以我自己必须解决这个问题,所以我希望这有助于其他人。
我没有找到SecKeyCreateFromData
行为更改的直接解释,但是因为documentation状态:
10.12添加了一个SecKeyCreateWithData,其中没有提到关于对称密钥的任何内容,也许他们在为对称密钥构造SecKeyRef对象。
SecKeyCreateFromData
中添加了一些额外的功能,这可能就是为什么它在10.12及以上时为我工作的原因。
然而,为了获得10.9兼容性,我使用SecItemImport和相同的ASN.1编码序列:
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;
}
这里的诀窍是猜测nFormat
和nType
,但幸运的是我找到了一张表格,其中包含Apple开源资源中的映射以及Github中的[CocoaCryptoMac]。我已经拥有了我的密钥的PKCS1版本,如问题的片段中所示,剩下的工作就是相应地设置格式。 This答案有很多关于PKCS1 / PKCS8的宝贵信息。此外,最初我不确定pKeyData
是否是键的字符串或二进制形式,因为有许多示例使用带有SecKeyCreateFromData
函数的字符串形式。我只是尝试了所有选项,直到二进制版本工作。