cmspubkey.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:18k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  * CMS public key crypto
  35.  *
  36.  * $Id: cmspubkey.c,v 1.2 2000/06/13 21:56:30 chrisk%netscape.com Exp $
  37.  */
  38. #include "cmslocal.h"
  39. #include "cert.h"
  40. #include "key.h"
  41. #include "secasn1.h"
  42. #include "secitem.h"
  43. #include "secoid.h"
  44. #include "pk11func.h"
  45. #include "secerr.h"
  46. /* ====== RSA ======================================================================= */
  47. /*
  48.  * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA
  49.  *
  50.  * this function takes a symmetric key and encrypts it using an RSA public key
  51.  * according to PKCS#1 and RFC2633 (S/MIME)
  52.  */
  53. SECStatus
  54. NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *bulkkey,
  55. SECItem *encKey)
  56. {
  57.     SECOidTag certalgtag; /* the certificate's encryption algorithm */
  58.     SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
  59.     SECStatus rv;
  60.     SECKEYPublicKey *publickey;
  61.     int data_len;
  62.     void *mark;
  63.     /* sanity check */
  64.     certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  65.     PORT_Assert(certalgtag == SEC_OID_PKCS1_RSA_ENCRYPTION);
  66.     encalgtag = SEC_OID_PKCS1_RSA_ENCRYPTION;
  67.     publickey = CERT_ExtractPublicKey(cert);
  68.     if (publickey == NULL)
  69. goto loser;
  70.     mark = PORT_ArenaMark(poolp);
  71.     /* allocate memory for the encrypted key */
  72.     data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */
  73.     encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
  74.     encKey->len = data_len;
  75.     if (encKey->data == NULL)
  76. goto loser;
  77.     /* encrypt the key now */
  78.     rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION),
  79. publickey, bulkkey, encKey);
  80.     SECKEY_DestroyPublicKey(publickey);
  81.     if (rv != SECSuccess)
  82. goto loser;
  83.     PORT_ArenaUnmark(poolp, mark);
  84.     return SECSuccess;
  85. loser:
  86.     PORT_ArenaRelease(poolp, mark);
  87.     return SECFailure;
  88. }
  89. /*
  90.  * NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key
  91.  *
  92.  * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
  93.  * key handle. Please note that the actual unwrapped key data may not be allowed to leave
  94.  * a hardware token...
  95.  */
  96. PK11SymKey *
  97. NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag)
  98. {
  99.     /* that's easy */
  100.     return PK11_PubUnwrapSymKey(privkey, encKey, PK11_AlgtagToMechanism(bulkalgtag), CKA_DECRYPT, 0);
  101. }
  102. /* ====== MISSI (Fortezza) ========================================================== */
  103. extern const SEC_ASN1Template NSS_SMIMEKEAParamTemplateAllParams[];
  104. SECStatus
  105. NSS_CMSUtil_EncryptSymKey_MISSI(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *bulkkey,
  106. SECOidTag symalgtag, SECItem *encKey, SECItem **pparams, void *pwfn_arg)
  107. {
  108.     SECOidTag certalgtag; /* the certificate's encryption algorithm */
  109.     SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
  110.     SECStatus rv = SECFailure;
  111.     SECItem *params = NULL;
  112.     SECStatus err;
  113.     PK11SymKey *tek;
  114.     CERTCertificate *ourCert;
  115.     SECKEYPublicKey *ourPubKey, *publickey = NULL;
  116.     SECKEYPrivateKey *ourPrivKey = NULL;
  117.     NSSCMSKEATemplateSelector whichKEA;
  118.     NSSCMSSMIMEKEAParameters keaParams;
  119.     PLArenaPool *arena;
  120.     extern const SEC_ASN1Template *nss_cms_get_kea_template(NSSCMSKEATemplateSelector whichTemplate);
  121.     /* Clear keaParams, since cleanup code checks the lengths */
  122.     (void) memset(&keaParams, 0, sizeof(keaParams));
  123.     certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  124.     PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD ||
  125. certalgtag == SEC_OID_MISSI_KEA_DSS ||
  126. certalgtag == SEC_OID_MISSI_KEA);
  127. #define SMIME_FORTEZZA_RA_LENGTH 128
  128. #define SMIME_FORTEZZA_IV_LENGTH 24
  129. #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
  130.     /* We really want to show our KEA tag as the key exchange algorithm tag. */
  131.     encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
  132.     /* Get the public key of the recipient. */
  133.     publickey = CERT_ExtractPublicKey(cert);
  134.     if (publickey == NULL) goto loser;
  135.     /* Find our own cert, and extract its keys. */
  136.     ourCert = PK11_FindBestKEAMatch(cert, pwfn_arg);
  137.     if (ourCert == NULL) goto loser;
  138.     arena = PORT_NewArena(1024);
  139.     if (arena == NULL)
  140. goto loser;
  141.     ourPubKey = CERT_ExtractPublicKey(ourCert);
  142.     if (ourPubKey == NULL) {
  143. CERT_DestroyCertificate(ourCert);
  144. goto loser;
  145.     }
  146.     /* While we're here, copy the public key into the outgoing
  147.      * KEA parameters. */
  148.     SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey), &(ourPubKey->u.fortezza.KEAKey));
  149.     SECKEY_DestroyPublicKey(ourPubKey);
  150.     ourPubKey = NULL;
  151.     /* Extract our private key in order to derive the KEA key. */
  152.     ourPrivKey = PK11_FindKeyByAnyCert(ourCert, pwfn_arg);
  153.     CERT_DestroyCertificate(ourCert); /* we're done with this */
  154.     if (!ourPrivKey)
  155. goto loser;
  156.     /* Prepare raItem with 128 bytes (filled with zeros). */
  157.     keaParams.originatorRA.data = (unsigned char *)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
  158.     keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;
  159.     /* Generate the TEK (token exchange key) which we use
  160.      * to wrap the bulk encryption key. (keaparams.originatorRA) will be
  161.      * filled with a random seed which we need to send to
  162.      * the recipient. (user keying material in RFC2630/DSA speak) */
  163.     tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
  164.  &keaParams.originatorRA, NULL,
  165.  CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
  166.  CKA_WRAP, 0,  pwfn_arg);
  167.     SECKEY_DestroyPublicKey(publickey);
  168.     SECKEY_DestroyPrivateKey(ourPrivKey);
  169.     publickey = NULL;
  170.     ourPrivKey = NULL;
  171.     
  172.     if (!tek)
  173. goto loser;
  174.     /* allocate space for the wrapped key data */
  175.     encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
  176.     encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
  177.     if (encKey->data == NULL) {
  178. PK11_FreeSymKey(tek);
  179. goto loser;
  180.     }
  181.     /* Wrap the bulk key. What we do with the resulting data
  182.        depends on whether we're using Skipjack to wrap the key. */
  183.     switch (PK11_AlgtagToMechanism(symalgtag)) {
  184.     case CKM_SKIPJACK_CBC64:
  185.     case CKM_SKIPJACK_ECB64:
  186.     case CKM_SKIPJACK_OFB64:
  187.     case CKM_SKIPJACK_CFB64:
  188.     case CKM_SKIPJACK_CFB32:
  189.     case CKM_SKIPJACK_CFB16:
  190.     case CKM_SKIPJACK_CFB8:
  191. /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
  192. err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, bulkkey, encKey);
  193. whichKEA = NSSCMSKEAUsesSkipjack;
  194. break;
  195.     default:
  196. /* Not SKIPJACK, we encrypt the raw key data */
  197. keaParams.nonSkipjackIV.data = 
  198.   (unsigned char *)PORT_ArenaAlloc(arena, SMIME_FORTEZZA_IV_LENGTH);
  199. keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
  200. err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, tek, bulkkey, encKey);
  201. if (err != SECSuccess)
  202.     goto loser;
  203. if (encKey->len != PK11_GetKeyLength(bulkkey)) {
  204.     /* The size of the encrypted key is not the same as
  205.        that of the original bulk key, presumably due to
  206.        padding. Encode and store the real size of the
  207.        bulk key. */
  208.     if (SEC_ASN1EncodeInteger(arena, &keaParams.bulkKeySize, PK11_GetKeyLength(bulkkey)) == NULL)
  209. err = (SECStatus)PORT_GetError();
  210.     else
  211. /* use full template for encoding */
  212. whichKEA = NSSCMSKEAUsesNonSkipjackWithPaddedEncKey;
  213. }
  214. else
  215.     /* enc key length == bulk key length */
  216.     whichKEA = NSSCMSKEAUsesNonSkipjack; 
  217. break;
  218.     }
  219.     PK11_FreeSymKey(tek);
  220.     if (err != SECSuccess)
  221. goto loser;
  222.     /* Encode the KEA parameters into the recipient info. */
  223.     params = SEC_ASN1EncodeItem(poolp, NULL, &keaParams, nss_cms_get_kea_template(whichKEA));
  224.     if (params == NULL)
  225. goto loser;
  226.     /* pass back the algorithm params */
  227.     *pparams = params;
  228.     rv = SECSuccess;
  229. loser:
  230.     if (arena)
  231. PORT_FreeArena(arena, PR_FALSE);
  232.     if (publickey)
  233.         SECKEY_DestroyPublicKey(publickey);
  234.     if (ourPrivKey)
  235.         SECKEY_DestroyPrivateKey(ourPrivKey);
  236.     return rv;
  237. }
  238. PK11SymKey *
  239. NSS_CMSUtil_DecryptSymKey_MISSI(SECKEYPrivateKey *privkey, SECItem *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
  240. {
  241.     /* fortezza: do a key exchange */
  242.     SECStatus err;
  243.     CK_MECHANISM_TYPE bulkType;
  244.     PK11SymKey *tek;
  245.     SECKEYPublicKey *originatorPubKey;
  246.     NSSCMSSMIMEKEAParameters keaParams;
  247.     PK11SymKey *bulkkey;
  248.     int bulkLength;
  249.     (void) memset(&keaParams, 0, sizeof(keaParams));
  250.     /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
  251.        All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
  252.     /* Decode the KEA algorithm parameters. */
  253.     err = SEC_ASN1DecodeItem(NULL, &keaParams, NSS_SMIMEKEAParamTemplateAllParams,
  254.      &(keyEncAlg->parameters));
  255.     if (err != SECSuccess)
  256. goto loser;
  257.     /* get originator's public key */
  258.    originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
  259.    keaParams.originatorKEAKey.len);
  260.    if (originatorPubKey == NULL)
  261.   goto loser;
  262.     
  263.    /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
  264.       The Derive function generates a shared secret and combines it with the originatorRA
  265.       data to come up with an unique session key */
  266.    tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
  267.  &keaParams.originatorRA, NULL,
  268.  CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
  269.  CKA_WRAP, 0, pwfn_arg);
  270.    SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
  271.    if (tek == NULL)
  272. goto loser;
  273.     
  274.     /* Now that we have the TEK, unwrap the bulk key
  275.        with which to decrypt the message. We have to
  276.        do one of two different things depending on 
  277.        whether Skipjack was used for *bulk* encryption 
  278.        of the message. */
  279.     bulkType = PK11_AlgtagToMechanism(bulkalgtag);
  280.     switch (bulkType) {
  281.     case CKM_SKIPJACK_CBC64:
  282.     case CKM_SKIPJACK_ECB64:
  283.     case CKM_SKIPJACK_OFB64:
  284.     case CKM_SKIPJACK_CFB64:
  285.     case CKM_SKIPJACK_CFB32:
  286.     case CKM_SKIPJACK_CFB16:
  287.     case CKM_SKIPJACK_CFB8:
  288. /* Skipjack is being used as the bulk encryption algorithm.*/
  289. /* Unwrap the bulk key. */
  290. bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
  291.     encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
  292. break;
  293.     default:
  294. /* Skipjack was not used for bulk encryption of this
  295.    message. Use Skipjack CBC64, with the nonSkipjackIV
  296.    part of the KEA key parameters, to decrypt 
  297.    the bulk key. If the optional parameter bulkKeySize is present,
  298.    bulk key size is different than the encrypted key size */
  299. if (keaParams.bulkKeySize.len > 0) {
  300.     err = SEC_ASN1DecodeItem(NULL, &bulkLength,
  301.       SEC_IntegerTemplate,
  302.       &keaParams.bulkKeySize);
  303.     if (err != SECSuccess)
  304. goto loser;
  305. }
  306. bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, 
  307.     encKey, bulkType, CKA_DECRYPT, bulkLength);
  308. break;
  309.     }
  310.     return bulkkey;
  311. loser:
  312.     return NULL;
  313. }
  314. /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
  315. SECStatus
  316. NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
  317. SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
  318. SECItem *pubKey)
  319. {
  320. #if 0 /* not yet done */
  321.     SECOidTag certalgtag; /* the certificate's encryption algorithm */
  322.     SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
  323.     SECStatus rv;
  324.     SECItem *params = NULL;
  325.     int data_len;
  326.     SECStatus err;
  327.     PK11SymKey *tek;
  328.     CERTCertificate *ourCert;
  329.     SECKEYPublicKey *ourPubKey;
  330.     NSSCMSKEATemplateSelector whichKEA;
  331.     certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  332.     PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
  333.     /* We really want to show our KEA tag as the key exchange algorithm tag. */
  334.     encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
  335.     /* Get the public key of the recipient. */
  336.     publickey = CERT_ExtractPublicKey(cert);
  337.     if (publickey == NULL) goto loser;
  338.     /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
  339.     /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
  340.     if (ourCert == NULL) goto loser;
  341.     arena = PORT_NewArena(1024);
  342.     if (arena == NULL) goto loser;
  343.     /* While we're here, extract the key pair's public key data and copy it into */
  344.     /* the outgoing parameters. */
  345.     /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
  346.     if (ourPubKey == NULL)
  347.     {
  348. goto loser;
  349.     }
  350.     SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
  351.     SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
  352.     ourPubKey = NULL;
  353.     /* Extract our private key in order to derive the KEA key. */
  354.     ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
  355.     CERT_DestroyCertificate(ourCert); /* we're done with this */
  356.     if (!ourPrivKey) goto loser;
  357.     /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
  358.     if (ukm) {
  359. ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
  360. ukm->len = /* XXXX */;
  361.     }
  362.     /* Generate the KEK (key exchange key) according to RFC2631 which we use
  363.      * to wrap the bulk encryption key. */
  364.     kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
  365.  ukm, NULL,
  366.  /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
  367.  CKA_WRAP, 0, wincx);
  368.     SECKEY_DestroyPublicKey(publickey);
  369.     SECKEY_DestroyPrivateKey(ourPrivKey);
  370.     publickey = NULL;
  371.     ourPrivKey = NULL;
  372.     
  373.     if (!kek)
  374. goto loser;
  375.     /* allocate space for the encrypted CEK (bulk key) */
  376.     encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
  377.     encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
  378.     if (encKey->data == NULL)
  379.     {
  380. PK11_FreeSymKey(kek);
  381. goto loser;
  382.     }
  383.     /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
  384.     /* bulk encryption algorithm */
  385.     switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
  386.     {
  387.     case /* XXXX */CKM_SKIPJACK_CFB8:
  388. err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
  389. whichKEA = NSSCMSKEAUsesSkipjack;
  390. break;
  391.     case /* XXXX */CKM_SKIPJACK_CFB8:
  392. err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
  393. whichKEA = NSSCMSKEAUsesSkipjack;
  394. break;
  395.     default:
  396. /* XXXX what do we do here? Neither RC2 nor 3DES... */
  397. break;
  398.     }
  399.     PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
  400.     if (err != SECSuccess)
  401. goto loser;
  402.     /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
  403.     /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
  404.     params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
  405.     if (params == NULL)
  406. goto loser;
  407.     /* now set keyEncAlg */
  408.     rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
  409.     if (rv != SECSuccess)
  410. goto loser;
  411.     /* XXXXXXX this is not right yet */
  412. loser:
  413.     if (arena) {
  414. PORT_FreeArena(arena, PR_FALSE);
  415.     }
  416.     if (publickey) {
  417.         SECKEY_DestroyPublicKey(publickey);
  418.     }
  419.     if (ourPrivKey) {
  420.         SECKEY_DestroyPrivateKey(ourPrivKey);
  421.     }
  422. #endif
  423.     return SECFailure;
  424. }
  425. PK11SymKey *
  426. NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
  427. {
  428. #if 0 /* not yet done */
  429.     SECStatus err;
  430.     CK_MECHANISM_TYPE bulkType;
  431.     PK11SymKey *tek;
  432.     SECKEYPublicKey *originatorPubKey;
  433.     NSSCMSSMIMEKEAParameters keaParams;
  434.    /* XXXX get originator's public key */
  435.    originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
  436.    keaParams.originatorKEAKey.len);
  437.    if (originatorPubKey == NULL)
  438.       goto loser;
  439.     
  440.    /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
  441.       The Derive function generates a shared secret and combines it with the originatorRA
  442.       data to come up with an unique session key */
  443.    tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
  444.  &keaParams.originatorRA, NULL,
  445.  CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
  446.  CKA_WRAP, 0, pwfn_arg);
  447.    SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
  448.    if (tek == NULL)
  449. goto loser;
  450.     
  451.     /* Now that we have the TEK, unwrap the bulk key
  452.        with which to decrypt the message. */
  453.     /* Skipjack is being used as the bulk encryption algorithm.*/
  454.     /* Unwrap the bulk key. */
  455.     bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
  456. encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
  457.     return bulkkey;
  458. loser:
  459. #endif
  460.     return NULL;
  461. }