]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsrecinfo.c
5c2b356d6c075fbc0f3885838ff46627397e5e47
[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 /* TODO: we might want to prefer subjkeyid */
292 #if 0
293 SecCmsRecipientInfoRef info = SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(envd, cert);
294
295 if (info)
296 return info;
297 else
298 #endif
299 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDIssuerSN, cert,
300 NULL, NULL);
301 }
302
303 SecCmsRecipientInfoRef
304 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
305 const SecAsn1Item * subjKeyID,
306 SecPublicKeyRef pubKey)
307 {
308 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
309 NULL, pubKey, subjKeyID);
310 }
311
312 #if USE_CDSA_CRYPTO
313 SecCmsRecipientInfoRef
314 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
315 SecCertificateRef cert)
316 {
317 SecPublicKeyRef pubKey = NULL;
318 SecAsn1Item subjKeyID = {0, NULL};
319 SecCmsRecipientInfoRef retVal = NULL;
320
321 if (!envd || !cert) {
322 return NULL;
323 }
324 pubKey = CERT_ExtractPublicKey(cert);
325 if (!pubKey) {
326 goto done;
327 }
328 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
329 subjKeyID.Data == NULL) {
330 goto done;
331 }
332 retVal = SecCmsRecipientInfoCreateWithSubjKeyID(envd, &subjKeyID, pubKey);
333 done:
334 if (pubKey)
335 SECKEY_DestroyPublicKey(pubKey);
336
337 if (subjKeyID.Data)
338 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
339
340 return retVal;
341 }
342 #else
343 SecCmsRecipientInfoRef
344 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
345 SecCertificateRef cert)
346 {
347 SecPublicKeyRef pubKey = NULL;
348 SecAsn1Item subjKeyID = {0, NULL};
349 SecCmsRecipientInfoRef retVal = NULL;
350 CFDataRef subjectKeyIDData = NULL;
351
352 if (!envd || !cert) {
353 return NULL;
354 }
355 subjectKeyIDData = SecCertificateGetSubjectKeyID(cert);
356 if (!subjectKeyIDData)
357 goto done;
358 subjKeyID.Length =
359 CFDataGetLength(subjectKeyIDData);
360 subjKeyID.Data = (uint8_t *)CFDataGetBytePtr(subjectKeyIDData);
361 retVal = nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
362 cert, pubKey, &subjKeyID);
363
364 done:
365
366 return retVal;
367 }
368 #endif
369
370 void
371 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri)
372 {
373 /* version was allocated on the pool, so no need to destroy it */
374 /* issuerAndSN was allocated on the pool, so no need to destroy it */
375 if (ri->cert != NULL)
376 CERT_DestroyCertificate(ri->cert);
377
378 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
379 SecCmsKeyTransRecipientInfoEx *extra;
380 extra = &ri->ri.keyTransRecipientInfoEx;
381 if (extra->pubKey)
382 SECKEY_DestroyPublicKey(extra->pubKey);
383 }
384
385 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
386 /* we're done. */
387 }
388
389 int
390 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri)
391 {
392 unsigned long version;
393 SecAsn1Item * versionitem = NULL;
394
395 switch (ri->recipientInfoType) {
396 case SecCmsRecipientInfoIDKeyTrans:
397 /* ignore subIndex */
398 versionitem = &(ri->ri.keyTransRecipientInfo.version);
399 break;
400 case SecCmsRecipientInfoIDKEK:
401 /* ignore subIndex */
402 versionitem = &(ri->ri.kekRecipientInfo.version);
403 break;
404 case SecCmsRecipientInfoIDKeyAgree:
405 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
406 break;
407 }
408
409 PORT_Assert(versionitem);
410 if (versionitem == NULL)
411 return 0;
412
413 /* always take apart the SecAsn1Item */
414 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
415 return 0;
416 else
417 return (int)version;
418 }
419
420 SecAsn1Item *
421 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri, int subIndex)
422 {
423 SecAsn1Item * enckey = NULL;
424
425 switch (ri->recipientInfoType) {
426 case SecCmsRecipientInfoIDKeyTrans:
427 /* ignore subIndex */
428 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
429 break;
430 case SecCmsRecipientInfoIDKEK:
431 /* ignore subIndex */
432 enckey = &(ri->ri.kekRecipientInfo.encKey);
433 break;
434 case SecCmsRecipientInfoIDKeyAgree:
435 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
436 break;
437 }
438 return enckey;
439 }
440
441
442 SECOidTag
443 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri)
444 {
445 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
446
447 switch (ri->recipientInfoType) {
448 case SecCmsRecipientInfoIDKeyTrans:
449 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
450 break;
451 case SecCmsRecipientInfoIDKeyAgree:
452 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
453 break;
454 case SecCmsRecipientInfoIDKEK:
455 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
456 break;
457 }
458 return encalgtag;
459 }
460
461 OSStatus
462 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey,
463 SECOidTag bulkalgtag)
464 {
465 SecCertificateRef cert;
466 SECOidTag certalgtag;
467 OSStatus rv = SECSuccess;
468 #if 0
469 SecAsn1Item * params = NULL;
470 SecCmsRecipientEncryptedKey *rek;
471 SecCmsOriginatorIdentifierOrKey *oiok;
472 #endif /* 0 */
473 const SECAlgorithmID *algid;
474 PLArenaPool *poolp;
475 SecCmsKeyTransRecipientInfoEx *extra = NULL;
476 Boolean usesSubjKeyID;
477
478 poolp = ri->envelopedData->contentInfo.cmsg->poolp;
479 cert = ri->cert;
480 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
481 if (cert) {
482 #if USE_CDSA_CRYPTO
483 rv = SecCertificateGetAlgorithmID(cert,&algid);
484 if (rv)
485 return SECFailure;
486 #else
487 SECAlgorithmID freeAlgID;
488 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
489 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
490 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
491 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
492 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
493 algid = &freeAlgID;
494 #endif
495 } else if (usesSubjKeyID) {
496 extra = &ri->ri.keyTransRecipientInfoEx;
497 /* sanity check */
498 PORT_Assert(extra->pubKey);
499 if (!extra->pubKey) {
500 PORT_SetError(SEC_ERROR_INVALID_ARGS);
501 return SECFailure;
502 }
503 #if USE_CDSA_CRYPTO
504 rv = SecKeyGetAlgorithmID(extra->pubKey,&algid);
505 if (rv)
506 #endif
507 return SECFailure;
508 certalgtag = SECOID_GetAlgorithmTag(algid);
509 } else {
510 PORT_SetError(SEC_ERROR_INVALID_ARGS);
511 return SECFailure;
512 }
513
514 /* XXX set ri->recipientInfoType to the proper value here */
515 /* or should we look if it's been set already ? */
516
517 certalgtag = SECOID_GetAlgorithmTag(algid);
518 switch (certalgtag) {
519 case SEC_OID_PKCS1_RSA_ENCRYPTION:
520 /* wrap the symkey */
521 if (cert) {
522 rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey,
523 &ri->ri.keyTransRecipientInfo.encKey);
524 if (rv != SECSuccess)
525 break;
526 } else if (usesSubjKeyID) {
527 PORT_Assert(extra != NULL);
528 rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey,
529 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
530 if (rv != SECSuccess)
531 break;
532 }
533
534 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
535 break;
536 #if 0
537 case SEC_OID_MISSI_KEA_DSS_OLD:
538 case SEC_OID_MISSI_KEA_DSS:
539 case SEC_OID_MISSI_KEA:
540 rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey,
541 bulkalgtag,
542 &ri->ri.keyTransRecipientInfo.encKey,
543 &params, ri->cmsg->pwfn_arg);
544 if (rv != SECSuccess)
545 break;
546
547 /* here, we DO need to pass the params to the wrap function because, with
548 * RSA, there is no funny stuff going on with generation of IV vectors or so */
549 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);
550 break;
551 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
552 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
553 if (rek == NULL) {
554 rv = SECFailure;
555 break;
556 }
557
558 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
559 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);
560
561 /* see RFC2630 12.3.1.1 */
562 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
563 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
564 rv = SECFailure;
565 break;
566 }
567
568 /* this will generate a key pair, compute the shared secret, */
569 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
570 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
571 rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey,
572 &rek->encKey,
573 &ri->ri.keyAgreeRecipientInfo.ukm,
574 &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
575 &oiok->id.originatorPublicKey.publicKey);
576
577 break;
578 #endif /* 0 */
579 default:
580 /* other algorithms not supported yet */
581 /* NOTE that we do not support any KEK algorithm */
582 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
583 rv = SECFailure;
584 break;
585 }
586 #if 0
587 if (freeSpki)
588 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
589 #endif
590
591 return rv;
592 }
593
594 SecSymmetricKeyRef
595 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri, int subIndex,
596 SecCertificateRef cert, SecPrivateKeyRef privkey, SECOidTag bulkalgtag)
597 {
598 SecSymmetricKeyRef bulkkey = NULL;
599 SECAlgorithmID *encalg;
600 SECOidTag encalgtag;
601 SecAsn1Item * enckey;
602 int error;
603
604 ri->cert = CERT_DupCertificate(cert);
605 /* mark the recipientInfo so we can find it later */
606
607 switch (ri->recipientInfoType) {
608 case SecCmsRecipientInfoIDKeyTrans:
609 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
610 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
611 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
612 switch (encalgtag) {
613 case SEC_OID_PKCS1_RSA_ENCRYPTION:
614 /* RSA encryption algorithm: */
615 /* get the symmetric (bulk) key by unwrapping it using our private key */
616 bulkkey = SecCmsUtilDecryptSymKeyRSA(privkey, enckey, bulkalgtag);
617 break;
618 #if 0
619 case SEC_OID_NETSCAPE_SMIME_KEA:
620 /* FORTEZZA key exchange algorithm */
621 /* the supplemental data is in the parameters of encalg */
622 bulkkey = SecCmsUtilDecryptSymKeyMISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
623 break;
624 #endif /* 0 */
625 default:
626 error = SEC_ERROR_UNSUPPORTED_KEYALG;
627 goto loser;
628 }
629 break;
630 case SecCmsRecipientInfoIDKeyAgree:
631 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
632 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
633 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
634 switch (encalgtag) {
635 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
636 /* Diffie-Helman key exchange */
637 /* XXX not yet implemented */
638 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
639 /* we support ephemeral-static DH only, so if the recipientinfo */
640 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
641 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
642 /* content encryption key using a Unwrap op */
643 /* the derive operation has to generate the key using the algorithm in RFC2631 */
644 error = SEC_ERROR_UNSUPPORTED_KEYALG;
645 break;
646 default:
647 error = SEC_ERROR_UNSUPPORTED_KEYALG;
648 goto loser;
649 }
650 break;
651 case SecCmsRecipientInfoIDKEK:
652 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
653 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
654 enckey = &(ri->ri.kekRecipientInfo.encKey);
655 /* not supported yet */
656 error = SEC_ERROR_UNSUPPORTED_KEYALG;
657 goto loser;
658 break;
659 }
660 /* XXXX continue here */
661 return bulkkey;
662
663 loser:
664 return NULL;
665 }