]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_smime/lib/cmspubkey.c
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_smime / lib / cmspubkey.c
diff --git a/Security/libsecurity_smime/lib/cmspubkey.c b/Security/libsecurity_smime/lib/cmspubkey.c
deleted file mode 100644 (file)
index 0f4d9f4..0000000
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- * 
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- * 
- * The Original Code is the Netscape security libraries.
- * 
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation.  Portions created by Netscape are 
- * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
- * Rights Reserved.
- * 
- * Contributor(s):
- * 
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable 
- * instead of those above.  If you wish to allow use of your 
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * CMS public key crypto
- */
-
-#include "cmslocal.h"
-
-#include "secitem.h"
-#include "secoid.h"
-#include "cryptohi.h"
-
-#include <security_asn1/secasn1.h>
-#include <security_asn1/secerr.h>
-#include <Security/SecCertificatePriv.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 ======================================================================= */
-
-/*
- * SecCmsUtilEncryptSymKeyRSA - wrap a symmetric key with RSA
- *
- * this function takes a symmetric key and encrypts it using an RSA public key
- * according to PKCS#1 and RFC2633 (S/MIME)
- */
-OSStatus
-SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert, 
-                              SecSymmetricKeyRef bulkkey,
-                              CSSM_DATA_PTR encKey)
-{
-    OSStatus rv;
-    SecPublicKeyRef publickey;
-
-    rv = SecCertificateCopyPublicKey(cert,&publickey);
-    if (publickey == NULL)
-       return SECFailure;
-
-    rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey);
-    CFRelease(publickey);
-    return rv;
-}
-
-OSStatus
-SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp, 
-                                SecPublicKeyRef publickey, 
-                                SecSymmetricKeyRef bulkkey, CSSM_DATA_PTR encKey)
-{
-    OSStatus rv;
-    unsigned int data_len;
-    //KeyType keyType;
-    void *mark = 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;
-
-    // Convert length to bytes;
-    data_len >>= 2;
-    encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
-    encKey->Length = data_len;
-    if (encKey->Data == NULL)
-       goto loser;
-
-    /* encrypt the key now */
-    rv = WRAP_PubWrapSymKey(publickey, bulkkey, encKey);
-    if (rv != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark(poolp, mark);
-    return SECSuccess;
-
-loser:
-    if (mark) {
-       PORT_ArenaRelease(poolp, mark);
-    }
-    return SECFailure;
-}
-
-/*
- * SecCmsUtilDecryptSymKeyRSA - unwrap a RSA-wrapped symmetric key
- *
- * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
- * key handle. Please note that the actual unwrapped key data may not be allowed to leave
- * a hardware token...
- */
-SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECOidTag bulkalgtag)
-{
-    /* that's easy */
-    return WRAP_PubUnwrapSymKey(privkey, encKey, bulkalgtag);
-}
-
-#if 0
-// @@@ Implement Fortezza and Diffie hellman support
-
-/* ====== MISSI (Fortezza) ========================================================== */
-
-extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams[];
-
-OSStatus
-SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey,
-                       SECOidTag symalgtag, CSSM_DATA_PTR encKey, CSSM_DATA_PTR *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;
-    OSStatus err;
-    SecSymmetricKeyRef tek;
-    SecCertificateRef ourCert;
-    SecPublicKeyRef ourPubKey, *publickey = NULL;
-    SecPrivateKeyRef ourPrivKey = NULL;
-    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));
-
-    SecCertificateGetAlgorithmID(cert,&algid);
-    certalgtag = SECOID_GetAlgorithmTag(algid);
-    PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD ||
-               certalgtag == SEC_OID_MISSI_KEA_DSS ||
-               certalgtag == SEC_OID_MISSI_KEA);
-
-#define SMIME_FORTEZZA_RA_LENGTH 128
-#define SMIME_FORTEZZA_IV_LENGTH 24
-#define SMIME_FORTEZZA_MAX_KEY_SIZE 256
-
-    /* We really want to show our KEA tag as the key exchange algorithm tag. */
-    encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
-
-    /* Get the public key of the recipient. */
-    publickey = CERT_ExtractPublicKey(cert);
-    if (publickey == NULL) goto loser;
-
-    /* Find our own cert, and extract its keys. */
-    ourCert = PK11_FindBestKEAMatch(cert, pwfn_arg);
-    if (ourCert == NULL) goto loser;
-
-    arena = PORT_NewArena(1024);
-    if (arena == NULL)
-       goto loser;
-
-    ourPubKey = CERT_ExtractPublicKey(ourCert);
-    if (ourPubKey == NULL) {
-       CERT_DestroyCertificate(ourCert);
-       goto loser;
-    }
-
-    /* While we're here, copy the public key into the outgoing
-     * KEA parameters. */
-    SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey), &(ourPubKey->u.fortezza.KEAKey));
-    SECKEY_DestroyPublicKey(ourPubKey);
-    ourPubKey = NULL;
-
-    /* Extract our private key in order to derive the KEA key. */
-    ourPrivKey = PK11_FindKeyByAnyCert(ourCert, pwfn_arg);
-    CERT_DestroyCertificate(ourCert); /* we're done with this */
-    if (!ourPrivKey)
-       goto loser;
-
-    /* Prepare raItem with 128 bytes (filled with zeros). */
-    keaParams.originatorRA.Data = (unsigned char *)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
-    keaParams.originatorRA.Length = SMIME_FORTEZZA_RA_LENGTH;
-
-    /* Generate the TEK (token exchange key) which we use
-     * to wrap the bulk encryption key. (keaparams.originatorRA) will be
-     * filled with a random seed which we need to send to
-     * the recipient. (user keying material in RFC2630/DSA speak) */
-    tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
-                        &keaParams.originatorRA, NULL,
-                        CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
-                        CKA_WRAP, 0,  pwfn_arg);
-
-    SECKEY_DestroyPublicKey(publickey);
-    SECKEY_DestroyPrivateKey(ourPrivKey);
-    publickey = NULL;
-    ourPrivKey = NULL;
-    
-    if (!tek)
-       goto loser;
-
-    /* allocate space for the wrapped key data */
-    encKey->Data = (unsigned char *)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
-    encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
-
-    if (encKey->Data == NULL) {
-       CFRelease(tek);
-       goto loser;
-    }
-
-    /* Wrap the bulk key. What we do with the resulting data
-       depends on whether we're using Skipjack to wrap the key. */
-    switch (PK11_AlgtagToMechanism(symalgtag)) {
-    case CKM_SKIPJACK_CBC64:
-    case CKM_SKIPJACK_ECB64:
-    case CKM_SKIPJACK_OFB64:
-    case CKM_SKIPJACK_CFB64:
-    case CKM_SKIPJACK_CFB32:
-    case CKM_SKIPJACK_CFB16:
-    case CKM_SKIPJACK_CFB8:
-       /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
-       err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, bulkkey, encKey);
-       whichKEA = SecCmsKEAUsesSkipjack;
-       break;
-    default:
-       /* Not SKIPJACK, we encrypt the raw key data */
-       keaParams.nonSkipjackIV.Data = 
-         (unsigned char *)PORT_ArenaAlloc(arena, SMIME_FORTEZZA_IV_LENGTH);
-       keaParams.nonSkipjackIV.Length = SMIME_FORTEZZA_IV_LENGTH;
-       err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, tek, bulkkey, encKey);
-       if (err != SECSuccess)
-           goto loser;
-
-       if (encKey->Length != PK11_GetKeyLength(bulkkey)) {
-           /* The size of the encrypted key is not the same as
-              that of the original bulk key, presumably due to
-              padding. Encode and store the real size of the
-              bulk key. */
-           if (SEC_ASN1EncodeInteger(arena, &keaParams.bulkKeySize, PK11_GetKeyLength(bulkkey)) == NULL)
-               err = (OSStatus)PORT_GetError();
-           else
-               /* use full template for encoding */
-               whichKEA = SecCmsKEAUsesNonSkipjackWithPaddedEncKey;
-       }
-       else
-           /* enc key length == bulk key length */
-           whichKEA = SecCmsKEAUsesNonSkipjack; 
-       break;
-    }
-
-    CFRelease(tek);
-
-    if (err != SECSuccess)
-       goto loser;
-
-    PORT_Assert(whichKEA != SecCmsKEAInvalid);
-
-    /* Encode the KEA parameters into the recipient info. */
-    params = SEC_ASN1EncodeItem(poolp, NULL, &keaParams, nss_cms_get_kea_template(whichKEA));
-    if (params == NULL)
-       goto loser;
-
-    /* pass back the algorithm params */
-    *pparams = params;
-
-    rv = SECSuccess;
-
-loser:
-    if (arena)
-       PORT_FreeArena(arena, PR_FALSE);
-    if (publickey)
-        SECKEY_DestroyPublicKey(publickey);
-    if (ourPrivKey)
-        SECKEY_DestroyPrivateKey(ourPrivKey);
-    return rv;
-}
-
-SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
-{
-    /* fortezza: do a key exchange */
-    OSStatus err;
-    CK_MECHANISM_TYPE bulkType;
-    SecSymmetricKeyRef tek;
-    SecPublicKeyRef originatorPubKey;
-    SecCmsSMIMEKEAParameters keaParams;
-    SecSymmetricKeyRef bulkkey;
-    int bulkLength;
-
-    (void) memset(&keaParams, 0, sizeof(keaParams));
-
-    /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
-       All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
-
-    /* Decode the KEA algorithm parameters. */
-    err = SEC_ASN1DecodeItem(NULL, &keaParams, NSS_SMIMEKEAParamTemplateAllParams,
-                            &(keyEncAlg->parameters));
-    if (err != SECSuccess)
-       goto loser;
-
-    /* get originator's public key */
-   originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
-                          keaParams.originatorKEAKey.Length);
-   if (originatorPubKey == NULL)
-         goto loser;
-    
-   /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
-      The Derive function generates a shared secret and combines it with the originatorRA
-      data to come up with an unique session key */
-   tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
-                        &keaParams.originatorRA, NULL,
-                        CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
-                        CKA_WRAP, 0, pwfn_arg);
-   SECKEY_DestroyPublicKey(originatorPubKey);  /* not needed anymore */
-   if (tek == NULL)
-       goto loser;
-    
-    /* Now that we have the TEK, unwrap the bulk key
-       with which to decrypt the message. We have to
-       do one of two different things depending on 
-       whether Skipjack was used for *bulk* encryption 
-       of the message. */
-    bulkType = PK11_AlgtagToMechanism(bulkalgtag);
-    switch (bulkType) {
-    case CKM_SKIPJACK_CBC64:
-    case CKM_SKIPJACK_ECB64:
-    case CKM_SKIPJACK_OFB64:
-    case CKM_SKIPJACK_CFB64:
-    case CKM_SKIPJACK_CFB32:
-    case CKM_SKIPJACK_CFB16:
-    case CKM_SKIPJACK_CFB8:
-       /* Skipjack is being used as the bulk encryption algorithm.*/
-       /* Unwrap the bulk key. */
-       bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
-                                   encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
-       break;
-    default:
-       /* Skipjack was not used for bulk encryption of this
-          message. Use Skipjack CBC64, with the nonSkipjackIV
-          part of the KEA key parameters, to decrypt 
-          the bulk key. If the optional parameter bulkKeySize is present,
-          bulk key size is different than the encrypted key size */
-       if (keaParams.bulkKeySize.Length > 0) {
-           err = SEC_ASN1DecodeItem(NULL, &bulkLength,
-                                    SEC_ASN1_GET(SEC_IntegerTemplate),
-                                    &keaParams.bulkKeySize);
-           if (err != SECSuccess)
-               goto loser;
-       }
-       
-       bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, 
-                                   encKey, bulkType, CKA_DECRYPT, bulkLength);
-       break;
-    }
-    return bulkkey;
-loser:
-    return NULL;
-}
-
-/* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
-
-OSStatus
-SecCmsUtilEncryptSymKeyESDH(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef key,
-                       CSSM_DATA_PTR encKey, CSSM_DATA_PTR ukm, SECAlgorithmID *keyEncAlg,
-                       CSSM_DATA_PTR 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;
-    int data_len;
-    OSStatus err;
-    SecSymmetricKeyRef tek;
-    SecCertificateRef ourCert;
-    SecPublicKeyRef ourPubKey;
-    SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
-
-    certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
-    PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
-
-    /* We really want to show our KEA tag as the key exchange algorithm tag. */
-    encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
-
-    /* Get the public key of the recipient. */
-    publickey = CERT_ExtractPublicKey(cert);
-    if (publickey == NULL) goto loser;
-
-    /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
-    /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
-    if (ourCert == NULL) goto loser;
-
-    arena = PORT_NewArena(1024);
-    if (arena == NULL) goto loser;
-
-    /* While we're here, extract the key pair's public key data and copy it into */
-    /* the outgoing parameters. */
-    /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
-    if (ourPubKey == NULL)
-    {
-       goto loser;
-    }
-    SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
-    SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
-    ourPubKey = NULL;
-
-    /* Extract our private key in order to derive the KEA key. */
-    ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
-    CERT_DestroyCertificate(ourCert); /* we're done with this */
-    if (!ourPrivKey) goto loser;
-
-    /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
-    if (ukm) {
-       ukm->Data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
-       ukm->Length = /* XXXX */;
-    }
-
-    /* Generate the KEK (key exchange key) according to RFC2631 which we use
-     * to wrap the bulk encryption key. */
-    kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
-                        ukm, NULL,
-                        /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
-                        CKA_WRAP, 0, wincx);
-
-    SECKEY_DestroyPublicKey(publickey);
-    SECKEY_DestroyPrivateKey(ourPrivKey);
-    publickey = NULL;
-    ourPrivKey = NULL;
-    
-    if (!kek)
-       goto loser;
-
-    /* allocate space for the encrypted CEK (bulk key) */
-    encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
-    encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
-
-    if (encKey->Data == NULL)
-    {
-       CFRelease(kek);
-       goto loser;
-    }
-
-
-    /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
-    /* bulk encryption algorithm */
-    switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
-    {
-    case /* XXXX */CKM_SKIPJACK_CFB8:
-       err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
-       whichKEA = SecCmsKEAUsesSkipjack;
-       break;
-    case /* XXXX */CKM_SKIPJACK_CFB8:
-       err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
-       whichKEA = SecCmsKEAUsesSkipjack;
-       break;
-    default:
-       /* XXXX what do we do here? Neither RC2 nor 3DES... */
-        err = SECFailure;
-        /* set error */
-       break;
-    }
-
-    CFRelease(kek);    /* we do not need the KEK anymore */
-    if (err != SECSuccess)
-       goto loser;
-
-    PORT_Assert(whichKEA != SecCmsKEAInvalid);
-
-    /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
-    /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
-    params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
-    if (params == NULL)
-       goto loser;
-
-    /* now set keyEncAlg */
-    rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
-    if (rv != SECSuccess)
-       goto loser;
-
-    /* XXXXXXX this is not right yet */
-loser:
-    if (arena) {
-       PORT_FreeArena(arena, PR_FALSE);
-    }
-    if (publickey) {
-        SECKEY_DestroyPublicKey(publickey);
-    }
-    if (ourPrivKey) {
-        SECKEY_DestroyPrivateKey(ourPrivKey);
-    }
-#endif
-    return SECFailure;
-}
-
-SecSymmetricKeyRef
-SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
-{
-#if 0 /* not yet done */
-    OSStatus err;
-    CK_MECHANISM_TYPE bulkType;
-    SecSymmetricKeyRef tek;
-    SecPublicKeyRef originatorPubKey;
-    SecCmsSMIMEKEAParameters keaParams;
-
-   /* XXXX get originator's public key */
-   originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
-                          keaParams.originatorKEAKey.Length);
-   if (originatorPubKey == NULL)
-      goto loser;
-    
-   /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
-      The Derive function generates a shared secret and combines it with the originatorRA
-      data to come up with an unique session key */
-   tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
-                        &keaParams.originatorRA, NULL,
-                        CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
-                        CKA_WRAP, 0, pwfn_arg);
-   SECKEY_DestroyPublicKey(originatorPubKey);  /* not needed anymore */
-   if (tek == NULL)
-       goto loser;
-    
-    /* Now that we have the TEK, unwrap the bulk key
-       with which to decrypt the message. */
-    /* Skipjack is being used as the bulk encryption algorithm.*/
-    /* Unwrap the bulk key. */
-    bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
-                               encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
-
-    return bulkkey;
-
-loser:
-#endif
-    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,
-           &paramData,
-           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;
-}
-
-
-