SecKeyCreateFromData 在 10.9 上失败并显示 -2147415792
SecKeyCreateFromData fails on 10.9 with -2147415792
我有一段代码可以在安全框架的帮助下在 MacOS 上构建 RSA public 密钥。这在 10.11/10.12/10.13 上工作正常,但今天我发现这在 10.9 上失败了。下面是包装密钥的 class 的构造函数:
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 上也不起作用,这似乎与添加相关 SecKeyCreateWithData
。
更新 2
查看 cssmerr.h 这个错误代码似乎是 CSSMERR_CSP_INVALID_KEY
。
由于我在任何地方都找不到答案,所以我不得不自己解决这个问题,所以我希望这对其他人有所帮助。
我没有找到 SecKeyCreateFromData
行为变化的直接解释,但由于 documentation 声明:
Constructs a SecKeyRef object for a symmetric key.
10.12 添加了一个 SecKeyCreateWithData,它没有提及任何关于对称密钥的内容,也许他们也在 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 开源源代码中找到了 table 映射,在 [=33= 中找到了 [CocoaCryptoMac] ].我的密钥已经有了 PKCS1 版本,如问题中的片段所示,剩下的工作只是相应地设置格式。 This 回答有很多关于 PKCS1/PKCS8 的有价值的信息。此外,最初我不确定 pKeyData
是密钥的字符串形式还是二进制形式,因为有很多示例将字符串形式与 SecKeyCreateFromData
函数一起使用。我只是尝试了所有选项,直到二进制版本起作用。
我有一段代码可以在安全框架的帮助下在 MacOS 上构建 RSA public 密钥。这在 10.11/10.12/10.13 上工作正常,但今天我发现这在 10.9 上失败了。下面是包装密钥的 class 的构造函数:
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 上也不起作用,这似乎与添加相关 SecKeyCreateWithData
。
更新 2
查看 cssmerr.h 这个错误代码似乎是 CSSMERR_CSP_INVALID_KEY
。
由于我在任何地方都找不到答案,所以我不得不自己解决这个问题,所以我希望这对其他人有所帮助。
我没有找到 SecKeyCreateFromData
行为变化的直接解释,但由于 documentation 声明:
Constructs a SecKeyRef object for a symmetric key.
10.12 添加了一个 SecKeyCreateWithData,它没有提及任何关于对称密钥的内容,也许他们也在 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 开源源代码中找到了 table 映射,在 [=33= 中找到了 [CocoaCryptoMac] ].我的密钥已经有了 PKCS1 版本,如问题中的片段所示,剩下的工作只是相应地设置格式。 This 回答有很多关于 PKCS1/PKCS8 的有价值的信息。此外,最初我不确定 pKeyData
是密钥的字符串形式还是二进制形式,因为有很多示例将字符串形式与 SecKeyCreateFromData
函数一起使用。我只是尝试了所有选项,直到二进制版本起作用。