security/nss/lib/smime/cmsrecinfo.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 recipientInfo methods.
     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 PRBool
    20 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
    21 {
    22     if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
    23 	NSSCMSRecipientIdentifier *rid;
    24 	rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
    25 	if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
    26 	    return PR_TRUE;
    27 	}
    28     }
    29     return PR_FALSE;
    30 }
    32 /*
    33  * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
    34  * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
    35  * been exported, and we would have added an ordinary enum to handle this 
    36  * check. Unfortunatly wo don't have that luxury so we are overloading the
    37  * contentTypeTag field. NO code should every try to interpret this content tag
    38  * as a real OID tag, or use any fields other than pwfn_arg or poolp of this 
    39  * CMSMessage for that matter */
    40 static const SECOidData fakeContent;
    41 NSSCMSRecipientInfo *
    42 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, 
    43 			    NSSCMSRecipientIDSelector type,
    44                             CERTCertificate *cert, 
    45 			    SECKEYPublicKey *pubKey, 
    46                             SECItem *subjKeyID, 
    47 			    void* pwfn_arg, 
    48 			    SECItem* DERinput)
    49 {
    50     NSSCMSRecipientInfo *ri;
    51     void *mark;
    52     SECOidTag certalgtag;
    53     SECStatus rv = SECSuccess;
    54     NSSCMSRecipientEncryptedKey *rek;
    55     NSSCMSOriginatorIdentifierOrKey *oiok;
    56     unsigned long version;
    57     SECItem *dummy;
    58     PLArenaPool *poolp;
    59     CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
    60     NSSCMSRecipientIdentifier *rid;
    61     extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
    63     if (!cmsg) {
    64 	/* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
    65 	 * and a private arena pool */
    66 	cmsg = NSS_CMSMessage_Create(NULL);
    67         cmsg->pwfn_arg = pwfn_arg;
    68 	/* mark it as a special cms message */
    69 	cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent;
    70     }
    72     poolp = cmsg->poolp;
    74     mark = PORT_ArenaMark(poolp);
    76     ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
    77     if (ri == NULL)
    78 	goto loser;
    80     ri->cmsg = cmsg;
    82     if (DERinput) {
    83         /* decode everything from DER */
    84         SECItem newinput;
    85         SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
    86         if (SECSuccess != rv)
    87             goto loser;
    88         rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
    89         if (SECSuccess != rv)
    90             goto loser;
    91     }
    93     switch (type) {
    94         case NSSCMSRecipientID_IssuerSN:
    95         {
    96             ri->cert = CERT_DupCertificate(cert);
    97             if (NULL == ri->cert)
    98                 goto loser;
    99             spki = &(cert->subjectPublicKeyInfo);
   100             break;
   101         }
   103         case NSSCMSRecipientID_SubjectKeyID:
   104         {
   105             PORT_Assert(pubKey);
   106             spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
   107             break;
   108         }
   110 	case NSSCMSRecipientID_BrandNew:
   111 	    goto done;
   112 	    break;
   114         default:
   115             /* unkown type */
   116             goto loser;
   117             break;
   118     }
   120     certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
   122     rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
   123     switch (certalgtag) {
   124     case SEC_OID_PKCS1_RSA_ENCRYPTION:
   125 	ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
   126 	rid->identifierType = type;
   127 	if (type == NSSCMSRecipientID_IssuerSN) {
   128 	    rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
   129 	    if (rid->id.issuerAndSN == NULL) {
   130 	      break;
   131 	    }
   132 	} else if (type == NSSCMSRecipientID_SubjectKeyID){
   133 	    NSSCMSKeyTransRecipientInfoEx *riExtra;
   135 	    rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
   136 	    if (rid->id.subjectKeyID == NULL) {
   137 		rv = SECFailure;
   138 		PORT_SetError(SEC_ERROR_NO_MEMORY);
   139 		break;
   140 	    } 
   141 	    SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
   142 	    if (rid->id.subjectKeyID->data == NULL) {
   143 		rv = SECFailure;
   144 		PORT_SetError(SEC_ERROR_NO_MEMORY);
   145 		break;
   146 	    }
   147 	    riExtra = &ri->ri.keyTransRecipientInfoEx;
   148 	    riExtra->version = 0;
   149 	    riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
   150 	    if (riExtra->pubKey == NULL) {
   151 		rv = SECFailure;
   152 		PORT_SetError(SEC_ERROR_NO_MEMORY);
   153 		break;
   154 	    }
   155 	} else {
   156 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
   157 	    rv = SECFailure;
   158 	}
   159 	break;
   160     case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
   161 	PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
   162 	if (type != NSSCMSRecipientID_IssuerSN) {
   163 	    rv = SECFailure;
   164 	    break;
   165 	}
   166 	/* a key agreement op */
   167 	ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
   169 	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
   170 	    rv = SECFailure;
   171 	    break;
   172 	}
   173 	/* we do not support the case where multiple recipients 
   174 	 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
   175 	 * in this case, we would need to walk all the recipientInfos, take the
   176 	 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
   177 	 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
   179 	/* only epheremal-static Diffie-Hellman is supported for now
   180 	 * this is the only form of key agreement that provides potential anonymity
   181 	 * of the sender, plus we do not have to include certs in the message */
   183 	/* force single recipientEncryptedKey for now */
   184 	if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
   185 	    rv = SECFailure;
   186 	    break;
   187 	}
   189 	/* hardcoded IssuerSN choice for now */
   190 	rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
   191 	if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
   192 	    rv = SECFailure;
   193 	    break;
   194 	}
   196 	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
   198 	/* see RFC2630 12.3.1.1 */
   199 	oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
   201 	rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
   202 				    (void *)rek);
   204 	break;
   205     default:
   206 	/* other algorithms not supported yet */
   207 	/* NOTE that we do not support any KEK algorithm */
   208 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   209 	rv = SECFailure;
   210 	break;
   211     }
   213     if (rv == SECFailure)
   214 	goto loser;
   216     /* set version */
   217     switch (ri->recipientInfoType) {
   218     case NSSCMSRecipientInfoID_KeyTrans:
   219 	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
   220 	    version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
   221 	else
   222 	    version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
   223 	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
   224 	if (dummy == NULL)
   225 	    goto loser;
   226 	break;
   227     case NSSCMSRecipientInfoID_KeyAgree:
   228 	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
   229 						NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
   230 	if (dummy == NULL)
   231 	    goto loser;
   232 	break;
   233     case NSSCMSRecipientInfoID_KEK:
   234 	/* NOTE: this cannot happen as long as we do not support any KEK algorithm */
   235 	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
   236 						NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
   237 	if (dummy == NULL)
   238 	    goto loser;
   239 	break;
   241     }
   243 done:
   244     PORT_ArenaUnmark (poolp, mark);
   245     if (freeSpki)
   246       SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
   247     return ri;
   249 loser:
   250     if (ri && ri->cert) {
   251         CERT_DestroyCertificate(ri->cert);
   252     }
   253     if (freeSpki) {
   254       SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
   255     }
   256     PORT_ArenaRelease (poolp, mark);
   257     if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
   258 	NSS_CMSMessage_Destroy(cmsg);
   259     }
   260     return NULL;
   261 }
   263 /*
   264  * NSS_CMSRecipientInfo_Create - create a recipientinfo
   265  *
   266  * we currently do not create KeyAgreement recipientinfos with multiple 
   267  * recipientEncryptedKeys the certificate is supposed to have been 
   268  * verified by the caller
   269  */
   270 NSSCMSRecipientInfo *
   271 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
   272 {
   273     return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, 
   274                                        NULL, NULL, NULL, NULL);
   275 }
   277 NSSCMSRecipientInfo *
   278 NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg)
   279 {
   280     return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 
   281                                        NULL, NULL, pwfn_arg, NULL);
   282 }
   284 NSSCMSRecipientInfo *
   285 NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg)
   286 {
   287     return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 
   288                                        NULL, NULL, pwfn_arg, input);
   289 }
   292 NSSCMSRecipientInfo *
   293 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage   *cmsg, 
   294                                      SECItem         *subjKeyID,
   295                                      SECKEYPublicKey *pubKey)
   296 {
   297     return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, 
   298                                        NULL, pubKey, subjKeyID, NULL, NULL);
   299 }
   301 NSSCMSRecipientInfo *
   302 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
   303                                              CERTCertificate *cert)
   304 {
   305     SECKEYPublicKey *pubKey = NULL;
   306     SECItem subjKeyID = {siBuffer, NULL, 0};
   307     NSSCMSRecipientInfo *retVal = NULL;
   309     if (!cmsg || !cert) {
   310 	return NULL;
   311     }
   312     pubKey = CERT_ExtractPublicKey(cert);
   313     if (!pubKey) {
   314 	goto done;
   315     }
   316     if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
   317         subjKeyID.data == NULL) {
   318 	goto done;
   319     }
   320     retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
   321 done:
   322     if (pubKey)
   323 	SECKEY_DestroyPublicKey(pubKey);
   325     if (subjKeyID.data)
   326 	SECITEM_FreeItem(&subjKeyID, PR_FALSE);
   328     return retVal;
   329 }
   331 void
   332 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
   333 {
   334     if (!ri) {
   335         return;
   336     }
   337     /* version was allocated on the pool, so no need to destroy it */
   338     /* issuerAndSN was allocated on the pool, so no need to destroy it */
   339     if (ri->cert != NULL)
   340 	CERT_DestroyCertificate(ri->cert);
   342     if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
   343 	NSSCMSKeyTransRecipientInfoEx *extra;
   344 	extra = &ri->ri.keyTransRecipientInfoEx;
   345 	if (extra->pubKey)
   346 	    SECKEY_DestroyPublicKey(extra->pubKey);
   347     }
   348     if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
   349 	NSS_CMSMessage_Destroy(ri->cmsg);
   350     }
   352     /* we're done. */
   353 }
   355 int
   356 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
   357 {
   358     unsigned long version;
   359     SECItem *versionitem = NULL;
   361     switch (ri->recipientInfoType) {
   362     case NSSCMSRecipientInfoID_KeyTrans:
   363 	/* ignore subIndex */
   364 	versionitem = &(ri->ri.keyTransRecipientInfo.version);
   365 	break;
   366     case NSSCMSRecipientInfoID_KEK:
   367 	/* ignore subIndex */
   368 	versionitem = &(ri->ri.kekRecipientInfo.version);
   369 	break;
   370     case NSSCMSRecipientInfoID_KeyAgree:
   371 	versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
   372 	break;
   373     }
   375     PORT_Assert(versionitem);
   376     if (versionitem == NULL) 
   377 	return 0;
   379     /* always take apart the SECItem */
   380     if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
   381 	return 0;
   382     else
   383 	return (int)version;
   384 }
   386 SECItem *
   387 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
   388 {
   389     SECItem *enckey = NULL;
   391     switch (ri->recipientInfoType) {
   392     case NSSCMSRecipientInfoID_KeyTrans:
   393 	/* ignore subIndex */
   394 	enckey = &(ri->ri.keyTransRecipientInfo.encKey);
   395 	break;
   396     case NSSCMSRecipientInfoID_KEK:
   397 	/* ignore subIndex */
   398 	enckey = &(ri->ri.kekRecipientInfo.encKey);
   399 	break;
   400     case NSSCMSRecipientInfoID_KeyAgree:
   401 	enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
   402 	break;
   403     }
   404     return enckey;
   405 }
   408 SECOidTag
   409 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
   410 {
   411     SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
   413     switch (ri->recipientInfoType) {
   414     case NSSCMSRecipientInfoID_KeyTrans:
   415 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
   416 	break;
   417     case NSSCMSRecipientInfoID_KeyAgree:
   418 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
   419 	break;
   420     case NSSCMSRecipientInfoID_KEK:
   421 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
   422 	break;
   423     }
   424     return encalgtag;
   425 }
   427 SECStatus
   428 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, 
   429                                  SECOidTag bulkalgtag)
   430 {
   431     CERTCertificate *cert;
   432     SECOidTag certalgtag;
   433     SECStatus rv = SECSuccess;
   434     NSSCMSRecipientEncryptedKey *rek;
   435     NSSCMSOriginatorIdentifierOrKey *oiok;
   436     CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
   437     PLArenaPool *poolp;
   438     NSSCMSKeyTransRecipientInfoEx *extra = NULL;
   439     PRBool usesSubjKeyID;
   441     poolp = ri->cmsg->poolp;
   442     cert = ri->cert;
   443     usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
   444     if (cert) {
   445 	spki = &cert->subjectPublicKeyInfo;
   446 	certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
   447     } else if (usesSubjKeyID) {
   448 	extra = &ri->ri.keyTransRecipientInfoEx;
   449 	/* sanity check */
   450 	PORT_Assert(extra->pubKey);
   451 	if (!extra->pubKey) {
   452 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
   453 	    return SECFailure;
   454 	}
   455 	spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
   456 	certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
   457     } else {
   458 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   459 	return SECFailure;
   460     }
   462     /* XXX set ri->recipientInfoType to the proper value here */
   463     /* or should we look if it's been set already ? */
   465     certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
   466     switch (certalgtag) {
   467     case SEC_OID_PKCS1_RSA_ENCRYPTION:
   468 	/* wrap the symkey */
   469 	if (cert) {
   470 	    rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, 
   471 	                         &ri->ri.keyTransRecipientInfo.encKey);
   472  	    if (rv != SECSuccess)
   473 		break;
   474 	} else if (usesSubjKeyID) {
   475 	    PORT_Assert(extra != NULL);
   476 	    rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
   477 	                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
   478  	    if (rv != SECSuccess)
   479 		break;
   480 	}
   482 	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
   483 	break;
   484     case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
   485 	rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
   486 	if (rek == NULL) {
   487 	    rv = SECFailure;
   488 	    break;
   489 	}
   491 	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
   492 	PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
   494 	/* see RFC2630 12.3.1.1 */
   495 	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
   496 				    SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
   497 	    rv = SECFailure;
   498 	    break;
   499 	}
   501 	/* this will generate a key pair, compute the shared secret, */
   502 	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
   503 	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
   504 	rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,
   505 					&rek->encKey,
   506 					&ri->ri.keyAgreeRecipientInfo.ukm,
   507 					&ri->ri.keyAgreeRecipientInfo.keyEncAlg,
   508 					&oiok->id.originatorPublicKey.publicKey);
   510 	break;
   511     default:
   512 	/* other algorithms not supported yet */
   513 	/* NOTE that we do not support any KEK algorithm */
   514 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   515 	rv = SECFailure;
   516 	break;
   517     }
   518     if (freeSpki)
   519 	SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
   521     return rv;
   522 }
   524 PK11SymKey *
   525 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, 
   526 	CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
   527 {
   528     PK11SymKey *bulkkey = NULL;
   529     SECAlgorithmID *encalg;
   530     SECOidTag encalgtag;
   531     SECItem *enckey;
   532     int error;
   534     ri->cert = CERT_DupCertificate(cert);
   535         	/* mark the recipientInfo so we can find it later */
   537     switch (ri->recipientInfoType) {
   538     case NSSCMSRecipientInfoID_KeyTrans:
   539 	encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
   540 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
   541 	enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
   542 	switch (encalgtag) {
   543 	case SEC_OID_PKCS1_RSA_ENCRYPTION:
   544 	    /* RSA encryption algorithm: */
   545 	    /* get the symmetric (bulk) key by unwrapping it using our private key */
   546 	    bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
   547 	    break;
   548 	default:
   549 	    error = SEC_ERROR_UNSUPPORTED_KEYALG;
   550 	    goto loser;
   551 	}
   552 	break;
   553     case NSSCMSRecipientInfoID_KeyAgree:
   554 	encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
   555 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
   556 	enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
   557 	switch (encalgtag) {
   558 	case SEC_OID_X942_DIFFIE_HELMAN_KEY:
   559 	    /* Diffie-Helman key exchange */
   560 	    /* XXX not yet implemented */
   561 	    /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
   562 	    /* we support ephemeral-static DH only, so if the recipientinfo */
   563 	    /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
   564 	    /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
   565 	    /* content encryption key using a Unwrap op */
   566 	    /* the derive operation has to generate the key using the algorithm in RFC2631 */
   567 	    error = SEC_ERROR_UNSUPPORTED_KEYALG;
   568 	    goto loser;
   569 	    break;
   570 	default:
   571 	    error = SEC_ERROR_UNSUPPORTED_KEYALG;
   572 	    goto loser;
   573 	}
   574 	break;
   575     case NSSCMSRecipientInfoID_KEK:
   576 	encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
   577 	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
   578 	enckey = &(ri->ri.kekRecipientInfo.encKey);
   579 	/* not supported yet */
   580 	error = SEC_ERROR_UNSUPPORTED_KEYALG;
   581 	goto loser;
   582 	break;
   583     }
   584     /* XXXX continue here */
   585     return bulkkey;
   587 loser:
   588     PORT_SetError(error);
   589     return NULL;
   590 }
   592 SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
   593                                              CERTCertificate** retcert,
   594                                              SECKEYPrivateKey** retkey)
   595 {
   596     CERTCertificate* cert = NULL;
   597     NSSCMSRecipient** recipients = NULL;
   598     NSSCMSRecipientInfo* recipientInfos[2];
   599     SECStatus rv = SECSuccess;
   600     SECKEYPrivateKey* key = NULL;
   602     if (!ri)
   603         return SECFailure;
   605     if (!retcert && !retkey) {
   606         /* nothing requested, nothing found, success */
   607         return SECSuccess;
   608     }
   610     if (retcert) {
   611         *retcert = NULL;
   612     }
   613     if (retkey) {
   614         *retkey = NULL;
   615     }
   617     if (ri->cert) {
   618         cert = CERT_DupCertificate(ri->cert);
   619         if (!cert) {
   620             rv = SECFailure;
   621         }
   622     }
   623     if (SECSuccess == rv && !cert) {
   624         /* we don't have the cert, we have to look for it */
   625         /* first build an NSS_CMSRecipient */
   626         recipientInfos[0] = ri;
   627         recipientInfos[1] = NULL;
   629         recipients = nss_cms_recipient_list_create(recipientInfos);
   630         if (recipients) {
   631             /* now look for the cert and key */
   632             if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
   633                 ri->cmsg->pwfn_arg)) {
   634                 cert = CERT_DupCertificate(recipients[0]->cert);
   635                 key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
   636             } else {
   637                 rv = SECFailure;
   638             }
   640             nss_cms_recipient_list_destroy(recipients);
   641         }
   642         else {
   643             rv = SECFailure;
   644         }            
   645     } else if (SECSuccess == rv && cert && retkey) {
   646         /* we have the cert, we just need the key now */
   647         key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
   648     }
   649     if (retcert) {
   650         *retcert = cert;
   651     } else {
   652         if (cert) {
   653             CERT_DestroyCertificate(cert);
   654         }
   655     }
   656     if (retkey) {
   657         *retkey = key;
   658     } else {
   659         if (key) {
   660             SECKEY_DestroyPrivateKey(key);
   661         }
   662     }
   664     return rv;
   665 }
   667 SECStatus NSS_CMSRecipientInfo_Encode(PLArenaPool* poolp,
   668                                       const NSSCMSRecipientInfo *src,
   669                                       SECItem* returned)
   670 {
   671     extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
   672     SECStatus rv = SECFailure;
   673     if (!src || !returned) {
   674         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   675     } else if (SEC_ASN1EncodeItem(poolp, returned, src,
   676         NSSCMSRecipientInfoTemplate))   {
   677         rv = SECSuccess;
   678     }
   679     return rv;
   680 }

mercurial