]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsrecinfo.c
Security-57031.20.26.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmsrecinfo.c
1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34 /*
35 * CMS recipientInfo methods.
36 */
37
38 #include "cmslocal.h"
39
40 #include "cert.h"
41 #include "SecAsn1Item.h"
42 #include "secoid.h"
43
44 #include <security_asn1/secasn1.h>
45 #include <security_asn1/secerr.h>
46 #include <security_asn1/secport.h>
47
48 #include <Security/SecKeyPriv.h>
49 #include <Security/SecCertificatePriv.h>
50 #include <Security/SecCertificateInternal.h>
51
52 #include "SecCmsRecipientInfo.h"
53
54 static Boolean
55 nss_cmsrecipientinfo_usessubjectkeyid(SecCmsRecipientInfoRef ri)
56 {
57 if (ri->recipientInfoType == SecCmsRecipientInfoIDKeyTrans) {
58 SecCmsRecipientIdentifier *rid;
59 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
60 if (rid->identifierType == SecCmsRecipientIDSubjectKeyID) {
61 return PR_TRUE;
62 }
63 }
64 return PR_FALSE;
65 }
66
67
68 static SecCmsRecipientInfoRef
69 nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelector type,
70 SecCertificateRef cert, SecPublicKeyRef pubKey,
71 const SecAsn1Item *subjKeyID)
72 {
73 SecCmsRecipientInfoRef ri;
74 void *mark;
75 SECOidTag certalgtag;
76 OSStatus rv = SECSuccess;
77 SecCmsRecipientEncryptedKey *rek;
78 SecCmsOriginatorIdentifierOrKey *oiok;
79 unsigned long version;
80 SecAsn1Item * dummy;
81 PLArenaPool *poolp;
82 const SECAlgorithmID *algid;
83 SECAlgorithmID freeAlgID;
84
85 SecCmsRecipientIdentifier *rid;
86
87 poolp = envd->contentInfo.cmsg->poolp;
88
89 mark = PORT_ArenaMark(poolp);
90
91 ri = (SecCmsRecipientInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientInfo));
92 if (ri == NULL)
93 goto loser;
94
95 ri->envelopedData = envd;
96
97 #if USE_CDSA_CRYPTO
98 if (type == SecCmsRecipientIDIssuerSN)
99 {
100 rv = SecCertificateGetAlgorithmID(cert,&algid);
101 } else {
102 PORT_Assert(pubKey);
103 rv = SecKeyGetAlgorithmID(pubKey,&algid);
104 }
105 #else
106 ri->cert = CERT_DupCertificate(cert);
107 if (ri->cert == NULL)
108 goto loser;
109
110 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
111 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
112 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
113 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
114 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
115 algid = &freeAlgID;
116 #endif
117
118 certalgtag = SECOID_GetAlgorithmTag(algid);
119
120 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
121 switch (certalgtag) {
122 case SEC_OID_PKCS1_RSA_ENCRYPTION:
123 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans;
124 rid->identifierType = type;
125 if (type == SecCmsRecipientIDIssuerSN) {
126 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
127 if (rid->id.issuerAndSN == NULL) {
128 break;
129 }
130 } else if (type == SecCmsRecipientIDSubjectKeyID){
131
132 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item);
133 if (rid->id.subjectKeyID == NULL) {
134 rv = SECFailure;
135 PORT_SetError(SEC_ERROR_NO_MEMORY);
136 break;
137 }
138 SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
139 if (rid->id.subjectKeyID->Data == NULL) {
140 rv = SECFailure;
141 PORT_SetError(SEC_ERROR_NO_MEMORY);
142 break;
143 }
144
145 #if 0
146 SecCmsKeyTransRecipientInfoEx *riExtra;
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 #endif
156 } else {
157 PORT_SetError(SEC_ERROR_INVALID_ARGS);
158 rv = SECFailure;
159 }
160 break;
161 case SEC_OID_MISSI_KEA_DSS_OLD:
162 case SEC_OID_MISSI_KEA_DSS:
163 case SEC_OID_MISSI_KEA:
164 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
165 if (type == SecCmsRecipientIDSubjectKeyID) {
166 rv = SECFailure;
167 break;
168 }
169 /* backward compatibility - this is not really a keytrans operation */
170 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans;
171 /* hardcoded issuerSN choice for now */
172 ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN;
173 ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
174 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
175 rv = SECFailure;
176 break;
177 }
178 break;
179 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
180 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
181 if (type == SecCmsRecipientIDSubjectKeyID) {
182 rv = SECFailure;
183 break;
184 }
185 /* a key agreement op */
186 ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree;
187
188 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
189 rv = SECFailure;
190 break;
191 }
192 /* we do not support the case where multiple recipients
193 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
194 * in this case, we would need to walk all the recipientInfos, take the
195 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
196 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
197
198 /* only epheremal-static Diffie-Hellman is supported for now
199 * this is the only form of key agreement that provides potential anonymity
200 * of the sender, plus we do not have to include certs in the message */
201
202 /* force single recipientEncryptedKey for now */
203 if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) {
204 rv = SECFailure;
205 break;
206 }
207
208 /* hardcoded IssuerSN choice for now */
209 rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN;
210 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
211 rv = SECFailure;
212 break;
213 }
214
215 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
216
217 /* see RFC2630 12.3.1.1 */
218 oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey;
219
220 rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
221 (void *)rek);
222
223 break;
224 default:
225 /* other algorithms not supported yet */
226 /* NOTE that we do not support any KEK algorithm */
227 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
228 rv = SECFailure;
229 break;
230 }
231
232 if (rv == SECFailure)
233 goto loser;
234
235 /* set version */
236 switch (ri->recipientInfoType) {
237 case SecCmsRecipientInfoIDKeyTrans:
238 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN)
239 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
240 else
241 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
242 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
243 if (dummy == NULL)
244 goto loser;
245 break;
246 case SecCmsRecipientInfoIDKeyAgree:
247 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
248 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
249 if (dummy == NULL)
250 goto loser;
251 break;
252 case SecCmsRecipientInfoIDKEK:
253 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
254 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
255 SEC_CMS_KEK_RECIPIENT_INFO_VERSION);
256 if (dummy == NULL)
257 goto loser;
258 break;
259
260 }
261
262 if (SecCmsEnvelopedDataAddRecipient(envd, ri))
263 goto loser;
264
265 PORT_ArenaUnmark (poolp, mark);
266 #if 0
267 if (freeSpki)
268 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
269 #endif
270 return ri;
271
272 loser:
273 #if 0
274 if (freeSpki)
275 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
276 #endif
277 PORT_ArenaRelease (poolp, mark);
278 return NULL;
279 }
280
281 /*
282 * SecCmsRecipientInfoCreate - create a recipientinfo
283 *
284 * we currently do not create KeyAgreement recipientinfos with multiple
285 * recipientEncryptedKeys the certificate is supposed to have been
286 * verified by the caller
287 */
288 SecCmsRecipientInfoRef
289 SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert)
290 {
291 #if 0
292 SecCmsRecipientInfoRef info = SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(envd, cert);
293
294 if (info)
295 return info;
296 else
297 #endif
298 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDIssuerSN, cert,
299 NULL, NULL);
300 }
301
302 SecCmsRecipientInfoRef
303 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
304 const SecAsn1Item * subjKeyID,
305 SecPublicKeyRef pubKey)
306 {
307 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
308 NULL, pubKey, subjKeyID);
309 }
310
311 #if USE_CDSA_CRYPTO
312 SecCmsRecipientInfoRef
313 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
314 SecCertificateRef cert)
315 {
316 SecPublicKeyRef pubKey = NULL;
317 SecAsn1Item subjKeyID = {0, NULL};
318 SecCmsRecipientInfoRef retVal = NULL;
319
320 if (!envd || !cert) {
321 return NULL;
322 }
323 pubKey = CERT_ExtractPublicKey(cert);
324 if (!pubKey) {
325 goto done;
326 }
327 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
328 subjKeyID.Data == NULL) {
329 goto done;
330 }
331 retVal = SecCmsRecipientInfoCreateWithSubjKeyID(envd, &subjKeyID, pubKey);
332 done:
333 if (pubKey)
334 SECKEY_DestroyPublicKey(pubKey);
335
336 if (subjKeyID.Data)
337 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
338
339 return retVal;
340 }
341 #else
342 SecCmsRecipientInfoRef
343 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
344 SecCertificateRef cert)
345 {
346 SecPublicKeyRef pubKey = NULL;
347 SecAsn1Item subjKeyID = {0, NULL};
348 SecCmsRecipientInfoRef retVal = NULL;
349 CFDataRef subjectKeyIDData = NULL;
350
351 if (!envd || !cert) {
352 return NULL;
353 }
354 subjectKeyIDData = SecCertificateGetSubjectKeyID(cert);
355 if (!subjectKeyIDData)
356 goto done;
357 subjKeyID.Length =
358 CFDataGetLength(subjectKeyIDData);
359 subjKeyID.Data = (uint8_t *)CFDataGetBytePtr(subjectKeyIDData);
360 retVal = nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
361 cert, pubKey, &subjKeyID);
362
363 done:
364
365 return retVal;
366 }
367 #endif
368
369 void
370 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri)
371 {
372 /* version was allocated on the pool, so no need to destroy it */
373 /* issuerAndSN was allocated on the pool, so no need to destroy it */
374 if (ri->cert != NULL)
375 CERT_DestroyCertificate(ri->cert);
376
377 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
378 SecCmsKeyTransRecipientInfoEx *extra;
379 extra = &ri->ri.keyTransRecipientInfoEx;
380 if (extra->pubKey)
381 SECKEY_DestroyPublicKey(extra->pubKey);
382 }
383
384 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
385 /* we're done. */
386 }
387
388 int
389 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri)
390 {
391 unsigned long version;
392 SecAsn1Item * versionitem = NULL;
393
394 switch (ri->recipientInfoType) {
395 case SecCmsRecipientInfoIDKeyTrans:
396 /* ignore subIndex */
397 versionitem = &(ri->ri.keyTransRecipientInfo.version);
398 break;
399 case SecCmsRecipientInfoIDKEK:
400 /* ignore subIndex */
401 versionitem = &(ri->ri.kekRecipientInfo.version);
402 break;
403 case SecCmsRecipientInfoIDKeyAgree:
404 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
405 break;
406 }
407
408 PORT_Assert(versionitem);
409 if (versionitem == NULL)
410 return 0;
411
412 /* always take apart the SecAsn1Item */
413 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
414 return 0;
415 else
416 return (int)version;
417 }
418
419 SecAsn1Item *
420 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri, int subIndex)
421 {
422 SecAsn1Item * enckey = NULL;
423
424 switch (ri->recipientInfoType) {
425 case SecCmsRecipientInfoIDKeyTrans:
426 /* ignore subIndex */
427 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
428 break;
429 case SecCmsRecipientInfoIDKEK:
430 /* ignore subIndex */
431 enckey = &(ri->ri.kekRecipientInfo.encKey);
432 break;
433 case SecCmsRecipientInfoIDKeyAgree:
434 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
435 break;
436 }
437 return enckey;
438 }
439
440
441 SECOidTag
442 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri)
443 {
444 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
445
446 switch (ri->recipientInfoType) {
447 case SecCmsRecipientInfoIDKeyTrans:
448 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
449 break;
450 case SecCmsRecipientInfoIDKeyAgree:
451 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
452 break;
453 case SecCmsRecipientInfoIDKEK:
454 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
455 break;
456 }
457 return encalgtag;
458 }
459
460 OSStatus
461 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey,
462 SECOidTag bulkalgtag)
463 {
464 SecCertificateRef cert;
465 SECOidTag certalgtag;
466 OSStatus rv = SECSuccess;
467 #if 0
468 SecAsn1Item * params = NULL;
469 SecCmsRecipientEncryptedKey *rek;
470 SecCmsOriginatorIdentifierOrKey *oiok;
471 #endif /* 0 */
472 const SECAlgorithmID *algid;
473 PLArenaPool *poolp;
474 SecCmsKeyTransRecipientInfoEx *extra = NULL;
475 Boolean usesSubjKeyID;
476
477 poolp = ri->envelopedData->contentInfo.cmsg->poolp;
478 cert = ri->cert;
479 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
480 if (cert) {
481 #if USE_CDSA_CRYPTO
482 rv = SecCertificateGetAlgorithmID(cert,&algid);
483 if (rv)
484 return SECFailure;
485 #else
486 SECAlgorithmID freeAlgID;
487 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
488 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
489 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
490 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
491 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
492 algid = &freeAlgID;
493 #endif
494 } else if (usesSubjKeyID) {
495 extra = &ri->ri.keyTransRecipientInfoEx;
496 /* sanity check */
497 PORT_Assert(extra->pubKey);
498 if (!extra->pubKey) {
499 PORT_SetError(SEC_ERROR_INVALID_ARGS);
500 return SECFailure;
501 }
502 #if USE_CDSA_CRYPTO
503 rv = SecKeyGetAlgorithmID(extra->pubKey,&algid);
504 if (rv)
505 #endif
506 return SECFailure;
507 certalgtag = SECOID_GetAlgorithmTag(algid);
508 } else {
509 PORT_SetError(SEC_ERROR_INVALID_ARGS);
510 return SECFailure;
511 }
512
513 /* XXX set ri->recipientInfoType to the proper value here */
514 /* or should we look if it's been set already ? */
515
516 certalgtag = SECOID_GetAlgorithmTag(algid);
517 switch (certalgtag) {
518 case SEC_OID_PKCS1_RSA_ENCRYPTION:
519 /* wrap the symkey */
520 if (cert) {
521 rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey,
522 &ri->ri.keyTransRecipientInfo.encKey);
523 if (rv != SECSuccess)
524 break;
525 } else if (usesSubjKeyID) {
526 PORT_Assert(extra != NULL);
527 rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey,
528 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
529 if (rv != SECSuccess)
530 break;
531 }
532
533 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
534 break;
535 #if 0
536 case SEC_OID_MISSI_KEA_DSS_OLD:
537 case SEC_OID_MISSI_KEA_DSS:
538 case SEC_OID_MISSI_KEA:
539 rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey,
540 bulkalgtag,
541 &ri->ri.keyTransRecipientInfo.encKey,
542 &params, ri->cmsg->pwfn_arg);
543 if (rv != SECSuccess)
544 break;
545
546 /* here, we DO need to pass the params to the wrap function because, with
547 * RSA, there is no funny stuff going on with generation of IV vectors or so */
548 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);
549 break;
550 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
551 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
552 if (rek == NULL) {
553 rv = SECFailure;
554 break;
555 }
556
557 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
558 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);
559
560 /* see RFC2630 12.3.1.1 */
561 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
562 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
563 rv = SECFailure;
564 break;
565 }
566
567 /* this will generate a key pair, compute the shared secret, */
568 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
569 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
570 rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey,
571 &rek->encKey,
572 &ri->ri.keyAgreeRecipientInfo.ukm,
573 &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
574 &oiok->id.originatorPublicKey.publicKey);
575
576 break;
577 #endif /* 0 */
578 default:
579 /* other algorithms not supported yet */
580 /* NOTE that we do not support any KEK algorithm */
581 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
582 rv = SECFailure;
583 break;
584 }
585 #if 0
586 if (freeSpki)
587 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
588 #endif
589
590 return rv;
591 }
592
593 SecSymmetricKeyRef
594 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri, int subIndex,
595 SecCertificateRef cert, SecPrivateKeyRef privkey, SECOidTag bulkalgtag)
596 {
597 SecSymmetricKeyRef bulkkey = NULL;
598 SECAlgorithmID *encalg;
599 SECOidTag encalgtag;
600 SecAsn1Item * enckey;
601 int error;
602
603 ri->cert = CERT_DupCertificate(cert);
604 /* mark the recipientInfo so we can find it later */
605
606 switch (ri->recipientInfoType) {
607 case SecCmsRecipientInfoIDKeyTrans:
608 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
609 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
610 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
611 switch (encalgtag) {
612 case SEC_OID_PKCS1_RSA_ENCRYPTION:
613 /* RSA encryption algorithm: */
614 /* get the symmetric (bulk) key by unwrapping it using our private key */
615 bulkkey = SecCmsUtilDecryptSymKeyRSA(privkey, enckey, bulkalgtag);
616 break;
617 #if 0
618 case SEC_OID_NETSCAPE_SMIME_KEA:
619 /* FORTEZZA key exchange algorithm */
620 /* the supplemental data is in the parameters of encalg */
621 bulkkey = SecCmsUtilDecryptSymKeyMISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
622 break;
623 #endif /* 0 */
624 default:
625 error = SEC_ERROR_UNSUPPORTED_KEYALG;
626 goto loser;
627 }
628 break;
629 case SecCmsRecipientInfoIDKeyAgree:
630 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
631 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
632 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
633 switch (encalgtag) {
634 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
635 /* Diffie-Helman key exchange */
636 /* XXX not yet implemented */
637 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
638 /* we support ephemeral-static DH only, so if the recipientinfo */
639 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
640 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
641 /* content encryption key using a Unwrap op */
642 /* the derive operation has to generate the key using the algorithm in RFC2631 */
643 error = SEC_ERROR_UNSUPPORTED_KEYALG;
644 break;
645 default:
646 error = SEC_ERROR_UNSUPPORTED_KEYALG;
647 goto loser;
648 }
649 break;
650 case SecCmsRecipientInfoIDKEK:
651 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
652 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
653 enckey = &(ri->ri.kekRecipientInfo.encKey);
654 /* not supported yet */
655 error = SEC_ERROR_UNSUPPORTED_KEYALG;
656 goto loser;
657 break;
658 }
659 /* XXXX continue here */
660 return bulkkey;
661
662 loser:
663 return NULL;
664 }