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