#include "cmslocal.h"
-#include "secitem.h"
+#include "SecAsn1Item.h"
#include "secoid.h"
#include "cryptohi.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
-#include <Security/SecCertificatePriv.h>
+#include <security_asn1/secport.h>
+
+#include <Security/SecCertificateInternal.h>
#include <Security/SecKeyPriv.h>
-#include <Security/Security.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <Security/SecCmsBase.h>
-#include <Security/secasn1t.h>
-#include <security_asn1/plarenas.h>
-#include <Security/keyTemplates.h>
/* ====== RSA ======================================================================= */
OSStatus
SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert,
SecSymmetricKeyRef bulkkey,
- CSSM_DATA_PTR encKey)
+ SecAsn1Item * encKey)
{
OSStatus rv;
SecPublicKeyRef publickey;
-
+#if USE_CDSA_CRYPTO
rv = SecCertificateCopyPublicKey(cert,&publickey);
+#else
+ publickey = SecCertificateCopyPublicKey(cert);
+#endif
if (publickey == NULL)
return SECFailure;
OSStatus
SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp,
SecPublicKeyRef publickey,
- SecSymmetricKeyRef bulkkey, CSSM_DATA_PTR encKey)
+ SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey)
{
OSStatus rv;
- unsigned int data_len;
+ size_t data_len;
//KeyType keyType;
void *mark = NULL;
}
#endif
/* allocate memory for the encrypted key */
+#if USE_CDSA_CRYPTO
rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len);
if (rv)
goto loser;
-
// Convert length to bytes;
data_len >>= 2;
+#else
+ data_len = SecKeyGetSize(publickey, kSecKeyEncryptedDataSize);
+#endif
+
encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
encKey->Length = data_len;
if (encKey->Data == NULL)
* a hardware token...
*/
SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECOidTag bulkalgtag)
+SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECOidTag bulkalgtag)
{
/* that's easy */
return WRAP_PubUnwrapSymKey(privkey, encKey, bulkalgtag);
OSStatus
SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey,
- SECOidTag symalgtag, CSSM_DATA_PTR encKey, CSSM_DATA_PTR *pparams, void *pwfn_arg)
+ SECOidTag symalgtag, SecAsn1Item * encKey, SecAsn1Item * *pparams, void *pwfn_arg)
{
SECOidTag certalgtag; /* the certificate's encryption algorithm */
SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
OSStatus rv = SECFailure;
- CSSM_DATA_PTR params = NULL;
+ SecAsn1Item * params = NULL;
OSStatus err;
SecSymmetricKeyRef tek;
SecCertificateRef ourCert;
SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
SecCmsSMIMEKEAParameters keaParams;
PLArenaPool *arena = NULL;
- extern const SecAsn1Template *nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate);
const SECAlgorithmID *algid;
/* Clear keaParams, since cleanup code checks the lengths */
(void) memset(&keaParams, 0, sizeof(keaParams));
+#if USE_CDSA_CRYPTO
SecCertificateGetAlgorithmID(cert,&algid);
+#endif
+
certalgtag = SECOID_GetAlgorithmTag(algid);
PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD ||
certalgtag == SEC_OID_MISSI_KEA_DSS ||
}
SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
+SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
{
/* fortezza: do a key exchange */
OSStatus err;
OSStatus
SecCmsUtilEncryptSymKeyESDH(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef key,
- CSSM_DATA_PTR encKey, CSSM_DATA_PTR ukm, SECAlgorithmID *keyEncAlg,
- CSSM_DATA_PTR pubKey)
+ SecAsn1Item * encKey, SecAsn1Item * *ukm, SECAlgorithmID *keyEncAlg,
+ SecAsn1Item * pubKey)
{
#if 0 /* not yet done */
SECOidTag certalgtag; /* the certificate's encryption algorithm */
SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
OSStatus rv;
- CSSM_DATA_PTR params = NULL;
+ SecAsn1Item * params = NULL;
int data_len;
OSStatus err;
SecSymmetricKeyRef tek;
}
SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
+SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey, SecAsn1Item * encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
{
#if 0 /* not yet done */
OSStatus err;
return NULL;
}
-#endif /* Fortezza, DIffie-Hellman */
-
-#define CFRELEASE(cf) if(cf != NULL) { CFRelease(cf); }
-
-/* ====== ECDH (Ephemeral-Static Diffie-Hellman) ==================================== */
-
-#pragma mark ---- ECDH support functions ----
-
-#ifdef NDEBUG
-#define CSSM_PERROR(f, r)
-#define dprintf(args...)
-#else
-#define CSSM_PERROR(f, r) cssmPerror(f, r)
-#define dprintf(args...) printf(args)
#endif
-
-/* Length of KeyAgreeRecipientInfo.ukm we create */
-#define UKM_LENGTH 8
-
-/* KEK algorithm info we generate */
-#define ECDH_KEK_ALG_TAG SEC_OID_DES_EDE3_CBC
-#define ECDH_KEK_KEY_CSSM_ALGID CSSM_ALGID_3DES_3KEY
-#define ECDH_KEK_ENCR_CSSM_ALGID CSSM_ALGID_3DES_3KEY_EDE
-#define ECDH_KEK_KEY_LEN_BYTES 24
-#define ECDH_KEK_IV_LEN_BYTES 8
-
-#define CMS_DUMP_BUFS 0
-#if CMS_DUMP_BUFS
-
-static void dumpBuf(
- const char *label,
- const CSSM_DATA *cd)
-{
- unsigned dex;
-
- printf("%s:\n ", label);
- for(dex=0; dex<cd->Length; dex++) {
- printf("%02X ", cd->Data[dex]);
- if(((dex % 16) == 15) && (dex != (cd->Length - 1))) {
- printf("\n ");
- }
- }
- putchar('\n');
-}
-
-#else
-#define dumpBuf(l, d)
-#endif /* CMS_DUMP_BUFS */
-
-/*
- * The ECC-CMS-SharedInfo struct, as defined in RFC 3278 8.2, and the
- * template for DER encoding and decoding it.
- */
-typedef struct {
- SECAlgorithmID algId; /* KEK alg, NULL params */
- CSSM_DATA entityUInfo; /* optional, ukm */
- CSSM_DATA suppPubInfo; /* length of KEK in bits as 4-byte integer */
-} ECC_CMS_SharedInfo;
-
-static const SecAsn1Template ECC_CMS_SharedInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ECC_CMS_SharedInfo) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(ECC_CMS_SharedInfo,entityUInfo),
- kSecAsn1OctetStringTemplate },
- { SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 2,
- offsetof(ECC_CMS_SharedInfo,suppPubInfo),
- kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-/*
- * Given a context specified via a CSSM_CC_HANDLE, add a new
- * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
- * AttributeLength, and an untyped pointer.
- */
-/* specify either 32-bit integer or a pointer as an added attribute value */
-typedef enum {
- CAT_Uint32,
- 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,
- unsigned char *b)
-{
- int dex;
- for(dex=3; dex>=0; dex--) {
- b[dex] = i;
- i >>= 8;
- }
-}
-
-/*
- * 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
- * be used here because the message does not contain a key size
- * indication.
- */
-static OSStatus encrAlgInfo(
- SECOidTag oidTag,
- uint32 *keySizeBits, /* RETURNED */
- CSSM_ENCRYPT_MODE *mode) /* RETURNED */
-{
- *keySizeBits = 64; /* default */
- *mode = CSSM_ALGMODE_CBCPadIV8; /* 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;
- }
- return noErr;
-}
-
-#pragma mark ---- ECDH CEK key wrap ----
-
-/*
- * Encrypt bulk encryption key (a.k.a. content encryption key, CEK) using ECDH
- */
-OSStatus
-SecCmsUtilEncryptSymKeyECDH(
- PLArenaPool *poolp,
- SecCertificateRef cert, /* recipient's cert */
- SecSymmetricKeyRef key, /* bulk key */
- /* remaining fields RETURNED */
- CSSM_DATA_PTR encKey, /* encrypted key --> recipientEncryptedKeys[0].EncryptedKey */
- CSSM_DATA_PTR ukm, /* random UKM --> KeyAgreeRecipientInfo.ukm */
- SECAlgorithmID *keyEncAlg, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
- * params := another encoded AlgId, with the KEK alg and IV */
- CSSM_DATA_PTR pubKey) /* our pub key as ECPoint -->
- * 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"};
- 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));
-
- 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;
- }
- }
- }
- }
-
- 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;
- }
- 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;
- }
-
- 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;
- }
- 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);
- ukm->Length = UKM_LENGTH;
- crtn = cmsGenRand(rawCspHand, UKM_LENGTH, ukm->Data);
- if(crtn) {
- goto loser;
- }
- 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
- * 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;
- }
- dumpBuf("sender IV", &ivData);
-
- memset(&kekAlgId, 0, sizeof(kekAlgId));
- if (!SEC_ASN1EncodeItem(poolp, &kekAlgId.parameters,
- &ivData, kSecAsn1OctetStringTemplate)) {
- rv = internalComponentErr;
- goto loser;
- }
-
- /* 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;
- }
- kekAlgId.algorithm = kekOid->oid;
- memset(keyEncAlg, 0, sizeof(*keyEncAlg));
- if (!SEC_ASN1EncodeItem(poolp, &keyEncAlg->parameters,
- &kekAlgId, SECOID_AlgorithmIDTemplate)) {
- rv = internalComponentErr;
- goto loser;
- }
- kekOid = SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF);
- if(kekOid == NULL) {
- dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
- rv = internalComponentErr;
- goto loser;
- }
- keyEncAlg->algorithm = kekOid->oid;
-
- /*
- * 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.
- */
- memset(&sharedInfo, 0, sizeof(sharedInfo));
- kekOid = SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG);
- sharedInfo.algId.algorithm = kekOid->oid;
- sharedInfo.algId.parameters.Data = nullData;
- sharedInfo.algId.parameters.Length = 2;
- sharedInfo.entityUInfo = *ukm;
- int32ToBytes(ECDH_KEK_KEY_LEN_BYTES << 3, keyLenAsBytes);
- sharedInfo.suppPubInfo.Length = 4;
- sharedInfo.suppPubInfo.Data = keyLenAsBytes;
- if (!SEC_ASN1EncodeItem(poolp, &sharedInfoEnc,
- &sharedInfo, ECC_CMS_SharedInfoTemplate)) {
- rv = internalComponentErr;
- goto loser;
- }
- 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;
- }
-
- /*
- * Finally, 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);
- }
- if(cekCssm.KeyData.Data) {
- CSSM_FreeKey(refCspHand, NULL, &cekCssm, CSSM_FALSE);
- }
- if(kekDerive.KeyData.Data) {
- CSSM_FreeKey(rawCspHand, NULL, &kekDerive, CSSM_FALSE);
- }
- if(theirPubKeyCssm) {
- /* Allocated by CL */
- cmsFreeCssmMemory(clHand, theirPubKeyCssm->KeyData.Data);
- cmsFreeCssmMemory(clHand, theirPubKeyCssm);
- }
- return rv;
-}
-
-#pragma mark ---- ECDH CEK key unwrap ----
-
-SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyECDH(
- SecPrivateKeyRef privkey, /* our private key */
- CSSM_DATA_PTR encKey, /* encrypted CEK */
- CSSM_DATA_PTR ukm, /* random UKM from KeyAgreeRecipientInfo.ukm */
- SECAlgorithmID *keyEncAlg, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
- * params := another encoded AlgId, with the KEK alg and IV */
- 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;
- CSSM_DATA iv = {0, NULL};
- ECC_CMS_SharedInfo sharedInfo;
- 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));
-
- /* 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;
- }
- memset(&keyAlgParam, 0, sizeof(keyAlgParam));
- if(SEC_ASN1DecodeItem(pool, &keyAlgParam, SECOID_AlgorithmIDTemplate,
- &keyEncAlg->parameters)) {
- dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n");
- goto loser;
- }
- kekOid = SECOID_FindOID(&keyAlgParam.algorithm);
- if(kekOid == NULL) {
- dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n");
- goto loser;
- }
- rv = encrAlgInfo(kekOid->offset, &kekSizeBits, &kekMode);
- if(rv) {
- goto loser;
- }
- /* 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;
- }
-
- /*
- * 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.
- */
- memset(&sharedInfo, 0, sizeof(sharedInfo));
- sharedInfo.algId.algorithm = kekOid->oid;
- sharedInfo.algId.parameters.Data = nullData;
- sharedInfo.algId.parameters.Length = 2;
- sharedInfo.entityUInfo = *ukm;
- int32ToBytes(kekSizeBits, keyLenAsBytes);
- sharedInfo.suppPubInfo.Length = 4;
- sharedInfo.suppPubInfo.Data = keyLenAsBytes;
- if (!SEC_ASN1EncodeItem(pool, &sharedInfoEnc,
- &sharedInfo, ECC_CMS_SharedInfoTemplate)) {
- rv = internalComponentErr;
- goto loser;
- }
- 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;
- }
- rv = SecKeyGetCredentials(privkey,
- CSSM_ACL_AUTHORIZATION_DERIVE,
- kSecCredentialTypeDefault,
- &accessCred);
- 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;
- }
- 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;
- }
-
- /*
- * 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;
- }
-
- memset(&wrappedKey, 0, sizeof(CSSM_KEY));
- memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
-
- bulkAlg = SECOID_FindyCssmAlgorithmByTag(bulkalgtag);
- if(bulkAlg == CSSM_ALGID_NONE) {
- dprintf("SecCmsUtilDecryptSymKeyECDH: unknown bulk alg\n");
- goto loser;
- }
-
- 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);
- }
-
-loser:
- if(pool != NULL) {
- PORT_FreeArena(pool, PR_FALSE);
- }
- if(kekDerive.KeyData.Data) {
- CSSM_FreeKey(refCspHand, NULL, &kekDerive, CSSM_FALSE);
- }
- if(outKey == NULL) {
- PORT_SetError(SEC_ERROR_NO_KEY);
- }
- return outKey;
-}
-
-
-