Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / smime / cmsrecinfo.c
blob47fbc093efa6edf35f504ee95686ba68e744635e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * CMS recipientInfo methods.
40 * $Id: cmsrecinfo.c,v 1.19 2006/07/19 00:36:38 nelson%bolyard.com Exp $
43 #include "cmslocal.h"
45 #include "cert.h"
46 #include "key.h"
47 #include "secasn1.h"
48 #include "secitem.h"
49 #include "secoid.h"
50 #include "pk11func.h"
51 #include "secerr.h"
53 PRBool
54 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
56 if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
57 NSSCMSRecipientIdentifier *rid;
58 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
59 if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
60 return PR_TRUE;
63 return PR_FALSE;
67 * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
68 * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
69 * been exported, and we would have added an ordinary enum to handle this
70 * check. Unfortunatly wo don't have that luxury so we are overloading the
71 * contentTypeTag field. NO code should every try to interpret this content tag
72 * as a real OID tag, or use any fields other than pwfn_arg or poolp of this
73 * CMSMessage for that matter */
74 static const SECOidData fakeContent;
75 NSSCMSRecipientInfo *
76 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
77 NSSCMSRecipientIDSelector type,
78 CERTCertificate *cert,
79 SECKEYPublicKey *pubKey,
80 SECItem *subjKeyID,
81 void* pwfn_arg,
82 SECItem* DERinput)
84 NSSCMSRecipientInfo *ri;
85 void *mark;
86 SECOidTag certalgtag;
87 SECStatus rv = SECSuccess;
88 NSSCMSRecipientEncryptedKey *rek;
89 NSSCMSOriginatorIdentifierOrKey *oiok;
90 unsigned long version;
91 SECItem *dummy;
92 PLArenaPool *poolp;
93 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
94 NSSCMSRecipientIdentifier *rid;
95 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
97 if (!cmsg) {
98 /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
99 * and a private arena pool */
100 cmsg = NSS_CMSMessage_Create(NULL);
101 cmsg->pwfn_arg = pwfn_arg;
102 /* mark it as a special cms message */
103 cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent;
106 poolp = cmsg->poolp;
108 mark = PORT_ArenaMark(poolp);
110 ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
111 if (ri == NULL)
112 goto loser;
114 ri->cmsg = cmsg;
116 if (DERinput) {
117 /* decode everything from DER */
118 SECItem newinput;
119 SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
120 if (SECSuccess != rv)
121 goto loser;
122 rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
123 if (SECSuccess != rv)
124 goto loser;
127 switch (type) {
128 case NSSCMSRecipientID_IssuerSN:
130 ri->cert = CERT_DupCertificate(cert);
131 if (NULL == ri->cert)
132 goto loser;
133 spki = &(cert->subjectPublicKeyInfo);
134 break;
137 case NSSCMSRecipientID_SubjectKeyID:
139 PORT_Assert(pubKey);
140 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
141 break;
144 case NSSCMSRecipientID_BrandNew:
145 goto done;
146 break;
148 default:
149 /* unkown type */
150 goto loser;
151 break;
154 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
156 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
157 switch (certalgtag) {
158 case SEC_OID_PKCS1_RSA_ENCRYPTION:
159 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
160 rid->identifierType = type;
161 if (type == NSSCMSRecipientID_IssuerSN) {
162 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
163 if (rid->id.issuerAndSN == NULL) {
164 break;
166 } else if (type == NSSCMSRecipientID_SubjectKeyID){
167 NSSCMSKeyTransRecipientInfoEx *riExtra;
169 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
170 if (rid->id.subjectKeyID == NULL) {
171 rv = SECFailure;
172 PORT_SetError(SEC_ERROR_NO_MEMORY);
173 break;
175 SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
176 if (rid->id.subjectKeyID->data == NULL) {
177 rv = SECFailure;
178 PORT_SetError(SEC_ERROR_NO_MEMORY);
179 break;
181 riExtra = &ri->ri.keyTransRecipientInfoEx;
182 riExtra->version = 0;
183 riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
184 if (riExtra->pubKey == NULL) {
185 rv = SECFailure;
186 PORT_SetError(SEC_ERROR_NO_MEMORY);
187 break;
189 } else {
190 PORT_SetError(SEC_ERROR_INVALID_ARGS);
191 rv = SECFailure;
193 break;
194 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
195 PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
196 if (type != NSSCMSRecipientID_IssuerSN) {
197 rv = SECFailure;
198 break;
200 /* a key agreement op */
201 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
203 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
204 rv = SECFailure;
205 break;
207 /* we do not support the case where multiple recipients
208 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
209 * in this case, we would need to walk all the recipientInfos, take the
210 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
211 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
213 /* only epheremal-static Diffie-Hellman is supported for now
214 * this is the only form of key agreement that provides potential anonymity
215 * of the sender, plus we do not have to include certs in the message */
217 /* force single recipientEncryptedKey for now */
218 if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
219 rv = SECFailure;
220 break;
223 /* hardcoded IssuerSN choice for now */
224 rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
225 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
226 rv = SECFailure;
227 break;
230 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
232 /* see RFC2630 12.3.1.1 */
233 oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
235 rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
236 (void *)rek);
238 break;
239 default:
240 /* other algorithms not supported yet */
241 /* NOTE that we do not support any KEK algorithm */
242 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
243 rv = SECFailure;
244 break;
247 if (rv == SECFailure)
248 goto loser;
250 /* set version */
251 switch (ri->recipientInfoType) {
252 case NSSCMSRecipientInfoID_KeyTrans:
253 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
254 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
255 else
256 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
257 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
258 if (dummy == NULL)
259 goto loser;
260 break;
261 case NSSCMSRecipientInfoID_KeyAgree:
262 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
263 NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
264 if (dummy == NULL)
265 goto loser;
266 break;
267 case NSSCMSRecipientInfoID_KEK:
268 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
269 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
270 NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
271 if (dummy == NULL)
272 goto loser;
273 break;
277 done:
278 PORT_ArenaUnmark (poolp, mark);
279 if (freeSpki)
280 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
281 return ri;
283 loser:
284 if (ri && ri->cert) {
285 CERT_DestroyCertificate(ri->cert);
287 if (freeSpki) {
288 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
290 PORT_ArenaRelease (poolp, mark);
291 if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
292 NSS_CMSMessage_Destroy(cmsg);
294 return NULL;
298 * NSS_CMSRecipientInfo_Create - create a recipientinfo
300 * we currently do not create KeyAgreement recipientinfos with multiple
301 * recipientEncryptedKeys the certificate is supposed to have been
302 * verified by the caller
304 NSSCMSRecipientInfo *
305 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
307 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert,
308 NULL, NULL, NULL, NULL);
311 NSSCMSRecipientInfo *
312 NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg)
314 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
315 NULL, NULL, pwfn_arg, NULL);
318 NSSCMSRecipientInfo *
319 NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg)
321 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
322 NULL, NULL, pwfn_arg, input);
326 NSSCMSRecipientInfo *
327 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
328 SECItem *subjKeyID,
329 SECKEYPublicKey *pubKey)
331 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID,
332 NULL, pubKey, subjKeyID, NULL, NULL);
335 NSSCMSRecipientInfo *
336 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
337 CERTCertificate *cert)
339 SECKEYPublicKey *pubKey = NULL;
340 SECItem subjKeyID = {siBuffer, NULL, 0};
341 NSSCMSRecipientInfo *retVal = NULL;
343 if (!cmsg || !cert) {
344 return NULL;
346 pubKey = CERT_ExtractPublicKey(cert);
347 if (!pubKey) {
348 goto done;
350 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
351 subjKeyID.data == NULL) {
352 goto done;
354 retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
355 done:
356 if (pubKey)
357 SECKEY_DestroyPublicKey(pubKey);
359 if (subjKeyID.data)
360 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
362 return retVal;
365 void
366 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
368 if (!ri) {
369 return;
371 /* version was allocated on the pool, so no need to destroy it */
372 /* issuerAndSN was allocated on the pool, so no need to destroy it */
373 if (ri->cert != NULL)
374 CERT_DestroyCertificate(ri->cert);
376 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
377 NSSCMSKeyTransRecipientInfoEx *extra;
378 extra = &ri->ri.keyTransRecipientInfoEx;
379 if (extra->pubKey)
380 SECKEY_DestroyPublicKey(extra->pubKey);
382 if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
383 NSS_CMSMessage_Destroy(ri->cmsg);
386 /* we're done. */
390 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
392 unsigned long version;
393 SECItem *versionitem = NULL;
395 switch (ri->recipientInfoType) {
396 case NSSCMSRecipientInfoID_KeyTrans:
397 /* ignore subIndex */
398 versionitem = &(ri->ri.keyTransRecipientInfo.version);
399 break;
400 case NSSCMSRecipientInfoID_KEK:
401 /* ignore subIndex */
402 versionitem = &(ri->ri.kekRecipientInfo.version);
403 break;
404 case NSSCMSRecipientInfoID_KeyAgree:
405 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
406 break;
409 PORT_Assert(versionitem);
410 if (versionitem == NULL)
411 return 0;
413 /* always take apart the SECItem */
414 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
415 return 0;
416 else
417 return (int)version;
420 SECItem *
421 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
423 SECItem *enckey = NULL;
425 switch (ri->recipientInfoType) {
426 case NSSCMSRecipientInfoID_KeyTrans:
427 /* ignore subIndex */
428 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
429 break;
430 case NSSCMSRecipientInfoID_KEK:
431 /* ignore subIndex */
432 enckey = &(ri->ri.kekRecipientInfo.encKey);
433 break;
434 case NSSCMSRecipientInfoID_KeyAgree:
435 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
436 break;
438 return enckey;
442 SECOidTag
443 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
445 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
447 switch (ri->recipientInfoType) {
448 case NSSCMSRecipientInfoID_KeyTrans:
449 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
450 break;
451 case NSSCMSRecipientInfoID_KeyAgree:
452 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
453 break;
454 case NSSCMSRecipientInfoID_KEK:
455 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
456 break;
458 return encalgtag;
461 SECStatus
462 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
463 SECOidTag bulkalgtag)
465 CERTCertificate *cert;
466 SECOidTag certalgtag;
467 SECStatus rv = SECSuccess;
468 SECItem *params = NULL;
469 NSSCMSRecipientEncryptedKey *rek;
470 NSSCMSOriginatorIdentifierOrKey *oiok;
471 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
472 PLArenaPool *poolp;
473 NSSCMSKeyTransRecipientInfoEx *extra = NULL;
474 PRBool usesSubjKeyID;
476 poolp = ri->cmsg->poolp;
477 cert = ri->cert;
478 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
479 if (cert) {
480 spki = &cert->subjectPublicKeyInfo;
481 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
482 } else if (usesSubjKeyID) {
483 extra = &ri->ri.keyTransRecipientInfoEx;
484 /* sanity check */
485 PORT_Assert(extra->pubKey);
486 if (!extra->pubKey) {
487 PORT_SetError(SEC_ERROR_INVALID_ARGS);
488 return SECFailure;
490 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
491 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
492 } else {
493 PORT_SetError(SEC_ERROR_INVALID_ARGS);
494 return SECFailure;
497 /* XXX set ri->recipientInfoType to the proper value here */
498 /* or should we look if it's been set already ? */
500 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
501 switch (certalgtag) {
502 case SEC_OID_PKCS1_RSA_ENCRYPTION:
503 /* wrap the symkey */
504 if (cert) {
505 rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey,
506 &ri->ri.keyTransRecipientInfo.encKey);
507 if (rv != SECSuccess)
508 break;
509 } else if (usesSubjKeyID) {
510 PORT_Assert(extra != NULL);
511 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
512 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
513 if (rv != SECSuccess)
514 break;
517 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
518 break;
519 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
520 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
521 if (rek == NULL) {
522 rv = SECFailure;
523 break;
526 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
527 PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
529 /* see RFC2630 12.3.1.1 */
530 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
531 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
532 rv = SECFailure;
533 break;
536 /* this will generate a key pair, compute the shared secret, */
537 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
538 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
539 rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,
540 &rek->encKey,
541 &ri->ri.keyAgreeRecipientInfo.ukm,
542 &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
543 &oiok->id.originatorPublicKey.publicKey);
545 break;
546 default:
547 /* other algorithms not supported yet */
548 /* NOTE that we do not support any KEK algorithm */
549 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
550 rv = SECFailure;
551 break;
553 if (freeSpki)
554 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
556 return rv;
559 PK11SymKey *
560 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
561 CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
563 PK11SymKey *bulkkey = NULL;
564 SECAlgorithmID *encalg;
565 SECOidTag encalgtag;
566 SECItem *enckey;
567 int error;
569 ri->cert = CERT_DupCertificate(cert);
570 /* mark the recipientInfo so we can find it later */
572 switch (ri->recipientInfoType) {
573 case NSSCMSRecipientInfoID_KeyTrans:
574 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
575 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
576 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
577 switch (encalgtag) {
578 case SEC_OID_PKCS1_RSA_ENCRYPTION:
579 /* RSA encryption algorithm: */
580 /* get the symmetric (bulk) key by unwrapping it using our private key */
581 bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
582 break;
583 case SEC_OID_NETSCAPE_SMIME_KEA:
584 /* FORTEZZA key exchange algorithm */
585 /* the supplemental data is in the parameters of encalg */
586 bulkkey = NSS_CMSUtil_DecryptSymKey_MISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
587 break;
588 default:
589 error = SEC_ERROR_UNSUPPORTED_KEYALG;
590 goto loser;
592 break;
593 case NSSCMSRecipientInfoID_KeyAgree:
594 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
595 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
596 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
597 switch (encalgtag) {
598 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
599 /* Diffie-Helman key exchange */
600 /* XXX not yet implemented */
601 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
602 /* we support ephemeral-static DH only, so if the recipientinfo */
603 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
604 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
605 /* content encryption key using a Unwrap op */
606 /* the derive operation has to generate the key using the algorithm in RFC2631 */
607 error = SEC_ERROR_UNSUPPORTED_KEYALG;
608 break;
609 default:
610 error = SEC_ERROR_UNSUPPORTED_KEYALG;
611 goto loser;
613 break;
614 case NSSCMSRecipientInfoID_KEK:
615 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
616 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
617 enckey = &(ri->ri.kekRecipientInfo.encKey);
618 /* not supported yet */
619 error = SEC_ERROR_UNSUPPORTED_KEYALG;
620 goto loser;
621 break;
623 /* XXXX continue here */
624 return bulkkey;
626 loser:
627 return NULL;
630 SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
631 CERTCertificate** retcert,
632 SECKEYPrivateKey** retkey)
634 CERTCertificate* cert = NULL;
635 NSSCMSRecipient** recipients = NULL;
636 NSSCMSRecipientInfo* recipientInfos[2];
637 SECStatus rv = SECSuccess;
638 SECKEYPrivateKey* key = NULL;
640 if (!ri)
641 return SECFailure;
643 if (!retcert && !retkey) {
644 /* nothing requested, nothing found, success */
645 return SECSuccess;
648 if (retcert) {
649 *retcert = NULL;
651 if (retkey) {
652 *retkey = NULL;
655 if (ri->cert) {
656 cert = CERT_DupCertificate(ri->cert);
657 if (!cert) {
658 rv = SECFailure;
661 if (SECSuccess == rv && !cert) {
662 /* we don't have the cert, we have to look for it */
663 /* first build an NSS_CMSRecipient */
664 recipientInfos[0] = ri;
665 recipientInfos[1] = NULL;
667 recipients = nss_cms_recipient_list_create(recipientInfos);
668 if (recipients) {
669 /* now look for the cert and key */
670 if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
671 ri->cmsg->pwfn_arg)) {
672 cert = CERT_DupCertificate(recipients[0]->cert);
673 key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
674 } else {
675 rv = SECFailure;
678 nss_cms_recipient_list_destroy(recipients);
680 else {
681 rv = SECFailure;
683 } else if (SECSuccess == rv && cert && retkey) {
684 /* we have the cert, we just need the key now */
685 key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
687 if (retcert) {
688 *retcert = cert;
689 } else {
690 if (cert) {
691 CERT_DestroyCertificate(cert);
694 if (retkey) {
695 *retkey = key;
696 } else {
697 if (key) {
698 SECKEY_DestroyPrivateKey(key);
702 return rv;
705 SECStatus NSS_CMSRecipientInfo_Encode(PRArenaPool* poolp,
706 const NSSCMSRecipientInfo *src,
707 SECItem* returned)
709 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
710 SECStatus rv = SECFailure;
711 if (!src || !returned) {
712 PORT_SetError(SEC_ERROR_INVALID_ARGS);
713 } else if (SEC_ASN1EncodeItem(poolp, returned, src,
714 NSSCMSRecipientInfoTemplate)) {
715 rv = SECSuccess;
717 return rv;