security/nss/lib/smime/cmspubkey.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * CMS public key crypto
     7  */
     9 #include "cmslocal.h"
    11 #include "cert.h"
    12 #include "key.h"
    13 #include "secasn1.h"
    14 #include "secitem.h"
    15 #include "secoid.h"
    16 #include "pk11func.h"
    17 #include "secerr.h"
    19 /* ====== RSA ======================================================================= */
    21 /*
    22  * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA
    23  *
    24  * this function takes a symmetric key and encrypts it using an RSA public key
    25  * according to PKCS#1 and RFC2633 (S/MIME)
    26  */
    27 SECStatus
    28 NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, 
    29                               PK11SymKey *bulkkey,
    30                               SECItem *encKey)
    31 {
    32     SECStatus rv;
    33     SECKEYPublicKey *publickey;
    35     publickey = CERT_ExtractPublicKey(cert);
    36     if (publickey == NULL)
    37 	return SECFailure;
    39     rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, publickey, bulkkey, encKey);
    40     SECKEY_DestroyPublicKey(publickey);
    41     return rv;
    42 }
    44 SECStatus
    45 NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp, 
    46                                     SECKEYPublicKey *publickey, 
    47                                     PK11SymKey *bulkkey, SECItem *encKey)
    48 {
    49     SECStatus rv;
    50     int data_len;
    51     KeyType keyType;
    52     void *mark = NULL;
    55     mark = PORT_ArenaMark(poolp);
    56     if (!mark)
    57 	goto loser;
    59     /* sanity check */
    60     keyType = SECKEY_GetPublicKeyType(publickey);
    61     PORT_Assert(keyType == rsaKey);
    62     if (keyType != rsaKey) {
    63 	goto loser;
    64     }
    65     /* allocate memory for the encrypted key */
    66     data_len = SECKEY_PublicKeyStrength(publickey);	/* block size (assumed to be > keylen) */
    67     encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
    68     encKey->len = data_len;
    69     if (encKey->data == NULL)
    70 	goto loser;
    72     /* encrypt the key now */
    73     rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION),
    74 				publickey, bulkkey, encKey);
    76     if (rv != SECSuccess)
    77 	goto loser;
    79     PORT_ArenaUnmark(poolp, mark);
    80     return SECSuccess;
    82 loser:
    83     if (mark) {
    84 	PORT_ArenaRelease(poolp, mark);
    85     }
    86     return SECFailure;
    87 }
    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     CK_MECHANISM_TYPE target;
   101     PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
   102     target = PK11_AlgtagToMechanism(bulkalgtag);
   103     if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) {
   104 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   105 	return NULL;
   106     }
   107     return PK11_PubUnwrapSymKey(privkey, encKey, target, CKA_DECRYPT, 0);
   108 }
   110 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
   112 SECStatus
   113 NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
   114 			SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
   115 			SECItem *pubKey)
   116 {
   117 #if 0 /* not yet done */
   118     SECOidTag certalgtag;	/* the certificate's encryption algorithm */
   119     SECOidTag encalgtag;	/* the algorithm used for key exchange/agreement */
   120     SECStatus rv;
   121     SECItem *params = NULL;
   122     int data_len;
   123     SECStatus err;
   124     PK11SymKey *tek;
   125     CERTCertificate *ourCert;
   126     SECKEYPublicKey *ourPubKey;
   127     NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid;
   129     certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
   130     PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
   132     /* We really want to show our KEA tag as the key exchange algorithm tag. */
   133     encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
   135     /* Get the public key of the recipient. */
   136     publickey = CERT_ExtractPublicKey(cert);
   137     if (publickey == NULL) goto loser;
   139     /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
   140     /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
   141     if (ourCert == NULL) goto loser;
   143     arena = PORT_NewArena(1024);
   144     if (arena == NULL) goto loser;
   146     /* While we're here, extract the key pair's public key data and copy it into */
   147     /* the outgoing parameters. */
   148     /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
   149     if (ourPubKey == NULL)
   150     {
   151 	goto loser;
   152     }
   153     SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
   154     SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
   155     ourPubKey = NULL;
   157     /* Extract our private key in order to derive the KEA key. */
   158     ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
   159     CERT_DestroyCertificate(ourCert); /* we're done with this */
   160     if (!ourPrivKey) goto loser;
   162     /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
   163     if (ukm) {
   164 	ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
   165 	ukm->len = /* XXXX */;
   166     }
   168     /* Generate the KEK (key exchange key) according to RFC2631 which we use
   169      * to wrap the bulk encryption key. */
   170     kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
   171 			 ukm, NULL,
   172 			 /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
   173 			 CKA_WRAP, 0, wincx);
   175     SECKEY_DestroyPublicKey(publickey);
   176     SECKEY_DestroyPrivateKey(ourPrivKey);
   177     publickey = NULL;
   178     ourPrivKey = NULL;
   180     if (!kek)
   181 	goto loser;
   183     /* allocate space for the encrypted CEK (bulk key) */
   184     encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
   185     encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
   187     if (encKey->data == NULL)
   188     {
   189 	PK11_FreeSymKey(kek);
   190 	goto loser;
   191     }
   194     /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
   195     /* bulk encryption algorithm */
   196     switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
   197     {
   198     case /* XXXX */CKM_SKIPJACK_CFB8:
   199 	err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
   200 	whichKEA = NSSCMSKEAUsesSkipjack;
   201 	break;
   202     case /* XXXX */CKM_SKIPJACK_CFB8:
   203 	err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
   204 	whichKEA = NSSCMSKEAUsesSkipjack;
   205 	break;
   206     default:
   207 	/* XXXX what do we do here? Neither RC2 nor 3DES... */
   208         err = SECFailure;
   209         /* set error */
   210 	break;
   211     }
   213     PK11_FreeSymKey(kek);	/* we do not need the KEK anymore */
   214     if (err != SECSuccess)
   215 	goto loser;
   217     PORT_Assert(whichKEA != NSSCMSKEAInvalid);
   219     /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
   220     /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
   221     params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
   222     if (params == NULL)
   223 	goto loser;
   225     /* now set keyEncAlg */
   226     rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
   227     if (rv != SECSuccess)
   228 	goto loser;
   230     /* XXXXXXX this is not right yet */
   231 loser:
   232     if (arena) {
   233 	PORT_FreeArena(arena, PR_FALSE);
   234     }
   235     if (publickey) {
   236         SECKEY_DestroyPublicKey(publickey);
   237     }
   238     if (ourPrivKey) {
   239         SECKEY_DestroyPrivateKey(ourPrivKey);
   240     }
   241 #endif
   242     return SECFailure;
   243 }
   245 PK11SymKey *
   246 NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
   247 {
   248 #if 0 /* not yet done */
   249     SECStatus err;
   250     CK_MECHANISM_TYPE bulkType;
   251     PK11SymKey *tek;
   252     SECKEYPublicKey *originatorPubKey;
   253     NSSCMSSMIMEKEAParameters keaParams;
   255    /* XXXX get originator's public key */
   256    originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
   257 			   keaParams.originatorKEAKey.len);
   258    if (originatorPubKey == NULL)
   259       goto loser;
   261    /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
   262       The Derive function generates a shared secret and combines it with the originatorRA
   263       data to come up with an unique session key */
   264    tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
   265 			 &keaParams.originatorRA, NULL,
   266 			 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
   267 			 CKA_WRAP, 0, pwfn_arg);
   268    SECKEY_DestroyPublicKey(originatorPubKey);	/* not needed anymore */
   269    if (tek == NULL)
   270 	goto loser;
   272     /* Now that we have the TEK, unwrap the bulk key
   273        with which to decrypt the message. */
   274     /* Skipjack is being used as the bulk encryption algorithm.*/
   275     /* Unwrap the bulk key. */
   276     bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
   277 				encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
   279     return bulkkey;
   281 loser:
   282 #endif
   283     return NULL;
   284 }

mercurial