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