-
-
-/* iOS SecKey shim functions */
-
-#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
-
-/* Currently length of SHA512 oid + 1 */
-#define MAX_OID_LEN (10)
-
-#define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
-
-/* Encode the digestInfo header into digestInfo and return the offset from
- digestInfo at which to put the actual digest. Returns 0 if digestInfo
- won't fit within digestInfoLength bytes.
-
- 0x30, topLen,
- 0x30, algIdLen,
- 0x06, oid.Len, oid.Data,
- 0x05, 0x00
- 0x04, digestLen
- digestData
- */
-static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid,
- size_t digestLength,
- uint8_t *digestInfo,
- size_t digestInfoLength)
-{
- size_t algIdLen = oid->Length + 4;
- size_t topLen = algIdLen + digestLength + 4;
- size_t totalLen = topLen + 2;
-
- if (totalLen > digestInfoLength) {
- return 0;
- }
-
- size_t ix = 0;
- digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
- digestInfo[ix++] = topLen;
- digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
- digestInfo[ix++] = algIdLen;
- digestInfo[ix++] = SEC_ASN1_OBJECT_ID;
- digestInfo[ix++] = oid->Length;
- memcpy(&digestInfo[ix], oid->Data, oid->Length);
- ix += oid->Length;
- digestInfo[ix++] = SEC_ASN1_NULL;
- digestInfo[ix++] = 0;
- digestInfo[ix++] = SEC_ASN1_OCTET_STRING;
- digestInfo[ix++] = digestLength;
-
- return ix;
-}
-
-static OSStatus SecKeyGetDigestInfo(SecKeyRef key, const SecAsn1AlgId *algId,
- const uint8_t *data, size_t dataLen, bool digestData,
- uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */)
-{
- unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *);
- CFIndex keyAlgID = kSecNullAlgorithmID;
- const SecAsn1Oid *digestOid;
- size_t digestLen;
- size_t offset = 0;
-
- /* Since these oids all have the same prefix, use switch. */
- if ((algId->algorithm.Length == CSSMOID_RSA.Length) &&
- !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data,
- algId->algorithm.Length - 1)) {
- keyAlgID = kSecRSAAlgorithmID;
- switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
-#if 0
- case 2: /* oidMD2WithRSA */
- digestFcn = CC_MD2;
- digestLen = CC_MD2_DIGEST_LENGTH;
- digestOid = &CSSMOID_MD2;
- break;
- case 3: /* oidMD4WithRSA */
- digestFcn = CC_MD4;
- digestLen = CC_MD4_DIGEST_LENGTH;
- digestOid = &CSSMOID_MD4;
- break;
- case 4: /* oidMD5WithRSA */
- digestFcn = CC_MD5;
- digestLen = CC_MD5_DIGEST_LENGTH;
- digestOid = &CSSMOID_MD5;
- break;
-#endif /* 0 */
- case 5: /* oidSHA1WithRSA */
- digestFcn = CC_SHA1;
- digestLen = CC_SHA1_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA1;
- break;
- case 11: /* oidSHA256WithRSA */
- digestFcn = CC_SHA256;
- digestLen = CC_SHA256_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA256;
- break;
- case 12: /* oidSHA384WithRSA */
- /* pkcs1 12 */
- digestFcn = CC_SHA384;
- digestLen = CC_SHA384_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA384;
- break;
- case 13: /* oidSHA512WithRSA */
- digestFcn = CC_SHA512;
- digestLen = CC_SHA512_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA512;
- break;
- case 14: /* oidSHA224WithRSA */
- digestFcn = CC_SHA224;
- digestLen = CC_SHA224_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA224;
- break;
- default:
- secdebug("key", "unsupported rsa signature algorithm");
- return errSecUnsupportedAlgorithm;
- }
- } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) &&
- !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data,
- algId->algorithm.Length - 1)) {
- keyAlgID = kSecECDSAAlgorithmID;
- switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
- case 1: /* oidSHA224WithECDSA */
- digestFcn = CC_SHA224;
- digestLen = CC_SHA224_DIGEST_LENGTH;
- break;
- case 2: /* oidSHA256WithECDSA */
- digestFcn = CC_SHA256;
- digestLen = CC_SHA256_DIGEST_LENGTH;
- break;
- case 3: /* oidSHA384WithECDSA */
- /* pkcs1 12 */
- digestFcn = CC_SHA384;
- digestLen = CC_SHA384_DIGEST_LENGTH;
- break;
- case 4: /* oidSHA512WithECDSA */
- digestFcn = CC_SHA512;
- digestLen = CC_SHA512_DIGEST_LENGTH;
- break;
- default:
- secdebug("key", "unsupported ecdsa signature algorithm");
- return errSecUnsupportedAlgorithm;
- }
- } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) {
- keyAlgID = kSecECDSAAlgorithmID;
- digestFcn = CC_SHA1;
- digestLen = CC_SHA1_DIGEST_LENGTH;
- } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) {
- digestFcn = CC_SHA1;
- digestLen = CC_SHA1_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA1;
- } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) &&
- !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1))
- {
- switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
- case 4: /* OID_SHA224 */
- digestFcn = CC_SHA224;
- digestLen = CC_SHA224_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA224;
- break;
- case 1: /* OID_SHA256 */
- digestFcn = CC_SHA256;
- digestLen = CC_SHA256_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA256;
- break;
- case 2: /* OID_SHA384 */
- /* pkcs1 12 */
- digestFcn = CC_SHA384;
- digestLen = CC_SHA384_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA384;
- break;
- case 3: /* OID_SHA512 */
- digestFcn = CC_SHA512;
- digestLen = CC_SHA512_DIGEST_LENGTH;
- digestOid = &CSSMOID_SHA512;
- break;
- default:
- secdebug("key", "unsupported sha-2 signature algorithm");
- return errSecUnsupportedAlgorithm;
- }
- } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) {
- digestFcn = CC_MD5;
- digestLen = CC_MD5_DIGEST_LENGTH;
- digestOid = &CSSMOID_MD5;
- } else {
- secdebug("key", "unsupported digesting algorithm");
- return errSecUnsupportedAlgorithm;
- }
-
- /* check key is appropriate for signature (superfluous for digest only oid) */
- {
- CFIndex supportedKeyAlgID = kSecNullAlgorithmID;
- #if TARGET_OS_EMBEDDED
- supportedKeyAlgID = SecKeyGetAlgorithmID(key);
- #else
- const CSSM_KEY* temporaryKey;
- SecKeyGetCSSMKey(key, &temporaryKey);
- CSSM_ALGORITHMS tempAlgorithm = temporaryKey->KeyHeader.AlgorithmId;
- if (CSSM_ALGID_RSA == tempAlgorithm) {
- supportedKeyAlgID = kSecRSAAlgorithmID;
- } else if (CSSM_ALGID_ECDSA == tempAlgorithm) {
- supportedKeyAlgID = kSecECDSAAlgorithmID;
- }
- #endif
-
- if (keyAlgID == kSecNullAlgorithmID) {
- keyAlgID = supportedKeyAlgID;
- }
- else if (keyAlgID != supportedKeyAlgID) {
- return errSecUnsupportedAlgorithm;
- }
- }
-
- switch(keyAlgID) {
- case kSecRSAAlgorithmID:
- offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
- digestInfo, *digestInfoLen);
- if (!offset)
- return errSecBufferTooSmall;
- break;
- case kSecDSAAlgorithmID:
- if (digestOid != &CSSMOID_SHA1)
- return errSecUnsupportedAlgorithm;
- break;
- case kSecECDSAAlgorithmID:
- break;
- default:
- secdebug("key", "unsupported signature algorithm");
- return errSecUnsupportedAlgorithm;
- }
-
- if (digestData) {
- if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */
- return errSecParam;
- digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]);
- *digestInfoLen = offset + digestLen;
- } else {
- if (dataLen != digestLen)
- return errSecParam;
- memcpy(&digestInfo[offset], data, dataLen);
- *digestInfoLen = offset + dataLen;
- }
-
- return errSecSuccess;
-}
-
-OSStatus SecKeyVerifyDigest(
- SecKeyRef key, /* Private key */
- const SecAsn1AlgId *algId, /* algorithm oid/params */
- const uint8_t *digestData, /* signature over this digest */
- size_t digestDataLen, /* length of dataToDigest */
- const uint8_t *sig, /* signature to verify */
- size_t sigLen) /* length of sig */
-{
- size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
- uint8_t digestInfo[digestInfoLength];
- OSStatus status;
-
- status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false /* data is digest */,
- digestInfo, &digestInfoLength);
- if (status)
- return status;
- return SecKeyRawVerify(key, kSecPaddingPKCS1,
- digestInfo, digestInfoLength, sig, sigLen);
-}
-
-OSStatus SecKeySignDigest(
- SecKeyRef key, /* Private key */
- const SecAsn1AlgId *algId, /* algorithm oid/params */
- const uint8_t *digestData, /* signature over this digest */
- size_t digestDataLen, /* length of digestData */
- uint8_t *sig, /* signature, RETURNED */
- size_t *sigLen) /* IN/OUT */
-{
- size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
- uint8_t digestInfo[digestInfoLength];
- OSStatus status;
-
- status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false,
- digestInfo, &digestInfoLength);
- if (status)
- return status;
- return SecKeyRawSign(key, kSecPaddingPKCS1,
- digestInfo, digestInfoLength, sig, sigLen);
-}
-
-/* It's debatable whether this belongs here or in the ssl code since the
- curve values come from a tls related rfc4492. */
-SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key)
-{
- try {
- SecPointer<KeyItem> keyItem(KeyItem::required(key));
- switch (keyItem->key().header().LogicalKeySizeInBits) {
-#if 0
- case 192:
- return kSecECCurveSecp192r1;
- case 224:
- return kSecECCurveSecp224r1;
-#endif
- case 256:
- return kSecECCurveSecp256r1;
- case 384:
- return kSecECCurveSecp384r1;
- case 521:
- return kSecECCurveSecp521r1;
- }
- }
- catch (...) {}
- return kSecECCurveNone;
-}
-
-static inline CFDataRef _CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
-{
- return CFDataCreateWithBytesNoCopy(allocator,
- CFDataGetBytePtr(sourceData) + range.location, range.length,
- kCFAllocatorNull);
-}
-
-static inline CFDataRef _CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
-{
- return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
-}
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function"
-static inline bool _CFDataEquals(CFDataRef left, CFDataRef right)
-{
- return (left != NULL) &&
- (right != NULL) &&
- (CFDataGetLength(left) == CFDataGetLength(right)) &&
- (0 == memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), (size_t)CFDataGetLength(left)));
-}
-#pragma clang diagnostic pop
-
-#if ECDSA_DEBUG
-void secdump(const unsigned char *data, unsigned long len)
-{
- unsigned long i;
- char s[128];
- char t[32];
- s[0]=0;
- for(i=0;i<len;i++)
- {
- if((i&0xf)==0) {
- sprintf(t, "%04lx :", i);
- strcat(s, t);
- }
- sprintf(t, " %02x", data[i]);
- strcat(s, t);
- if((i&0xf)==0xf) {
- strcat(s, "\n");
- syslog(LOG_NOTICE, s);
- s[0]=0;
- }
- }
- strcat(s, "\n");
- syslog(LOG_NOTICE, s);
-}
-#endif
-
-OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes)
-{
- CFIndex keyAlgId;
-#if TARGET_OS_EMBEDDED
- keyAlgId = SecKeyGetAlgorithmID(key);
-#else
- keyAlgId = SecKeyGetAlgorithmId(key);
-#endif
-
- OSStatus ecStatus = errSecParam;
- CFDataRef tempPublicData = NULL;
- CFDataRef headerlessPublicData = NULL;
- CFIndex headerLength = 0;
- const UInt8* pData_Ptr = NULL;
-
- if (kSecRSAAlgorithmID == keyAlgId)
- {
- return SecItemExport(key, kSecFormatBSAFE, 0, NULL, publicBytes);
- }
-
- if (kSecECDSAAlgorithmID == keyAlgId)
- {
- // First export the key so there is access to the underlying key material
- ecStatus = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, &tempPublicData);
- if(ecStatus != errSecSuccess)
- {
- secdebug("key", "SecKeyCopyPublicBytes: SecItemExport error (%d) for ECDSA public key %p",
- ecStatus, (uintptr_t)key);
-
- return ecStatus;
- }
-
-
- // Get a pointer to the first byte of the exported data
- pData_Ptr = CFDataGetBytePtr(tempPublicData);
-
- // the first byte should be a sequence 0x30
- if (*pData_Ptr != 0x30)
- {
- secdebug("key", "SecKeyCopyPublicBytes: exported data is invalid");
- if (NULL != tempPublicData)
- CFRelease(tempPublicData);
-
- ecStatus = errSecParam;
- return ecStatus;
- }
-
- // move past the sequence byte
- pData_Ptr++;
-
- // Check to see if the high bit is set which
- // indicates that the length will be at least
- // two bytes. If the high bit is set then
- // The lower seven bits specifies the number of
- // bytes used for the length. The additonal 1
- // is for the current byte. Otherwise just move past the
- // single length byte
- pData_Ptr += (*pData_Ptr & 0x80) ? ((*pData_Ptr & 0x7F) + 1) : 1;
-
- // The current byte should be a sequence 0x30
- if (*pData_Ptr != 0x30)
- {
- secdebug("key", "SecKeyCopyPublicBytes: Could not find the key sequence");
- if (NULL != tempPublicData) {
- CFRelease(tempPublicData);
- }
- ecStatus = errSecParam;
- return ecStatus;
- }
-
- // The next bytes will always be the same
- // 0x30 = SEQUENCE
- // XX Length Byte
- // 0x06 OBJECT ID
- // 0x07 Length Byte
- // ECDSA public KEY OID value 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01
- // 0x06 OBJECT ID
- // This is a total of 12 bytes
- pData_Ptr += 12;
-
- // Next byte is the length of the ECDSA curve OID
- // Move past the length byte and the curve OID
- pData_Ptr += (((int)*pData_Ptr) + 1);
-
- // Should be at a BINARY String which is specifed by a 0x3
- if (*pData_Ptr != 0x03)
- {
- secdebug("key", "SecKeyCopyPublicBytes: Invalid key structure");
- if (NULL != tempPublicData) {
- CFRelease(tempPublicData);
- }
- ecStatus = errSecParam;
- return ecStatus;
- }
-
- // Move past the BINARY String specifier 0x03
- pData_Ptr++;
-
-
- // Check to see if the high bit is set which
- // indicates that the length will be at least
- // two bytes. If the high bit is set then
- // The lower seven bits specifies the number of
- // bytes used for the length. The additonal 1
- // is for the current byte. Otherwise just move past the
- // single length byte
- pData_Ptr += (*pData_Ptr & 0x80) ? ((*pData_Ptr & 0x7F) + 1) : 1;
-
- // Move past the beginning marker for the BINARY String 0x00
- pData_Ptr++;
-
- // pData_Ptr now points to the first bytes of the key material
- headerLength = (CFIndex)(((intptr_t)pData_Ptr) - ((intptr_t)CFDataGetBytePtr(tempPublicData)));
-
- headerlessPublicData = _CFDataCreateCopyFromRange(kCFAllocatorDefault,
- tempPublicData, CFRangeMake(headerLength, CFDataGetLength(tempPublicData) - headerLength));
-
- if (!headerlessPublicData)
- {
- printf("SecKeyCopyPublicBytes: headerlessPublicData is nil (1)\n");
- if (NULL != tempPublicData)
- CFRelease(tempPublicData);
-
- ecStatus = errSecParam;
-
- return ecStatus;
- }
-
- if (publicBytes)
- {
- *publicBytes = headerlessPublicData;
- }
-
- ecStatus = errSecSuccess;
-
- if (NULL != tempPublicData)
- CFRelease(tempPublicData);
-
- return ecStatus;
- }
-
- return errSecParam;
-}
-
-
-CFDataRef SecECKeyCopyPublicBits(SecKeyRef key)
-{
- CFDataRef exportedKey;
- if(SecKeyCopyPublicBytes(key, &exportedKey) != errSecSuccess) {
- exportedKey = NULL;
- }
- return exportedKey;
-}
-
-SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef publicBytes)
-{
- SecExternalFormat externalFormat = kSecFormatOpenSSL;
- SecExternalItemType externalItemType = kSecItemTypePublicKey;
- CFDataRef workingData = NULL;
- CFArrayRef outArray = NULL;
- SecKeyRef retVal = NULL;
-
- if (kSecRSAAlgorithmID == algorithmID) {
- /*
- * kSecFormatBSAFE uses the original PKCS#1 definition:
- * RSAPublicKey ::= SEQUENCE {
- * modulus INTEGER, -- n
- * publicExponent INTEGER -- e
- * }
- * kSecFormatOpenSSL uses different ASN.1 encoding.
- */
- externalFormat = kSecFormatBSAFE;
- workingData = _CFDataCreateReferenceFromRange(kCFAllocatorDefault, publicBytes, CFRangeMake(0, CFDataGetLength(publicBytes)));
- } else if (kSecECDSAAlgorithmID == algorithmID) {
- CFMutableDataRef tempData;
- uint8 requiredFirstDERByte [] = {0x04};
- uint8 placeholder[1];
- uint8 headerBytes[] = { 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,
- 0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
- 0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
- 0x42,0x00 };
-
- /* FIXME: this code only handles one specific curve type; need to expand this */
- if(CFDataGetLength(publicBytes) != 65)
- goto cleanup;
-
- CFDataGetBytes(publicBytes, CFRangeMake(0, 1), placeholder);
-
- if(requiredFirstDERByte[0] != placeholder[0])
- goto cleanup;
-
-
- tempData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- CFDataAppendBytes(tempData, headerBytes, sizeof(headerBytes));
- CFDataAppendBytes(tempData, CFDataGetBytePtr(publicBytes), CFDataGetLength(publicBytes));
-
- workingData = tempData;
- }
- if(SecItemImport(workingData, NULL, &externalFormat, &externalItemType, 0, NULL, NULL, &outArray) != errSecSuccess) {
- goto cleanup;
- }
- if(!outArray || CFArrayGetCount(outArray) == 0) {
- goto cleanup;
- }
- retVal = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
- CFRetain(retVal);
-
-cleanup:
- if(workingData) CFRelease(workingData);
- if(outArray) CFRelease(outArray);
- return retVal;
-}
-
-SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator,
- const uint8_t *keyData, CFIndex keyDataLength,
- SecKeyEncoding encoding)
-{
- CFDataRef pubKeyData = NULL;
- if(kSecKeyEncodingPkcs1 == encoding) {
- /* DER-encoded according to PKCS1. */
- pubKeyData = CFDataCreate(allocator, keyData, keyDataLength);
-
- } else if(kSecKeyEncodingApplePkcs1 == encoding) {
- /* DER-encoded according to PKCS1 with Apple Extensions. */
- /* FIXME: need to actually handle extensions */
- return NULL;
-
- } else if(kSecKeyEncodingRSAPublicParams == encoding) {
- /* SecRSAPublicKeyParams format; we must encode as PKCS1. */
- SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData;
- DERSize m_size = params->modulusLength;
- DERSize e_size = params->exponentLength;
- const DERSize seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) +
- DERLengthOfItem(ASN1_INTEGER, e_size);
- const DERSize result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size);
- DERSize r_size, remaining_size = result_size;
- DERReturn drtn;
-
- CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size);
- if (pkcs1 == NULL) {
- return NULL;
- }
- CFDataSetLength(pkcs1, result_size);
- uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1);
-
- *bytes++ = ASN1_CONSTR_SEQUENCE;
- remaining_size--;
- r_size = 4;
- drtn = DEREncodeLength(seq_size, bytes, &r_size);
- if (r_size <= remaining_size) {
- bytes += r_size;
- remaining_size -= r_size;
- }
- r_size = remaining_size;
- drtn = DEREncodeItem(ASN1_INTEGER, m_size, (const DERByte *)params->modulus, (DERByte *)bytes, &r_size);
- if (r_size <= remaining_size) {
- bytes += r_size;
- remaining_size -= r_size;
- }
- r_size = remaining_size;
- drtn = DEREncodeItem(ASN1_INTEGER, e_size, (const DERByte *)params->exponent, (DERByte *)bytes, &r_size);
-
- pubKeyData = pkcs1;
-
- } else {
- /* unsupported encoding */
- return NULL;
- }
- SecKeyRef publicKey = SecKeyCreateFromPublicData(allocator, kSecRSAAlgorithmID, pubKeyData);
- CFRelease(pubKeyData);
- return publicKey;
-}
-
-#if !TARGET_OS_EMBEDDED
-//
-// Given a CSSM public key, copy its modulus and/or exponent data.
-// Caller is responsible for releasing the returned CFDataRefs.
-//
-static
-OSStatus _SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key, CFDataRef *modulus, CFDataRef *exponent)
-{
- const CSSM_KEY *pubKey;
- const CSSM_KEYHEADER *hdr;
- CSSM_DATA pubKeyBlob;
- OSStatus result;
-
- result = SecKeyGetCSSMKey(key, &pubKey);
- if(result != errSecSuccess) {
- return result;
- }
- hdr = &pubKey->KeyHeader;
- if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
- return errSSLInternal;
- }
- if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
- return errSSLInternal;
- }
- switch(hdr->BlobType) {
- case CSSM_KEYBLOB_RAW:
- pubKeyBlob.Length = pubKey->KeyData.Length;
- pubKeyBlob.Data = pubKey->KeyData.Data;
- break;
- case CSSM_KEYBLOB_REFERENCE:
- // FIXME: currently SSL only uses raw public keys, obtained from the CL
- default:
- return errSSLInternal;
- }
- assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
- // at this point we should have a PKCS1-encoded blob
-
- DERItem keyItem = {(DERByte *)pubKeyBlob.Data, pubKeyBlob.Length};
- DERRSAPubKeyPKCS1 decodedKey;
- if(DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
- DERRSAPubKeyPKCS1ItemSpecs,
- &decodedKey, sizeof(decodedKey)) != DR_Success) {
- return errSecDecode;
- }
- if(modulus) {
- *modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data, decodedKey.modulus.length);
- if(*modulus == NULL) {
- return errSecDecode;
- }
- }
- if(exponent) {
- *exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data, decodedKey.pubExponent.length);
- if(*exponent == NULL) {
- return errSecDecode;
- }
- }
-
- return errSecSuccess;
-}
-#endif /* !TARGET_OS_EMBEDDED */
-
-CFDataRef SecKeyCopyModulus(SecKeyRef key)
-{
-#if TARGET_OS_EMBEDDED
- ccrsa_pub_ctx_t pubkey;
- pubkey.pub = key->key;
-
- size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey));
-
- CFAllocatorRef allocator = CFGetAllocator(key);
- CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size);
-
- if (modulusData == NULL)
- return NULL;
-
- CFDataSetLength(modulusData, m_size);
-
- ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData));
-#else
- CFDataRef modulusData;
- OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, &modulusData, NULL);
- if(status != errSecSuccess) {
- modulusData = NULL;
- }
-#endif
-
- return modulusData;
-}
-
-CFDataRef SecKeyCopyExponent(SecKeyRef key)
-{
-#if TARGET_OS_EMBEDDED
- ccrsa_pub_ctx_t pubkey;
- pubkey.pub = key->key;
-
- size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey));
-
- CFAllocatorRef allocator = CFGetAllocator(key);
- CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size);
-
- if (exponentData == NULL)
- return NULL;
-
- CFDataSetLength(exponentData, e_size);
-
- ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, CFDataGetMutableBytePtr(exponentData));
-#else
- CFDataRef exponentData;
- OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, NULL, &exponentData);
- if(status != errSecSuccess) {
- exponentData = NULL;
- }
-#endif
-
- return exponentData;
-}
-
-SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) {
- OSStatus status = errSecParam;
-
- CFDataRef serializedPublic = NULL;
-
- status = SecKeyCopyPublicBytes(privateKey, &serializedPublic);
- if ((status == errSecSuccess) && (serializedPublic != NULL)) {
- SecKeyRef publicKeyRef = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmId(privateKey), serializedPublic);
- CFRelease(serializedPublic);
- if (publicKeyRef != NULL) {
- return publicKeyRef;
- }
- }
-
- const void *keys[] = { kSecClass, kSecValueRef, kSecReturnAttributes };
- const void *values[] = { kSecClassKey, privateKey, kCFBooleanTrue };
- CFDictionaryRef query= CFDictionaryCreate(NULL, keys, values,
- (sizeof(values) / sizeof(*values)),
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFTypeRef foundItem = NULL;
- status = SecItemCopyMatching(query, &foundItem);
-
- if (status == errSecSuccess) {
- if (CFGetTypeID(foundItem) == CFDictionaryGetTypeID()) {
- CFMutableDictionaryRef query2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFDictionaryAddValue(query2, kSecClass, kSecClassKey);
- CFDictionaryAddValue(query2, kSecAttrKeyClass, kSecAttrKeyClassPublic);
- CFDictionaryAddValue(query2, kSecAttrApplicationLabel, CFDictionaryGetValue((CFDictionaryRef)foundItem, kSecAttrApplicationLabel));
- CFDictionaryAddValue(query2, kSecReturnRef, kCFBooleanTrue);
-
- CFTypeRef foundKey = NULL;
- status = SecItemCopyMatching(query2, &foundKey);
- if (status == errSecSuccess) {
- if (CFGetTypeID(foundKey) == SecKeyGetTypeID()) {
- CFRelease(query);
- CFRelease(query2);
- CFRelease(foundItem);
- return (SecKeyRef)foundKey;
- } else {
- status = errSecItemNotFound;
- }
- }
- CFRelease(query2);
-
- } else {
- status = errSecItemNotFound;
- }
- CFRelease(foundItem);
- }
-
- CFRelease(query);
- return NULL;
-}
-