Wed, 31 Dec 2014 06:09:35 +0100
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 }