Back to index

lightning-sunbird  0.9+nobinonly
cmsrecinfo.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * CMS recipientInfo methods.
00039  *
00040  * $Id: cmsrecinfo.c,v 1.16.2.2 2006/07/19 00:34:19 nelson%bolyard.com Exp $
00041  */
00042 
00043 #include "cmslocal.h"
00044 
00045 #include "cert.h"
00046 #include "key.h"
00047 #include "secasn1.h"
00048 #include "secitem.h"
00049 #include "secoid.h"
00050 #include "pk11func.h"
00051 #include "secerr.h"
00052 
00053 PRBool
00054 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
00055 {
00056     if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
00057        NSSCMSRecipientIdentifier *rid;
00058        rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
00059        if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
00060            return PR_TRUE;
00061        }
00062     }
00063     return PR_FALSE;
00064 }
00065 
00066 /*
00067  * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
00068  * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
00069  * been exported, and we would have added an ordinary enum to handle this 
00070  * check. Unfortunatly wo don't have that luxury so we are overloading the
00071  * contentTypeTag field. NO code should every try to interpret this content tag
00072  * as a real OID tag, or use any fields other than pwfn_arg or poolp of this 
00073  * CMSMessage for that matter */
00074 static const SECOidData fakeContent;
00075 NSSCMSRecipientInfo *
00076 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type,
00077                             CERTCertificate *cert, SECKEYPublicKey *pubKey, 
00078                             SECItem *subjKeyID, void* pwfn_arg, SECItem* DERinput)
00079 {
00080     NSSCMSRecipientInfo *ri;
00081     void *mark;
00082     SECOidTag certalgtag;
00083     SECStatus rv = SECSuccess;
00084     NSSCMSRecipientEncryptedKey *rek;
00085     NSSCMSOriginatorIdentifierOrKey *oiok;
00086     unsigned long version;
00087     SECItem *dummy;
00088     PLArenaPool *poolp;
00089     CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
00090     NSSCMSRecipientIdentifier *rid;
00091     extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
00092 
00093     if (!cmsg) {
00094        /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
00095         * and a private arena pool */
00096        cmsg = NSS_CMSMessage_Create(NULL);
00097         cmsg->pwfn_arg = pwfn_arg;
00098        /* mark it as a special cms message */
00099        cmsg->contentInfo.contentTypeTag = &fakeContent;
00100     }
00101 
00102     poolp = cmsg->poolp;
00103 
00104     mark = PORT_ArenaMark(poolp);
00105 
00106     ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
00107     if (ri == NULL)
00108        goto loser;
00109 
00110     ri->cmsg = cmsg;
00111 
00112     if (DERinput) {
00113         /* decode everything from DER */
00114         SECItem newinput;
00115         SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
00116         if (SECSuccess != rv)
00117             goto loser;
00118         rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
00119         if (SECSuccess != rv)
00120             goto loser;
00121     }
00122 
00123     switch (type) {
00124         case NSSCMSRecipientID_IssuerSN:
00125         {
00126             ri->cert = CERT_DupCertificate(cert);
00127             if (NULL == ri->cert)
00128                 goto loser;
00129             spki = &(cert->subjectPublicKeyInfo);
00130             break;
00131         }
00132         
00133         case NSSCMSRecipientID_SubjectKeyID:
00134         {
00135             PORT_Assert(pubKey);
00136             spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
00137             break;
00138         }
00139 
00140        case NSSCMSRecipientID_BrandNew:
00141            goto done;
00142            break;
00143 
00144         default:
00145             /* unkown type */
00146             goto loser;
00147             break;
00148     }
00149 
00150     certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
00151 
00152     rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
00153     switch (certalgtag) {
00154     case SEC_OID_PKCS1_RSA_ENCRYPTION:
00155        ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
00156        rid->identifierType = type;
00157        if (type == NSSCMSRecipientID_IssuerSN) {
00158            rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
00159            if (rid->id.issuerAndSN == NULL) {
00160              break;
00161            }
00162        } else if (type == NSSCMSRecipientID_SubjectKeyID){
00163            NSSCMSKeyTransRecipientInfoEx *riExtra;
00164 
00165            rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
00166            if (rid->id.subjectKeyID == NULL) {
00167               rv = SECFailure;
00168               PORT_SetError(SEC_ERROR_NO_MEMORY);
00169               break;
00170            } 
00171            SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
00172            if (rid->id.subjectKeyID->data == NULL) {
00173               rv = SECFailure;
00174               PORT_SetError(SEC_ERROR_NO_MEMORY);
00175               break;
00176            }
00177            riExtra = &ri->ri.keyTransRecipientInfoEx;
00178            riExtra->version = 0;
00179            riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
00180            if (riExtra->pubKey == NULL) {
00181               rv = SECFailure;
00182               PORT_SetError(SEC_ERROR_NO_MEMORY);
00183               break;
00184            }
00185        } else {
00186            PORT_SetError(SEC_ERROR_INVALID_ARGS);
00187            rv = SECFailure;
00188        }
00189        break;
00190     case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
00191        PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
00192        if (type != NSSCMSRecipientID_IssuerSN) {
00193            rv = SECFailure;
00194            break;
00195        }
00196        /* a key agreement op */
00197        ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
00198 
00199        if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
00200            rv = SECFailure;
00201            break;
00202        }
00203        /* we do not support the case where multiple recipients 
00204         * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
00205         * in this case, we would need to walk all the recipientInfos, take the
00206         * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
00207         * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
00208 
00209        /* only epheremal-static Diffie-Hellman is supported for now
00210         * this is the only form of key agreement that provides potential anonymity
00211         * of the sender, plus we do not have to include certs in the message */
00212 
00213        /* force single recipientEncryptedKey for now */
00214        if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
00215            rv = SECFailure;
00216            break;
00217        }
00218 
00219        /* hardcoded IssuerSN choice for now */
00220        rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
00221        if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
00222            rv = SECFailure;
00223            break;
00224        }
00225 
00226        oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
00227 
00228        /* see RFC2630 12.3.1.1 */
00229        oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
00230 
00231        rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
00232                                 (void *)rek);
00233 
00234        break;
00235     default:
00236        /* other algorithms not supported yet */
00237        /* NOTE that we do not support any KEK algorithm */
00238        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
00239        rv = SECFailure;
00240        break;
00241     }
00242 
00243     if (rv == SECFailure)
00244        goto loser;
00245 
00246     /* set version */
00247     switch (ri->recipientInfoType) {
00248     case NSSCMSRecipientInfoID_KeyTrans:
00249        if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
00250            version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
00251        else
00252            version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
00253        dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
00254        if (dummy == NULL)
00255            goto loser;
00256        break;
00257     case NSSCMSRecipientInfoID_KeyAgree:
00258        dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
00259                                           NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
00260        if (dummy == NULL)
00261            goto loser;
00262        break;
00263     case NSSCMSRecipientInfoID_KEK:
00264        /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
00265        dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
00266                                           NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
00267        if (dummy == NULL)
00268            goto loser;
00269        break;
00270     
00271     }
00272 
00273 done:
00274     PORT_ArenaUnmark (poolp, mark);
00275     if (freeSpki)
00276       SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
00277     return ri;
00278 
00279 loser:
00280     if (ri && ri->cert) {
00281         CERT_DestroyCertificate(ri->cert);
00282     }
00283     if (freeSpki) {
00284       SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
00285     }
00286     PORT_ArenaRelease (poolp, mark);
00287     if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
00288        NSS_CMSMessage_Destroy(cmsg);
00289     }
00290     return NULL;
00291 }
00292 
00293 /*
00294  * NSS_CMSRecipientInfo_Create - create a recipientinfo
00295  *
00296  * we currently do not create KeyAgreement recipientinfos with multiple 
00297  * recipientEncryptedKeys the certificate is supposed to have been 
00298  * verified by the caller
00299  */
00300 NSSCMSRecipientInfo *
00301 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
00302 {
00303     return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, 
00304                                        NULL, NULL, NULL, NULL);
00305 }
00306 
00307 NSSCMSRecipientInfo *
00308 NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg)
00309 {
00310     return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 
00311                                        NULL, NULL, pwfn_arg, NULL);
00312 }
00313 
00314 NSSCMSRecipientInfo *
00315 NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg)
00316 {
00317     return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 
00318                                        NULL, NULL, pwfn_arg, input);
00319 }
00320 
00321 
00322 NSSCMSRecipientInfo *
00323 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage   *cmsg, 
00324                                      SECItem         *subjKeyID,
00325                                      SECKEYPublicKey *pubKey)
00326 {
00327     return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, 
00328                                        NULL, pubKey, subjKeyID, NULL, NULL);
00329 }
00330 
00331 NSSCMSRecipientInfo *
00332 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
00333                                              CERTCertificate *cert)
00334 {
00335     SECKEYPublicKey *pubKey = NULL;
00336     SECItem subjKeyID = {siBuffer, NULL, 0};
00337     NSSCMSRecipientInfo *retVal = NULL;
00338 
00339     if (!cmsg || !cert) {
00340        return NULL;
00341     }
00342     pubKey = CERT_ExtractPublicKey(cert);
00343     if (!pubKey) {
00344        goto done;
00345     }
00346     if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
00347         subjKeyID.data == NULL) {
00348        goto done;
00349     }
00350     retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
00351 done:
00352     if (pubKey)
00353        SECKEY_DestroyPublicKey(pubKey);
00354 
00355     if (subjKeyID.data)
00356        SECITEM_FreeItem(&subjKeyID, PR_FALSE);
00357 
00358     return retVal;
00359 }
00360 
00361 void
00362 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
00363 {
00364     if (!ri) {
00365         return;
00366     }
00367     /* version was allocated on the pool, so no need to destroy it */
00368     /* issuerAndSN was allocated on the pool, so no need to destroy it */
00369     if (ri->cert != NULL)
00370        CERT_DestroyCertificate(ri->cert);
00371 
00372     if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
00373        NSSCMSKeyTransRecipientInfoEx *extra;
00374        extra = &ri->ri.keyTransRecipientInfoEx;
00375        if (extra->pubKey)
00376            SECKEY_DestroyPublicKey(extra->pubKey);
00377     }
00378     if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
00379        NSS_CMSMessage_Destroy(ri->cmsg);
00380     }
00381 
00382     /* we're done. */
00383 }
00384 
00385 int
00386 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
00387 {
00388     unsigned long version;
00389     SECItem *versionitem = NULL;
00390 
00391     switch (ri->recipientInfoType) {
00392     case NSSCMSRecipientInfoID_KeyTrans:
00393        /* ignore subIndex */
00394        versionitem = &(ri->ri.keyTransRecipientInfo.version);
00395        break;
00396     case NSSCMSRecipientInfoID_KEK:
00397        /* ignore subIndex */
00398        versionitem = &(ri->ri.kekRecipientInfo.version);
00399        break;
00400     case NSSCMSRecipientInfoID_KeyAgree:
00401        versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
00402        break;
00403     }
00404 
00405     PORT_Assert(versionitem);
00406     if (versionitem == NULL) 
00407        return 0;
00408 
00409     /* always take apart the SECItem */
00410     if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
00411        return 0;
00412     else
00413        return (int)version;
00414 }
00415 
00416 SECItem *
00417 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
00418 {
00419     SECItem *enckey = NULL;
00420 
00421     switch (ri->recipientInfoType) {
00422     case NSSCMSRecipientInfoID_KeyTrans:
00423        /* ignore subIndex */
00424        enckey = &(ri->ri.keyTransRecipientInfo.encKey);
00425        break;
00426     case NSSCMSRecipientInfoID_KEK:
00427        /* ignore subIndex */
00428        enckey = &(ri->ri.kekRecipientInfo.encKey);
00429        break;
00430     case NSSCMSRecipientInfoID_KeyAgree:
00431        enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
00432        break;
00433     }
00434     return enckey;
00435 }
00436 
00437 
00438 SECOidTag
00439 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
00440 {
00441     SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
00442 
00443     switch (ri->recipientInfoType) {
00444     case NSSCMSRecipientInfoID_KeyTrans:
00445        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
00446        break;
00447     case NSSCMSRecipientInfoID_KeyAgree:
00448        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
00449        break;
00450     case NSSCMSRecipientInfoID_KEK:
00451        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
00452        break;
00453     }
00454     return encalgtag;
00455 }
00456 
00457 SECStatus
00458 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, 
00459                                  SECOidTag bulkalgtag)
00460 {
00461     CERTCertificate *cert;
00462     SECOidTag certalgtag;
00463     SECStatus rv = SECSuccess;
00464     SECItem *params = NULL;
00465     NSSCMSRecipientEncryptedKey *rek;
00466     NSSCMSOriginatorIdentifierOrKey *oiok;
00467     CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
00468     PLArenaPool *poolp;
00469     NSSCMSKeyTransRecipientInfoEx *extra = NULL;
00470     PRBool usesSubjKeyID;
00471 
00472     poolp = ri->cmsg->poolp;
00473     cert = ri->cert;
00474     usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
00475     if (cert) {
00476        spki = &cert->subjectPublicKeyInfo;
00477        certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
00478     } else if (usesSubjKeyID) {
00479        extra = &ri->ri.keyTransRecipientInfoEx;
00480        /* sanity check */
00481        PORT_Assert(extra->pubKey);
00482        if (!extra->pubKey) {
00483            PORT_SetError(SEC_ERROR_INVALID_ARGS);
00484            return SECFailure;
00485        }
00486        spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
00487        certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
00488     } else {
00489        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00490        return SECFailure;
00491     }
00492 
00493     /* XXX set ri->recipientInfoType to the proper value here */
00494     /* or should we look if it's been set already ? */
00495 
00496     certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
00497     switch (certalgtag) {
00498     case SEC_OID_PKCS1_RSA_ENCRYPTION:
00499        /* wrap the symkey */
00500        if (cert) {
00501            rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, 
00502                                 &ri->ri.keyTransRecipientInfo.encKey);
00503            if (rv != SECSuccess)
00504               break;
00505        } else if (usesSubjKeyID) {
00506            PORT_Assert(extra != NULL);
00507            rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
00508                                 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
00509            if (rv != SECSuccess)
00510               break;
00511        }
00512 
00513        rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
00514        break;
00515     case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
00516        rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
00517        if (rek == NULL) {
00518            rv = SECFailure;
00519            break;
00520        }
00521 
00522        oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
00523        PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
00524 
00525        /* see RFC2630 12.3.1.1 */
00526        if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
00527                                 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
00528            rv = SECFailure;
00529            break;
00530        }
00531 
00532        /* this will generate a key pair, compute the shared secret, */
00533        /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
00534        /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
00535        rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,
00536                                    &rek->encKey,
00537                                    &ri->ri.keyAgreeRecipientInfo.ukm,
00538                                    &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
00539                                    &oiok->id.originatorPublicKey.publicKey);
00540 
00541        break;
00542     default:
00543        /* other algorithms not supported yet */
00544        /* NOTE that we do not support any KEK algorithm */
00545        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
00546        rv = SECFailure;
00547        break;
00548     }
00549     if (freeSpki)
00550        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
00551 
00552     return rv;
00553 }
00554 
00555 PK11SymKey *
00556 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, 
00557        CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
00558 {
00559     PK11SymKey *bulkkey = NULL;
00560     SECAlgorithmID *encalg;
00561     SECOidTag encalgtag;
00562     SECItem *enckey;
00563     int error;
00564 
00565     ri->cert = CERT_DupCertificate(cert);
00566               /* mark the recipientInfo so we can find it later */
00567 
00568     switch (ri->recipientInfoType) {
00569     case NSSCMSRecipientInfoID_KeyTrans:
00570        encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
00571        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
00572        enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
00573        switch (encalgtag) {
00574        case SEC_OID_PKCS1_RSA_ENCRYPTION:
00575            /* RSA encryption algorithm: */
00576            /* get the symmetric (bulk) key by unwrapping it using our private key */
00577            bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
00578            break;
00579        case SEC_OID_NETSCAPE_SMIME_KEA:
00580            /* FORTEZZA key exchange algorithm */
00581            /* the supplemental data is in the parameters of encalg */
00582            bulkkey = NSS_CMSUtil_DecryptSymKey_MISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
00583            break;
00584        default:
00585            error = SEC_ERROR_UNSUPPORTED_KEYALG;
00586            goto loser;
00587        }
00588        break;
00589     case NSSCMSRecipientInfoID_KeyAgree:
00590        encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
00591        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
00592        enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
00593        switch (encalgtag) {
00594        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
00595            /* Diffie-Helman key exchange */
00596            /* XXX not yet implemented */
00597            /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
00598            /* we support ephemeral-static DH only, so if the recipientinfo */
00599            /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
00600            /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
00601            /* content encryption key using a Unwrap op */
00602            /* the derive operation has to generate the key using the algorithm in RFC2631 */
00603            error = SEC_ERROR_UNSUPPORTED_KEYALG;
00604            break;
00605        default:
00606            error = SEC_ERROR_UNSUPPORTED_KEYALG;
00607            goto loser;
00608        }
00609        break;
00610     case NSSCMSRecipientInfoID_KEK:
00611        encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
00612        encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
00613        enckey = &(ri->ri.kekRecipientInfo.encKey);
00614        /* not supported yet */
00615        error = SEC_ERROR_UNSUPPORTED_KEYALG;
00616        goto loser;
00617        break;
00618     }
00619     /* XXXX continue here */
00620     return bulkkey;
00621 
00622 loser:
00623     return NULL;
00624 }
00625 
00626 SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
00627                                              CERTCertificate** retcert,
00628                                              SECKEYPrivateKey** retkey)
00629 {
00630     CERTCertificate* cert = NULL;
00631     NSSCMSRecipient** recipients = NULL;
00632     NSSCMSRecipientInfo* recipientInfos[2];
00633     SECStatus rv = SECSuccess;
00634     SECKEYPrivateKey* key = NULL;
00635 
00636     if (!ri)
00637         return SECFailure;
00638     
00639     if (!retcert && !retkey) {
00640         /* nothing requested, nothing found, success */
00641         return SECSuccess;
00642     }
00643 
00644     if (retcert) {
00645         *retcert = NULL;
00646     }
00647     if (retkey) {
00648         *retkey = NULL;
00649     }
00650 
00651     if (ri->cert) {
00652         cert = CERT_DupCertificate(ri->cert);
00653         if (!cert) {
00654             rv = SECFailure;
00655         }
00656     }
00657     if (SECSuccess == rv && !cert) {
00658         /* we don't have the cert, we have to look for it */
00659         /* first build an NSS_CMSRecipient */
00660         recipientInfos[0] = ri;
00661         recipientInfos[1] = NULL;
00662 
00663         recipients = nss_cms_recipient_list_create(recipientInfos);
00664         if (recipients) {
00665             /* now look for the cert and key */
00666             if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
00667                 ri->cmsg->pwfn_arg)) {
00668                 cert = CERT_DupCertificate(recipients[0]->cert);
00669                 key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
00670             } else {
00671                 rv = SECFailure;
00672             }
00673 
00674             nss_cms_recipient_list_destroy(recipients);
00675         }
00676         else {
00677             rv = SECFailure;
00678         }            
00679     } else if (SECSuccess == rv && cert && retkey) {
00680         /* we have the cert, we just need the key now */
00681         key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
00682     }
00683     if (retcert) {
00684         *retcert = cert;
00685     } else {
00686         if (cert) {
00687             CERT_DestroyCertificate(cert);
00688         }
00689     }
00690     if (retkey) {
00691         *retkey = key;
00692     } else {
00693         if (key) {
00694             SECKEY_DestroyPrivateKey(key);
00695         }
00696     }
00697 
00698     return rv;
00699 }
00700 
00701 SECStatus NSS_CMSRecipientInfo_Encode(PRArenaPool* poolp,
00702                                       const NSSCMSRecipientInfo *src,
00703                                       SECItem* returned)
00704 {
00705     extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
00706     SECStatus rv = SECFailure;
00707     if (!src || !returned) {
00708         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00709     } else if (SEC_ASN1EncodeItem(poolp, returned, src,
00710         NSSCMSRecipientInfoTemplate))   {
00711         rv = SECSuccess;
00712     }
00713     return rv;
00714 }