X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..07691282a056c4efea71e1e505527601e8cc166b:/OSX/libsecurity_smime/lib/cmspubkey.c diff --git a/OSX/libsecurity_smime/lib/cmspubkey.c b/OSX/libsecurity_smime/lib/cmspubkey.c index a42f322b..c4dc0eaa 100644 --- a/OSX/libsecurity_smime/lib/cmspubkey.c +++ b/OSX/libsecurity_smime/lib/cmspubkey.c @@ -45,12 +45,16 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include /* ====== RSA ======================================================================= */ @@ -66,9 +70,7 @@ SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert, CSSM_DATA_PTR encKey) { OSStatus rv; - SecPublicKeyRef publickey; - - rv = SecCertificateCopyPublicKey(cert,&publickey); + SecPublicKeyRef publickey = SecCertificateCopyKey(cert); if (publickey == NULL) return SECFailure; @@ -86,26 +88,24 @@ SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp, unsigned int data_len; //KeyType keyType; void *mark = NULL; + CFDictionaryRef theirKeyAttrs = NULL; mark = PORT_ArenaMark(poolp); if (!mark) goto loser; - -#if 0 - /* sanity check */ - keyType = SECKEY_GetPublicKeyType(publickey); - PORT_Assert(keyType == rsaKey); - if (keyType != rsaKey) { - goto loser; - } -#endif /* allocate memory for the encrypted key */ - rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len); - if (rv) - goto loser; + theirKeyAttrs = SecKeyCopyAttributes(publickey); + if (!theirKeyAttrs) { + goto loser; + } + CFNumberRef keySizeNum = CFDictionaryGetValue(theirKeyAttrs, kSecAttrKeySizeInBits); + if (!CFNumberGetValue(keySizeNum, kCFNumberIntType, &data_len)) { + goto loser; + } // Convert length to bytes; - data_len >>= 2; + data_len /= 8; + encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len); encKey->Length = data_len; if (encKey->Data == NULL) @@ -120,6 +120,9 @@ SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp, return SECSuccess; loser: + if (theirKeyAttrs) { + CFRelease(theirKeyAttrs); + } if (mark) { PORT_ArenaRelease(poolp, mark); } @@ -648,59 +651,6 @@ typedef enum { CAT_Ptr } ContextAttrType; -static CSSM_RETURN cmsAddContextAttribute( - CSSM_CC_HANDLE CCHandle, - uint32 AttributeType, - uint32 AttributeLength, - ContextAttrType attrType, - /* specify exactly one of these */ - const void *AttributePtr, - uint32 attributeInt) -{ - CSSM_CONTEXT_ATTRIBUTE newAttr; - CSSM_RETURN crtn; - - newAttr.AttributeType = AttributeType; - newAttr.AttributeLength = AttributeLength; - if(attrType == CAT_Uint32) { - newAttr.Attribute.Uint32 = attributeInt; - } - else { - /* this is a union of a bunch of different pointers...*/ - newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; - } - crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); - if(crtn) { - CSSM_PERROR("CSSM_UpdateContextAttributes", crtn); - } - return crtn; -} - -static CSSM_RETURN cmsGenRand( - CSSM_CSP_HANDLE cspHand, - CSSM_SIZE len, - uint8 *randOut) -{ - CSSM_CC_HANDLE ccHand = 0; - CSSM_DATA randData = {len, randOut}; - - CSSM_RETURN crtn = CSSM_CSP_CreateRandomGenContext(cspHand, - CSSM_ALGID_APPLE_YARROW, - NULL, /* seed*/ - len, - &ccHand); - if(crtn) { - CSSM_PERROR("CSSM_CSP_CreateRandomGenContext", crtn); - return crtn; - } - crtn = CSSM_GenerateRandom(ccHand, &randData); - CSSM_DeleteContext(ccHand); - if(crtn) { - CSSM_PERROR("CSSM_GenerateRandom", crtn); - } - return crtn; -} - /* convert uint32 to big-endian 4 bytes */ static void int32ToBytes( uint32_t i, @@ -713,68 +663,6 @@ static void int32ToBytes( } } -/* - * NULL wrap a ref key to raw key in default format. - */ -static OSStatus cmsNullWrapKey( - CSSM_CSP_HANDLE cspHand, - const CSSM_KEY *refKey, - CSSM_KEY_PTR rawKey) -{ - CSSM_DATA descData = {0, 0}; - CSSM_RETURN crtn; - CSSM_CC_HANDLE ccHand; - CSSM_ACCESS_CREDENTIALS creds; - uint32 keyAttr; - - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - memset(rawKey, 0, sizeof(CSSM_KEY)); - - crtn = CSSM_CSP_CreateSymmetricContext(cspHand, - CSSM_ALGID_NONE, - CSSM_ALGMODE_NONE, - &creds, - NULL, // unwrappingKey - NULL, // initVector - CSSM_PADDING_NONE, - 0, // Params - &ccHand); - if(crtn) { - CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", crtn); - return crtn; - } - - keyAttr = rawKey->KeyHeader.KeyAttr; - keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE | - CSSM_KEYATTR_MODIFIABLE); - keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; - crtn = CSSM_WrapKey(ccHand, - &creds, - refKey, - &descData, - rawKey); - if(crtn != CSSM_OK) { - CSSM_PERROR("CSSM_WrapKey", crtn); - } - CSSM_DeleteContext(ccHand); - return crtn; -} - -/* - * Free memory via specified plugin's app-level allocator - */ -static void cmsFreeCssmMemory( - CSSM_HANDLE hand, - void *p) -{ - CSSM_API_MEMORY_FUNCS memFuncs; - CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs); - if(crtn) { - return; - } - memFuncs.free_func(p, memFuncs.AllocRef); -} - /* * Given an OID tag, return key size and mode. * NOTE: ciphers with variable key sizes, like RC2, RC4, and RC5 cannot @@ -784,60 +672,63 @@ static void cmsFreeCssmMemory( static OSStatus encrAlgInfo( SECOidTag oidTag, uint32 *keySizeBits, /* RETURNED */ - CSSM_ENCRYPT_MODE *mode) /* RETURNED */ + CCAlgorithm *algorithm, /* RETURNED */ + CCOptions *options) /* RETURNED */ { *keySizeBits = 64; /* default */ - *mode = CSSM_ALGMODE_CBCPadIV8; /* default */ + *options = kCCOptionPKCS7Padding; /* default */ switch(oidTag) { - case SEC_OID_RC2_CBC: - case SEC_OID_RC4: - case SEC_OID_RC5_CBC_PAD: - dprintf("encrAlgInfo: key size unknowable\n"); - return errSecDataNotAvailable; - - case SEC_OID_DES_EDE3_CBC: - *keySizeBits = 192; - break; - case SEC_OID_DES_EDE: - /* Not sure about this; SecCmsCipherContextStart() treats this - * like SEC_OID_DES_EDE3_CBC... */ - case SEC_OID_DES_ECB: - *mode = CSSM_ALGMODE_ECB; - break; - case SEC_OID_DES_CBC: - *mode = CSSM_ALGMODE_CBC; - break; - case SEC_OID_AES_128_CBC: - *keySizeBits = 128; - break; - case SEC_OID_AES_192_CBC: - *keySizeBits = 192; - break; - case SEC_OID_AES_256_CBC: - *keySizeBits = 256; - break; - case SEC_OID_AES_128_ECB: - *keySizeBits = 128; - *mode = CSSM_ALGMODE_ECB; - break; - case SEC_OID_AES_192_ECB: - *keySizeBits = 192; - *mode = CSSM_ALGMODE_ECB; - break; - case SEC_OID_AES_256_ECB: - *keySizeBits = 256; - *mode = CSSM_ALGMODE_ECB; - break; - case SEC_OID_DES_OFB: - *mode = CSSM_ALGMODE_OFB; - break; - case SEC_OID_DES_CFB: - *mode = CSSM_ALGMODE_CFB; - break; - default: - dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag); - return errSecDataNotAvailable; + case SEC_OID_RC2_CBC: + case SEC_OID_RC4: + case SEC_OID_RC5_CBC_PAD: + dprintf("encrAlgInfo: key size unknowable\n"); + return errSecDataNotAvailable; + case SEC_OID_DES_EDE: + /* Not sure about this; SecCmsCipherContextStart() treats this + * like SEC_OID_DES_EDE3_CBC... */ + *options = kCCOptionECBMode; + // fall through + case SEC_OID_DES_EDE3_CBC: + *keySizeBits = 192; + *algorithm = kCCAlgorithm3DES; + break; + case SEC_OID_DES_ECB: + *options = kCCOptionECBMode; + // fall through + case SEC_OID_DES_CBC: + *algorithm = kCCAlgorithmDES; + break; + case SEC_OID_AES_128_CBC: + *keySizeBits = 128; + *algorithm = kCCAlgorithmAES; + break; + case SEC_OID_AES_192_CBC: + *keySizeBits = 192; + *algorithm = kCCAlgorithmAES; + break; + case SEC_OID_AES_256_CBC: + *keySizeBits = 256; + *algorithm = kCCAlgorithmAES; + break; + case SEC_OID_AES_128_ECB: + *keySizeBits = 128; + *algorithm = kCCAlgorithmAES; + *options = kCCOptionECBMode; + break; + case SEC_OID_AES_192_ECB: + *keySizeBits = 192; + *algorithm = kCCAlgorithmAES; + *options = kCCOptionECBMode; + break; + case SEC_OID_AES_256_ECB: + *keySizeBits = 256; + *algorithm = kCCAlgorithmAES; + *options = kCCOptionECBMode; + break; + default: + dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag); + return errSecDataNotAvailable; } return noErr; } @@ -861,216 +752,120 @@ SecCmsUtilEncryptSymKeyECDH( * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */ { OSStatus rv = noErr; - CSSM_KEY ourPrivKeyCssm; - CSSM_KEY ourPubKeyCssm; - SecKeyRef theirPubKeyRef = NULL; - CSSM_KEY_PTR theirPubKeyCssm = NULL; - const CSSM_KEY *cekCssmRef = NULL; - uint32 ecdhKeySizeBits; - CSSM_CSP_HANDLE rawCspHand = SecCspHandleForAlgorithm(CSSM_ALGID_ECDH); - CSSM_CC_HANDLE ccHand = 0; - CSSM_RETURN crtn; - CSSM_DATA keyLabel = {8, (uint8 *)"tempKey"}; + SecKeyRef theirPubKey = NULL, ourPubKey = NULL, ourPrivKey = NULL; + CFDictionaryRef theirKeyAttrs = NULL, ourKeyParams = NULL, kekParams = NULL; + uint8_t iv[ECDH_KEK_IV_LEN_BYTES]; + CSSM_DATA ivData = { ECDH_KEK_IV_LEN_BYTES, iv }; SECAlgorithmID kekAlgId; - uint8 iv[ECDH_KEK_IV_LEN_BYTES]; - CSSM_DATA ivData = {ECDH_KEK_IV_LEN_BYTES, iv}; SECOidData *kekOid; ECC_CMS_SharedInfo sharedInfo; CSSM_DATA sharedInfoEnc = {0, NULL}; uint8 nullData[2] = {SEC_ASN1_NULL, 0}; uint8 keyLenAsBytes[4]; - CSSM_KEY kekDerive; - CSSM_DATA certData; - CSSM_CL_HANDLE clHand; - CSSM_ACCESS_CREDENTIALS creds; - CSSM_DATA paramData = {0, NULL}; - CSSM_KEY cekCssm; - CSSM_CSP_HANDLE refCspHand; - CSSM_SIZE bytesEncrypted; - CSSM_DATA remData = {0, NULL}; - CSSM_DATA ctext = {0, NULL}; - CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKey; - - if(rawCspHand == 0) { - return internalComponentErr; - } - - memset(&ourPrivKeyCssm, 0, sizeof(CSSM_KEY)); - memset(&ourPubKeyCssm, 0, sizeof(CSSM_KEY)); - memset(&cekCssm, 0, sizeof(CSSM_KEY)); - memset(&kekDerive, 0, sizeof(kekDerive)); - + CFDataRef sharedInfoData = NULL, kekData = NULL, ourPubData = NULL; + CFNumberRef kekLen = NULL; + CFErrorRef error = NULL; + CCCryptorRef ciphercc = NULL; + encKey->Data = NULL; encKey->Length = 0; - - /* - * Create our ECDH key pair matching the recipient's key. - * Get the public key in "read-only" OCTET_STRING format, which - * is the ECPoint we put in - * KeyAgreeRecipientInfo.originator.OriginatorPublicKey. - */ - rv = SecCertificateGetData(cert, &certData); - if(rv) { - CSSM_PERROR("SecCertificateGetData", rv); - return rv; - } - rv = SecCertificateGetCLHandle(cert, &clHand); - if(rv) { - CSSM_PERROR("SecCertificateGetCLHandle", rv); - return rv; - } - rv = CSSM_CL_CertGetKeyInfo(clHand, &certData, &theirPubKeyCssm); - if(rv) { - CSSM_PERROR("CSSM_CL_CertGetKeyInfo", rv); - return rv; - } - - /* - * Verify the EC curve of the recipient's public key. It's in the - * public key's AlgId.parameters as an OID. The key we were - * given is in CSSM_X509_SUBJECT_PUBLIC_KEY_INFO form. - */ - memset(&subjPubKey, 0, sizeof(subjPubKey)); - if(SEC_ASN1DecodeItem(poolp, &subjPubKey, kSecAsn1SubjectPublicKeyInfoTemplate, - &theirPubKeyCssm->KeyData)) { - dprintf("SecCmsUtilEncryptSymKeyECDH: error decoding SubjPubKey\n"); - /* oh well, keep going */ - } - else { - if(subjPubKey.algorithm.parameters.Data != NULL) { - CSSM_DATA curveOid; - if(SEC_ASN1DecodeItem(poolp, &curveOid, kSecAsn1ObjectIDTemplate, - &subjPubKey.algorithm.parameters)) { - dprintf("SecCmsUtilEncryptSymKeyECDH: error decoding curveOid\n"); - /* oh well, keep going */ - } - else { - /* We have the curve OID. Any other errors are fatal. */ - SECOidTag oidTag = SECOID_FindOIDTag(&curveOid); - switch(oidTag) { - case SEC_OID_SECP_256_R1: - case SEC_OID_SECP_384_R1: - case SEC_OID_SECP_521_R1: - break; - default: - dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported curveOid\n"); - rv = CSSMERR_CSP_INVALID_KEY; - goto loser; - } - } - } + + /* Copy the recipient's static public ECDH key */ + theirPubKey = SecCertificateCopyKey(cert); + if (rv || !theirPubKey) { + dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get public key from cert, %d\n", (int)rv); + goto out; } - - ecdhKeySizeBits = theirPubKeyCssm->KeyHeader.LogicalKeySizeInBits; - crtn = CSSM_CSP_CreateKeyGenContext(rawCspHand, - CSSM_ALGID_ECDSA, - ecdhKeySizeBits, - NULL, // Seed - NULL, // Salt - NULL, // StartDate - NULL, // EndDate - NULL, // Params - &ccHand); - if(crtn) { - CSSM_PERROR("CSSM_CSP_CreateKeyGenContext", crtn); - rv = crtn; - goto loser; + + theirKeyAttrs = SecKeyCopyAttributes(theirPubKey); + if (!theirKeyAttrs) { + dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get key attributes\n"); + goto out; } - crtn = cmsAddContextAttribute(ccHand, - CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT, - sizeof(uint32), - CAT_Uint32, - NULL, - CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING); - if(crtn) { - CSSM_PERROR("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn); - rv = crtn; - goto loser; + + CFStringRef keyType = NULL; + CFNumberRef keySizeNum = NULL; + keyType = CFDictionaryGetValue(theirKeyAttrs, kSecAttrKeyType); + keySizeNum = CFDictionaryGetValue(theirKeyAttrs, kSecAttrKeySizeInBits); + + if (!CFEqual(kSecAttrKeyTypeECSECPrimeRandom, keyType)) { + dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported key type\n"); + rv = CSSMERR_CSP_INVALID_KEY; + goto out; } - crtn = CSSM_GenerateKeyPair(ccHand, - CSSM_KEYUSE_DERIVE, - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, - &keyLabel, - &ourPubKeyCssm, - CSSM_KEYUSE_DERIVE, - CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, - &keyLabel, - NULL, // CredAndAclEntry - &ourPrivKeyCssm); - CSSM_DeleteContext(ccHand); - ccHand = 0; - if(crtn) { - CSSM_PERROR("CSSM_GenerateKeyPair", crtn); - rv = crtn; - goto loser; + /* Generate ephemeral ECDH key */ + const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrNoLegacy}; + const void *values[] = { keyType, keySizeNum, kCFBooleanTrue }; + ourKeyParams = CFDictionaryCreate(NULL, keys, values, 3, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + rv = SecKeyGeneratePair(ourKeyParams, &ourPubKey, &ourPrivKey); + if (rv || !ourPubKey || !ourPrivKey) { + dprintf("SecKeyGeneratePair: unable to generate ECDH key pair, %d\n", (int)rv); + goto out; } - pubKey->Length = ourPubKeyCssm.KeyData.Length; - pubKey->Data = (uint8 *)PORT_ArenaAlloc(poolp, pubKey->Length); - memmove(pubKey->Data, ourPubKeyCssm.KeyData.Data, pubKey->Length); - dumpBuf("sender's public key", pubKey); - - /* - * Cook up random UKM - */ - ukm->Data = (uint8 *)PORT_ArenaAlloc(poolp, UKM_LENGTH); + + /* Generate UKM */ + ukm->Data = PORT_Alloc(UKM_LENGTH); ukm->Length = UKM_LENGTH; - crtn = cmsGenRand(rawCspHand, UKM_LENGTH, ukm->Data); - if(crtn) { - goto loser; + rv = CCRandomCopyBytes(kCCRandomDefault, ukm->Data, UKM_LENGTH); + if (rv || !ukm->Data) { + dprintf("CCRandomGenerateBytes failed, %d", (int)rv); + goto out; } - dumpBuf("sender UKM", ukm); - + /* * OK, we have to set up a weird SECAlgorithmID. * algorithm = dhSinglePass-stdDH-sha1kdf-scheme - * params = an encoded SECAlgorithmID representing the KEK algorithm, with + * params = an encoded SECAlgorithmID representing the KEK algorithm, with * algorithm = whatever we pick * parameters = IV as octet string (though I haven't seen that specified * anywhere; it's how the CEK IV is encoded) - * - * First, the 8-byte random IV, encoded as octet string */ - crtn = cmsGenRand(rawCspHand, ECDH_KEK_IV_LEN_BYTES, iv); - if(crtn) { - goto loser; + + /* Generate 8-byte IV */ + rv = CCRandomCopyBytes(kCCRandomDefault, iv, ECDH_KEK_IV_LEN_BYTES); + if (rv) { + dprintf("CCRandomGenerateBytes failed, %d", (int)rv); + goto out; } dumpBuf("sender IV", &ivData); - + memset(&kekAlgId, 0, sizeof(kekAlgId)); if (!SEC_ASN1EncodeItem(poolp, &kekAlgId.parameters, - &ivData, kSecAsn1OctetStringTemplate)) { - rv = internalComponentErr; - goto loser; + &ivData, kSecAsn1OctetStringTemplate)) { + rv = internalComponentErr; + goto out; } /* Drop in the KEK OID and encode the whole thing */ kekOid = SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG); if(kekOid == NULL) { - dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n"); - rv = internalComponentErr; - goto loser; + dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n"); + rv = internalComponentErr; + goto out; } kekAlgId.algorithm = kekOid->oid; memset(keyEncAlg, 0, sizeof(*keyEncAlg)); if (!SEC_ASN1EncodeItem(poolp, &keyEncAlg->parameters, - &kekAlgId, SECOID_AlgorithmIDTemplate)) { - rv = internalComponentErr; - goto loser; + &kekAlgId, SECOID_AlgorithmIDTemplate)) { + rv = internalComponentErr; + goto out; } kekOid = SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF); if(kekOid == NULL) { - dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n"); - rv = internalComponentErr; - goto loser; + dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n"); + rv = internalComponentErr; + goto out; } keyEncAlg->algorithm = kekOid->oid; - - /* - * Now in order to derive the KEK proper, we have to create a + + /* + * Now in order to derive the KEK proper, we have to create a * ECC-CMS-SharedInfo, which does not appear in the message, and DER - * encode that struct, the result of which is used as the - * SharedInfo value in the KEK key derive. + * encode that struct, the result of which is used as the + * SharedInfo value in the KEK key derive. */ memset(&sharedInfo, 0, sizeof(sharedInfo)); kekOid = SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG); @@ -1082,146 +877,102 @@ SecCmsUtilEncryptSymKeyECDH( sharedInfo.suppPubInfo.Length = 4; sharedInfo.suppPubInfo.Data = keyLenAsBytes; if (!SEC_ASN1EncodeItem(poolp, &sharedInfoEnc, - &sharedInfo, ECC_CMS_SharedInfoTemplate)) { - rv = internalComponentErr; - goto loser; + &sharedInfo, ECC_CMS_SharedInfoTemplate)) { + rv = internalComponentErr; + goto out; } dumpBuf("sender encoded SharedInfo", &sharedInfoEnc); - - /* - * Since we're using the raw CSP here, we can provide the "other" public - * key as an actual CSSM_KEY. When unwrapping, we won't be able to do that - * since we'll be using our private key obtained from a SecIdentityRef. - */ - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - crtn = CSSM_CSP_CreateDeriveKeyContext(rawCspHand, - CSSM_ALGID_ECDH_X963_KDF, - ECDH_KEK_KEY_CSSM_ALGID, // algorithm of the KEK - ECDH_KEK_KEY_LEN_BYTES * 8, - &creds, - &ourPrivKeyCssm, // BaseKey - 0, // IterationCount - &sharedInfoEnc, // Salt - 0, // Seed - &ccHand); - if(crtn) { - CSSM_PERROR("CSSM_CSP_CreateDeriveKeyContext", crtn); - rv = crtn; - goto loser; - } - - /* add recipient's pub key as a context attr */ - crtn = cmsAddContextAttribute(ccHand, - CSSM_ATTRIBUTE_PUBLIC_KEY, - sizeof(CSSM_KEY), - CAT_Ptr, - (void *)theirPubKeyCssm, - 0); - if(crtn) { - rv = crtn; - goto loser; - } - - /* Derive the KEK */ - crtn = CSSM_DeriveKey(ccHand, - ¶mData, - CSSM_KEYUSE_ANY, - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, - &keyLabel, - NULL, // cread/acl - &kekDerive); - if(crtn) { - CSSM_PERROR("CSSM_DeriveKey", crtn); - rv = crtn; - goto loser; - } - CSSM_DeleteContext(ccHand); - ccHand = 0; - - /* - * Obtain the raw CEK bits. - */ - rv = SecKeyGetCSSMKey(key, &cekCssmRef); - if(rv) { - CSSM_PERROR("SecKeyGetCSSMKey", rv); - goto loser; - } - rv = SecKeyGetCSPHandle(key, &refCspHand); - if(rv) { - CSSM_PERROR("SecKeyGetCSPHandle", rv); - goto loser; - } - rv = cmsNullWrapKey(refCspHand, cekCssmRef, &cekCssm); - if(rv) { - goto loser; + + /* Derive KEK */ + sharedInfoData = CFDataCreate(NULL, sharedInfoEnc.Data, sharedInfoEnc.Length); + int32_t ecdh_key_key_len = ECDH_KEK_KEY_LEN_BYTES; + kekLen = CFNumberCreate(NULL, kCFNumberSInt32Type, &ecdh_key_key_len); + const void *kekKeys[] = { kSecKeyKeyExchangeParameterRequestedSize, kSecKeyKeyExchangeParameterSharedInfo }; + const void *kekValues[] = { kekLen, sharedInfoData }; + kekParams = CFDictionaryCreate(NULL, kekKeys, kekValues, 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + kekData = SecKeyCopyKeyExchangeResult(ourPrivKey, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1, + theirPubKey, kekParams, &error); + if (error) { + dprintf("SecKeyCopyKeyExchangeResult: failed\n"); + goto out; } - - /* - * Finally, encrypt the raw CEK bits with the KEK we just derived + + /* + * Encrypt the raw CEK bits with the KEK we just derived */ - crtn = CSSM_CSP_CreateSymmetricContext(rawCspHand, - ECDH_KEK_ENCR_CSSM_ALGID, - CSSM_ALGMODE_CBCPadIV8, - NULL, // access cred - &kekDerive, - &ivData, // InitVector - CSSM_PADDING_PKCS7, - NULL, // Params - &ccHand); - if(rv) { - CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", rv); - goto loser; - } - rv = CSSM_EncryptData(ccHand, - &cekCssm.KeyData, - 1, - &ctext, - 1, - &bytesEncrypted, - &remData); - if(rv) { - CSSM_PERROR("CSSM_EncryptData", rv); - goto loser; - } - encKey->Data = PORT_ArenaAlloc(poolp, bytesEncrypted); - encKey->Length = bytesEncrypted; - memmove(encKey->Data, ctext.Data, ctext.Length); - if(bytesEncrypted != ctext.Length) { - memmove(encKey->Data + ctext.Length, remData.Data, remData.Length); - } - dumpBuf("sender encKey", encKey); - -loser: - if(ccHand) { - CSSM_DeleteContext(ccHand); - } - CFRELEASE(theirPubKeyRef); - if(ourPubKeyCssm.KeyData.Data) { - CSSM_FreeKey(rawCspHand, NULL, &ourPubKeyCssm, CSSM_FALSE); - } - if(ourPrivKeyCssm.KeyData.Data) { - CSSM_FreeKey(rawCspHand, NULL, &ourPrivKeyCssm, CSSM_FALSE); - } - if(ctext.Data) { - cmsFreeCssmMemory(rawCspHand, ctext.Data); - } - if(remData.Data) { - cmsFreeCssmMemory(rawCspHand, remData.Data); + rv = CCCryptorCreate(kCCEncrypt, kCCAlgorithm3DES, kCCOptionPKCS7Padding, + CFDataGetBytePtr(kekData), CFDataGetLength(kekData), iv, &ciphercc); + if (rv) { + dprintf("CCCryptorCreate failed: %d\n", (int)rv); + goto out; } - if(cekCssm.KeyData.Data) { - CSSM_FreeKey(refCspHand, NULL, &cekCssm, CSSM_FALSE); + CSSM_KEY cek; + rv = cmsNullWrapKey(key, &cek); + if (rv) { + dprintf("SecKeyGetCSSMKey failed: %d\n", (int)rv); + goto out; } - if(kekDerive.KeyData.Data) { - CSSM_FreeKey(rawCspHand, NULL, &kekDerive, CSSM_FALSE); + size_t expectedEncKeyLength = CCCryptorGetOutputLength(ciphercc, cek.KeyData.Length, true); + encKey->Data = PORT_ArenaAlloc(poolp, expectedEncKeyLength); + size_t bytes_output = 0; + rv = CCCryptorUpdate(ciphercc, cek.KeyData.Data, cek.KeyData.Length, encKey->Data, expectedEncKeyLength, &bytes_output); + if (rv) { + dprintf("CCCryptorUpdate failed: %d\n", (int)rv); + goto out; } - if(theirPubKeyCssm) { - /* Allocated by CL */ - cmsFreeCssmMemory(clHand, theirPubKeyCssm->KeyData.Data); - cmsFreeCssmMemory(clHand, theirPubKeyCssm); + size_t final_bytes_output = 0; + rv = CCCryptorFinal(ciphercc, encKey->Data+bytes_output, expectedEncKeyLength - bytes_output, &final_bytes_output); + if (rv) { + dprintf("CCCryptorFinal failed: %d\n", (int)rv); + goto out; + } + encKey->Length = bytes_output + final_bytes_output; + + /* Provide our ephemeral public key to the caller */ + ourPubData = SecKeyCopyExternalRepresentation(ourPubKey, &error); + if (error) { + dprintf("SecKeyCopyExternalRepresentation failed\n"); + goto out; + } + pubKey->Length = CFDataGetLength(ourPubData); + pubKey->Data = malloc(pubKey->Length); + if (pubKey->Data) { + memcpy(pubKey->Data, CFDataGetBytePtr(ourPubData), pubKey->Length); + } else { + rv = errSecAllocate; + } + /* pubKey is bit string, convert here */ + pubKey->Length <<= 3; + +out: + if (theirPubKey) { CFRelease(theirPubKey); } + if (theirKeyAttrs) { CFRelease(theirKeyAttrs); } + if (ourKeyParams) { CFRelease(ourKeyParams); } + if (ourPubKey) { CFRelease(ourPubKey); } + if (ourPrivKey) { CFRelease(ourPrivKey); } + if (sharedInfoData) { CFRelease(sharedInfoData); } + if (kekLen) { CFRelease(kekLen); } + if (kekParams) { CFRelease(kekParams); } + if (kekData) { CFRelease(kekData); } + if (error) { CFRelease(error); } + if (ciphercc) { CCCryptorRelease(ciphercc); } + if (ourPubData) { CFRelease(ourPubData); } + if (rv && encKey->Data) { + PORT_Free(encKey->Data); + encKey->Data = NULL; + encKey->Length = 0; + } + if (rv && ukm->Data) { + PORT_Free(ukm->Data); + ukm->Data = NULL; + ukm->Length = 0; } return rv; } + #pragma mark ---- ECDH CEK key unwrap ---- SecSymmetricKeyRef @@ -1234,11 +985,9 @@ SecCmsUtilDecryptSymKeyECDH( SECOidTag bulkalgtag, /* algorithm of returned key */ CSSM_DATA_PTR pubKey) /* sender's pub key as ECPoint from * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */ - { SecSymmetricKeyRef outKey = NULL; OSStatus rv = noErr; - const CSSM_KEY *ourPrivKeyCssm; PLArenaPool *pool = NULL; SECAlgorithmID keyAlgParam; SECOidData *kekOid = NULL; @@ -1247,70 +996,58 @@ SecCmsUtilDecryptSymKeyECDH( CSSM_DATA sharedInfoEnc = {0, NULL}; uint8 nullData[2] = {SEC_ASN1_NULL, 0}; uint8 keyLenAsBytes[4]; - CSSM_ENCRYPT_MODE kekMode; uint32 kekSizeBits; - CSSM_KEY kekDerive; - CSSM_RETURN crtn; - CSSM_ACCESS_CREDENTIALS creds; - CSSM_CSP_HANDLE refCspHand; - CSSM_CC_HANDLE ccHand = 0; - CSSM_DATA keyLabel = {8, (uint8 *)"tempKey"}; - const CSSM_ACCESS_CREDENTIALS *accessCred; - CSSM_KEY wrappedKey; - CSSM_KEY unwrappedKey; - CSSM_ALGORITHMS bulkAlg; - CSSM_DATA descriptiveData = {0, NULL}; - - dumpBuf("receiver encKey", encKey); - - memset(&kekDerive, 0, sizeof(kekDerive)); + SecKeyRef theirPubKey = NULL; + CFStringRef keyType = NULL; + CFDictionaryRef theirKeyAttrs = NULL, kekParams = NULL; + CFMutableDictionaryRef cekParams = NULL; + CFDataRef sharedInfoData = NULL, theirPubData= NULL, kekData = NULL, cekData = NULL; + CFNumberRef kekLen = NULL, theirKeyLen = NULL; + CFErrorRef error = NULL; + CCAlgorithm alg; + CCOptions options = 0; + CCCryptorRef ciphercc = NULL; + size_t theirKeySizeInBits = 0; - /* our private key in CSSM form */ - rv = SecKeyGetCSSMKey(privkey, &ourPrivKeyCssm); - if(rv) { - CSSM_PERROR("SecKeyGetCSSMKey", rv); - goto loser; - } - - /* + /* * Decode keyEncAlg.params to get KEK algorithm and IV - */ + */ pool = PORT_NewArena(1024); if(pool == NULL) { - goto loser; + goto out; } memset(&keyAlgParam, 0, sizeof(keyAlgParam)); - if(SEC_ASN1DecodeItem(pool, &keyAlgParam, SECOID_AlgorithmIDTemplate, - &keyEncAlg->parameters)) { - dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n"); - goto loser; + if(SEC_ASN1DecodeItem(pool, &keyAlgParam, SECOID_AlgorithmIDTemplate, + &keyEncAlg->parameters)) { + dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n"); + goto out; } kekOid = SECOID_FindOID(&keyAlgParam.algorithm); if(kekOid == NULL) { - dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n"); - goto loser; + dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n"); + goto out; } - rv = encrAlgInfo(kekOid->offset, &kekSizeBits, &kekMode); + rv = encrAlgInfo(kekOid->offset, &kekSizeBits, &alg, &options); if(rv) { - goto loser; + goto out; } /* IV is OCTET STRING in the alg params */ - if(SEC_ASN1DecodeItem(pool, &iv, kSecAsn1OctetStringTemplate, - &keyAlgParam.parameters)) { - /* - * Not sure here - is it legal to have no IV? I haven't seen this - * addressed in any spec. Maybe we should condition the behavior - * here on the KEK algorithm. - */ - dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n"); - goto loser; + if(SEC_ASN1DecodeItem(pool, &iv, kSecAsn1OctetStringTemplate, + &keyAlgParam.parameters)) { + /* + * Not sure here - is it legal to have no IV? I haven't seen this + * addressed in any spec. Maybe we should condition the behavior + * here on the KEK algorithm. + */ + dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n"); + goto out; } - - /* - * Now in order to derive the KEK proper, we have to create a + + /* + * Now in order to derive the KEK proper, we have to create a * ECC-CMS-SharedInfo, which does not appear in the message, and DER - * encode that struct, the result of which is used as the - * SharedInfo value in the KEK key derive. + * encode that struct, the result of which is used as the + * SharedInfo value in the KEK key derive. */ memset(&sharedInfo, 0, sizeof(sharedInfo)); sharedInfo.algId.algorithm = kekOid->oid; @@ -1321,129 +1058,107 @@ SecCmsUtilDecryptSymKeyECDH( sharedInfo.suppPubInfo.Length = 4; sharedInfo.suppPubInfo.Data = keyLenAsBytes; if (!SEC_ASN1EncodeItem(pool, &sharedInfoEnc, - &sharedInfo, ECC_CMS_SharedInfoTemplate)) { - rv = internalComponentErr; - goto loser; + &sharedInfo, ECC_CMS_SharedInfoTemplate)) { + rv = internalComponentErr; + goto out; } dumpBuf("receiver encoded SharedInfo", &sharedInfoEnc); dumpBuf("receiver IV", &iv); dumpBuf("receiver UKM", ukm); dumpBuf("sender's public key", pubKey); - /* - * Using the Sec-layer CSPDL, "other's" public key specified as ECPOint param. Which - * is fortunate because that's what we have... - */ - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - rv = SecKeyGetCSPHandle(privkey, &refCspHand); - if(rv) { - CSSM_PERROR("SecKeyGetCSPHandle", rv); - goto loser; + /* pubKey is bit string, convert here */ + theirKeySizeInBits = pubKey->Length; + pubKey->Length = (theirKeySizeInBits + 7) >> 3; + theirPubData = CFDataCreate(NULL, pubKey->Data, pubKey->Length); + theirKeyLen = CFNumberCreate(NULL, kCFNumberSInt32Type, &theirKeySizeInBits); + const void *keys[] = { kSecAttrKeyType, kSecAttrKeyClass, kSecAttrKeySizeInBits }; + const void *values[] = { kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClassPublic, theirKeyLen}; + theirKeyAttrs = CFDictionaryCreate(NULL, keys, values, 3, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + theirPubKey = SecKeyCreateWithData(theirPubData, theirKeyAttrs, &error); + if (error) { + dprintf("SecKeyCreateWithData: failed\n"); + goto out; + } + + /* Derive KEK */ + sharedInfoData = CFDataCreate(NULL, sharedInfoEnc.Data, sharedInfoEnc.Length); + int32_t ecdh_key_key_len = (kekSizeBits + 7) >> 3; + kekLen = CFNumberCreate(NULL, kCFNumberSInt32Type, &ecdh_key_key_len); + const void *kekKeys[] = { kSecKeyKeyExchangeParameterRequestedSize, kSecKeyKeyExchangeParameterSharedInfo }; + const void *kekValues[] = { kekLen, sharedInfoData }; + kekParams = CFDictionaryCreate(NULL, kekKeys, kekValues, 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + kekData = SecKeyCopyKeyExchangeResult(privkey, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1, + theirPubKey, kekParams, &error); + if (error) { + dprintf("SecKeyCopyKeyExchangeResult: failed\n"); + goto out; } - rv = SecKeyGetCredentials(privkey, - CSSM_ACL_AUTHORIZATION_DERIVE, - kSecCredentialTypeDefault, - &accessCred); + + /* + * Decrypt the raw CEK bits with the KEK we just derived + */ + CSSM_DATA cek = { 0, NULL }; + rv = CCCryptorCreate(kCCDecrypt, alg, options, + CFDataGetBytePtr(kekData), CFDataGetLength(kekData), iv.Data, &ciphercc); if (rv) { - CSSM_PERROR("SecKeyGetCredentials", rv); - goto loser; - } - crtn = CSSM_CSP_CreateDeriveKeyContext(refCspHand, - CSSM_ALGID_ECDH_X963_KDF, - kekOid->cssmAlgorithm, // algorithm of the KEK - kekSizeBits, - &creds, - ourPrivKeyCssm, // BaseKey - 0, // IterationCount - &sharedInfoEnc, // Salt - 0, // Seed - &ccHand); - if(crtn) { - CSSM_PERROR("CSSM_CSP_CreateDeriveKeyContext", crtn); - goto loser; + dprintf("CCCryptorCreate failed: %d\n", (int)rv); + goto out; } - crtn = CSSM_DeriveKey(ccHand, - pubKey, // param - CSSM_KEYUSE_ANY, - CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, - &keyLabel, - NULL, // cred/acl - &kekDerive); - CSSM_DeleteContext(ccHand); - ccHand = 0; - if(crtn) { - CSSM_PERROR("CSSM_DeriveKey", crtn); - goto loser; + size_t expectedKeyLength = CCCryptorGetOutputLength(ciphercc, encKey->Length, true); + cek.Data = PORT_ArenaAlloc(pool, expectedKeyLength); + size_t bytes_output = 0; + rv = CCCryptorUpdate(ciphercc, encKey->Data, encKey->Length, cek.Data, expectedKeyLength, &bytes_output); + if (rv) { + dprintf("CCCryptorUpdate failed: %d\n", (int)rv); + goto out; } - - /* - * Decrypt the encrypted key bits with the KEK key. - */ - crtn = CSSM_CSP_CreateSymmetricContext(refCspHand, - kekOid->cssmAlgorithm, - kekMode, - NULL, // access cred - &kekDerive, - &iv, // InitVector - /* FIXME is this variable too? */ - CSSM_PADDING_PKCS7, - NULL, // Params - &ccHand); - if(rv) { - CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", rv); - goto loser; + size_t final_bytes_output = 0; + rv = CCCryptorFinal(ciphercc, cek.Data+bytes_output, expectedKeyLength - bytes_output, &final_bytes_output); + if (rv) { + dprintf("CCCryptorFinal failed: %d\n", (int)rv); + goto out; } - - memset(&wrappedKey, 0, sizeof(CSSM_KEY)); - memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); + cek.Length = bytes_output + final_bytes_output; - bulkAlg = SECOID_FindyCssmAlgorithmByTag(bulkalgtag); - if(bulkAlg == CSSM_ALGID_NONE) { - dprintf("SecCmsUtilDecryptSymKeyECDH: unknown bulk alg\n"); - goto loser; + /* create the SecSymmetricKeyRef */ + cekData = CFDataCreate(NULL, cek.Data, cek.Length); + keyType = SECOID_CopyKeyTypeByTag(bulkalgtag); + if (!keyType) { + goto out; } - - wrappedKey.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; - wrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_WRAPPED; - wrappedKey.KeyHeader.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7; - wrappedKey.KeyHeader.AlgorithmId = bulkAlg; - wrappedKey.KeyHeader.KeyClass = CSSM_KEYCLASS_SESSION_KEY; - wrappedKey.KeyHeader.WrapAlgorithmId = kekOid->cssmAlgorithm; - wrappedKey.KeyHeader.WrapMode = CSSM_ALGMODE_NONE; - wrappedKey.KeyData = *encKey; - - crtn = CSSM_UnwrapKey(ccHand, - NULL, /* publicKey */ - &wrappedKey, - CSSM_KEYUSE_DECRYPT, - CSSM_KEYATTR_EXTRACTABLE, - &keyLabel, - NULL, /* rcc */ - &unwrappedKey, - &descriptiveData); - CSSM_DeleteContext(ccHand); - ccHand = 0; - if(crtn) { - CSSM_PERROR("CSSM_UnwrapKey", crtn); - goto loser; - } - rv = SecKeyCreateWithCSSMKey(&unwrappedKey, &outKey); - if (rv) { - CSSM_PERROR("SecKeyCreateWithCSSMKey", rv); + cekParams = CFDictionaryCreateMutable(NULL, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!cekParams) { + goto out; } - -loser: + CFDictionaryAddValue(cekParams, kSecAttrKeyType, keyType); + outKey = SecKeyCreateFromData(cekParams, cekData, NULL); + +out: if(pool != NULL) { - PORT_FreeArena(pool, PR_FALSE); - } - if(kekDerive.KeyData.Data) { - CSSM_FreeKey(refCspHand, NULL, &kekDerive, CSSM_FALSE); - } + PORT_FreeArena(pool, PR_FALSE); + } + if (theirPubData) { CFRelease(theirPubData); } + if (theirKeyLen) { CFRelease(theirKeyLen); } + if (theirPubKey) { CFRelease(theirPubKey); } + if (theirKeyAttrs) { CFRelease(theirKeyAttrs); } + if (sharedInfoData) { CFRelease(sharedInfoData); } + if (kekLen) { CFRelease(kekLen); } + if (kekParams) { CFRelease(kekParams); } + if (kekData) { CFRelease(kekData); } + if (error) { CFRelease(error); } + if (ciphercc) { CCCryptorRelease(ciphercc); } + if (cekData) { CFRelease(cekData); } + if (keyType) { CFRelease(keyType); } + if (cekParams) { CFRelease(cekParams); } if(outKey == NULL) { - PORT_SetError(SEC_ERROR_NO_KEY); + PORT_SetError(SEC_ERROR_NO_KEY); } return outKey; } - - -