]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsrecinfo.c
Security-57740.51.3.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 ri->cert = CERT_DupCertificate(cert);
98 if (ri->cert == NULL)
99 goto loser;
100
101 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
102 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
103 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
104 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
105 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
106 algid = &freeAlgID;
107
108 certalgtag = SECOID_GetAlgorithmTag(algid);
109
110 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
111 switch (certalgtag) {
112 case SEC_OID_PKCS1_RSA_ENCRYPTION:
113 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans;
114 rid->identifierType = type;
115 if (type == SecCmsRecipientIDIssuerSN) {
116 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
117 if (rid->id.issuerAndSN == NULL) {
118 break;
119 }
120 } else if (type == SecCmsRecipientIDSubjectKeyID){
121
122 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item);
123 if (rid->id.subjectKeyID == NULL) {
124 rv = SECFailure;
125 PORT_SetError(SEC_ERROR_NO_MEMORY);
126 break;
127 }
128 if (SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID)) {
129 rv = SECFailure;
130 PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
131 break;
132 }
133 if (rid->id.subjectKeyID->Data == NULL) {
134 rv = SECFailure;
135 PORT_SetError(SEC_ERROR_NO_MEMORY);
136 break;
137 }
138 } else {
139 PORT_SetError(SEC_ERROR_INVALID_ARGS);
140 rv = SECFailure;
141 }
142 break;
143 case SEC_OID_MISSI_KEA_DSS_OLD:
144 case SEC_OID_MISSI_KEA_DSS:
145 case SEC_OID_MISSI_KEA:
146 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
147 if (type == SecCmsRecipientIDSubjectKeyID) {
148 rv = SECFailure;
149 break;
150 }
151 /* backward compatibility - this is not really a keytrans operation */
152 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans;
153 /* hardcoded issuerSN choice for now */
154 ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN;
155 ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
156 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
157 rv = SECFailure;
158 break;
159 }
160 break;
161 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
162 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
163 if (type == SecCmsRecipientIDSubjectKeyID) {
164 rv = SECFailure;
165 break;
166 }
167 /* a key agreement op */
168 ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree;
169
170 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
171 rv = SECFailure;
172 break;
173 }
174 /* we do not support the case where multiple recipients
175 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
176 * in this case, we would need to walk all the recipientInfos, take the
177 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
178 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
179
180 /* only epheremal-static Diffie-Hellman is supported for now
181 * this is the only form of key agreement that provides potential anonymity
182 * of the sender, plus we do not have to include certs in the message */
183
184 /* force single recipientEncryptedKey for now */
185 if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) {
186 rv = SECFailure;
187 break;
188 }
189
190 /* hardcoded IssuerSN choice for now */
191 rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN;
192 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
193 rv = SECFailure;
194 break;
195 }
196
197 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
198
199 /* see RFC2630 12.3.1.1 */
200 oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey;
201
202 rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
203 (void *)rek);
204
205 break;
206 case SEC_OID_EC_PUBLIC_KEY:
207 /* ephemeral-static ECDH - issuerAndSN, OriginatorPublicKey only */
208 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
209 if (type == SecCmsRecipientIDSubjectKeyID) {
210 rv = SECFailure;
211 break;
212 }
213 /* a key agreement op */
214 ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree;
215 ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
216 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
217 rv = SECFailure;
218 break;
219 }
220 /* we do not support the case where multiple recipients
221 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
222 * in this case, we would need to walk all the recipientInfos, take the
223 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
224 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
225
226 /* force single recipientEncryptedKey for now */
227 if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) {
228 rv = SECFailure;
229 break;
230 }
231
232 /* hardcoded IssuerSN choice for now */
233 rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN;
234 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
235 rv = SECFailure;
236 break;
237 }
238
239 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
240
241 /* see RFC 3278 3.1.1 */
242 oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey;
243
244 rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
245 (void *)rek);
246
247 break;
248 default:
249 /* other algorithms not supported yet */
250 /* NOTE that we do not support any KEK algorithm */
251 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
252 rv = SECFailure;
253 break;
254 }
255
256 if (rv == SECFailure)
257 goto loser;
258
259 /* set version */
260 switch (ri->recipientInfoType) {
261 case SecCmsRecipientInfoIDKeyTrans:
262 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN)
263 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
264 else
265 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
266 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
267 if (dummy == NULL)
268 goto loser;
269 break;
270 case SecCmsRecipientInfoIDKeyAgree:
271 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
272 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
273 if (dummy == NULL)
274 goto loser;
275 break;
276 case SecCmsRecipientInfoIDKEK:
277 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
278 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
279 SEC_CMS_KEK_RECIPIENT_INFO_VERSION);
280 if (dummy == NULL)
281 goto loser;
282 break;
283
284 }
285
286 if (SecCmsEnvelopedDataAddRecipient(envd, ri))
287 goto loser;
288
289 PORT_ArenaUnmark (poolp, mark);
290 #if 0
291 if (freeSpki)
292 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
293 #endif
294 return ri;
295
296 loser:
297 #if 0
298 if (freeSpki)
299 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
300 #endif
301 PORT_ArenaRelease (poolp, mark);
302 return NULL;
303 }
304
305 /*
306 * SecCmsRecipientInfoCreate - create a recipientinfo
307 *
308 * we currently do not create KeyAgreement recipientinfos with multiple
309 * recipientEncryptedKeys the certificate is supposed to have been
310 * verified by the caller
311 */
312 SecCmsRecipientInfoRef
313 SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert)
314 {
315 /* TODO: We might want to prefer subjkeyid */
316 #if 0
317 SecCmsRecipientInfoRef info = SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(envd, cert);
318
319 if (info)
320 return info;
321 else
322 #endif
323 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDIssuerSN, cert,
324 NULL, NULL);
325 }
326
327 SecCmsRecipientInfoRef
328 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
329 const SecAsn1Item * subjKeyID,
330 SecPublicKeyRef pubKey)
331 {
332 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
333 NULL, pubKey, subjKeyID);
334 }
335
336 SecCmsRecipientInfoRef
337 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
338 SecCertificateRef cert)
339 {
340 SecPublicKeyRef pubKey = NULL;
341 SecAsn1Item subjKeyID = {0, NULL};
342 SecCmsRecipientInfoRef retVal = NULL;
343 CFDataRef subjectKeyIDData = NULL;
344
345 if (!envd || !cert) {
346 return NULL;
347 }
348 subjectKeyIDData = SecCertificateGetSubjectKeyID(cert);
349 if (!subjectKeyIDData)
350 goto done;
351 subjKeyID.Length =
352 CFDataGetLength(subjectKeyIDData);
353 subjKeyID.Data = (uint8_t *)CFDataGetBytePtr(subjectKeyIDData);
354 retVal = nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
355 cert, pubKey, &subjKeyID);
356
357 done:
358
359 return retVal;
360 }
361
362 void
363 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri)
364 {
365 /* version was allocated on the pool, so no need to destroy it */
366 /* issuerAndSN was allocated on the pool, so no need to destroy it */
367 if (ri->cert != NULL)
368 CERT_DestroyCertificate(ri->cert);
369
370 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
371 SecCmsKeyTransRecipientInfoEx *extra;
372 extra = &ri->ri.keyTransRecipientInfoEx;
373 if (extra->pubKey)
374 SECKEY_DestroyPublicKey(extra->pubKey);
375 }
376
377 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
378 /* we're done. */
379 }
380
381 int
382 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri)
383 {
384 unsigned long version;
385 SecAsn1Item * versionitem = NULL;
386
387 switch (ri->recipientInfoType) {
388 case SecCmsRecipientInfoIDKeyTrans:
389 /* ignore subIndex */
390 versionitem = &(ri->ri.keyTransRecipientInfo.version);
391 break;
392 case SecCmsRecipientInfoIDKEK:
393 /* ignore subIndex */
394 versionitem = &(ri->ri.kekRecipientInfo.version);
395 break;
396 case SecCmsRecipientInfoIDKeyAgree:
397 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
398 break;
399 }
400
401 PORT_Assert(versionitem);
402 if (versionitem == NULL)
403 return 0;
404
405 /* always take apart the SecAsn1Item */
406 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
407 return 0;
408 else
409 return (int)version;
410 }
411
412 SecAsn1Item *
413 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri, int subIndex)
414 {
415 SecAsn1Item * enckey = NULL;
416
417 switch (ri->recipientInfoType) {
418 case SecCmsRecipientInfoIDKeyTrans:
419 /* ignore subIndex */
420 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
421 break;
422 case SecCmsRecipientInfoIDKEK:
423 /* ignore subIndex */
424 enckey = &(ri->ri.kekRecipientInfo.encKey);
425 break;
426 case SecCmsRecipientInfoIDKeyAgree:
427 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
428 break;
429 }
430 return enckey;
431 }
432
433
434 SECOidTag
435 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri)
436 {
437 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
438
439 switch (ri->recipientInfoType) {
440 case SecCmsRecipientInfoIDKeyTrans:
441 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
442 break;
443 case SecCmsRecipientInfoIDKeyAgree:
444 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
445 break;
446 case SecCmsRecipientInfoIDKEK:
447 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
448 break;
449 }
450 return encalgtag;
451 }
452
453 OSStatus
454 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey,
455 SECOidTag bulkalgtag)
456 {
457 SecCertificateRef cert;
458 SECOidTag certalgtag;
459 OSStatus rv = SECSuccess;
460 SecCmsRecipientEncryptedKey *rek;
461 SecCmsOriginatorIdentifierOrKey *oiok;
462 const SECAlgorithmID *algid;
463 SECAlgorithmID freeAlgID;
464 PLArenaPool *poolp;
465 Boolean usesSubjKeyID;
466 uint8_t nullData[2] = {SEC_ASN1_NULL, 0};
467 SECItem nullItem;
468 SecCmsKeyAgreeRecipientInfo *kari;
469
470 poolp = ri->envelopedData->contentInfo.cmsg->poolp;
471 cert = ri->cert;
472 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
473 if (cert) {
474 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
475 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
476 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
477 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
478 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
479 algid = &freeAlgID;
480 } else {
481 PORT_SetError(SEC_ERROR_INVALID_ARGS);
482 return SECFailure;
483 }
484
485 /* XXX set ri->recipientInfoType to the proper value here */
486 /* or should we look if it's been set already ? */
487
488 certalgtag = SECOID_GetAlgorithmTag(algid);
489 switch (certalgtag) {
490 case SEC_OID_PKCS1_RSA_ENCRYPTION:
491 /* wrap the symkey */
492 if (cert) {
493 rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey,
494 &ri->ri.keyTransRecipientInfo.encKey);
495 if (rv != SECSuccess)
496 break;
497 }
498
499 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
500 break;
501 case SEC_OID_EC_PUBLIC_KEY:
502 /* These were set up in nss_cmsrecipientinfo_create() */
503 kari = &ri->ri.keyAgreeRecipientInfo;
504 rek = kari->recipientEncryptedKeys[0];
505 if (rek == NULL) {
506 rv = SECFailure;
507 break;
508 }
509
510 oiok = &(kari->originatorIdentifierOrKey);
511 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);
512
513 /*
514 * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to
515 * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one
516 * explicitly instead of mucking up the login in SECOID_SetAlgorithmID().
517 */
518 nullItem.Data = nullData;
519 nullItem.Length = 2;
520 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
521 SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) {
522 rv = SECFailure;
523 break;
524 }
525 /* this will generate a key pair, compute the shared secret, */
526 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
527 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
528 rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey,
529 &rek->encKey,
530 &kari->ukm,
531 &kari->keyEncAlg,
532 &oiok->id.originatorPublicKey.publicKey);
533 break;
534 default:
535 /* other algorithms not supported yet */
536 /* NOTE that we do not support any KEK algorithm */
537 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
538 rv = SECFailure;
539 break;
540 }
541
542 return rv;
543 }
544
545 #ifdef NDEBUG
546 #define dprintf(args...)
547 #else
548 #define dprintf(args...) fprintf(stderr, args)
549 #endif
550
551 SecSymmetricKeyRef
552 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri, int subIndex,
553 SecCertificateRef cert, SecPrivateKeyRef privkey, SECOidTag bulkalgtag)
554 {
555 SecSymmetricKeyRef bulkkey = NULL;
556 SECAlgorithmID *encalg;
557 SECOidTag encalgtag;
558 SecAsn1Item * enckey;
559 int error;
560
561 ri->cert = CERT_DupCertificate(cert);
562 /* mark the recipientInfo so we can find it later */
563
564 switch (ri->recipientInfoType) {
565 case SecCmsRecipientInfoIDKeyTrans:
566 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
567 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
568 switch (encalgtag) {
569 case SEC_OID_PKCS1_RSA_ENCRYPTION:
570 /* RSA encryption algorithm: */
571 /* get the symmetric (bulk) key by unwrapping it using our private key */
572 bulkkey = SecCmsUtilDecryptSymKeyRSA(privkey, enckey, bulkalgtag);
573 break;
574 #if 0
575 case SEC_OID_NETSCAPE_SMIME_KEA:
576 /* FORTEZZA key exchange algorithm */
577 /* the supplemental data is in the parameters of encalg */
578 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
579 bulkkey = SecCmsUtilDecryptSymKeyMISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
580 break;
581 #endif /* 0 */
582 default:
583 error = SEC_ERROR_UNSUPPORTED_KEYALG;
584 goto loser;
585 }
586 break;
587 case SecCmsRecipientInfoIDKeyAgree:
588 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
589 switch (encalgtag) {
590 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
591 /* Diffie-Helman key exchange */
592 /* XXX not yet implemented */
593 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
594 /* we support ephemeral-static DH only, so if the recipientinfo */
595 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
596 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
597 /* content encryption key using a Unwrap op */
598 /* the derive operation has to generate the key using the algorithm in RFC2631 */
599 error = SEC_ERROR_UNSUPPORTED_KEYALG;
600 break;
601 case SEC_OID_DH_SINGLE_STD_SHA1KDF:
602 {
603 /* ephemeral-static ECDH */
604 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
605 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
606 SecCmsKeyAgreeRecipientInfo *kari = &ri->ri.keyAgreeRecipientInfo;
607 SecCmsOriginatorIdentifierOrKey *oiok = &kari->originatorIdentifierOrKey;
608 if(oiok->identifierType != SecCmsOriginatorIDOrKeyOriginatorPublicKey) {
609 dprintf("SEC_OID_EC_PUBLIC_KEY unwrap key: bad oiok.id\n");
610 error = SEC_ERROR_LIBRARY_FAILURE;
611 goto loser;
612 }
613 SecCmsOriginatorPublicKey *opk = &oiok->id.originatorPublicKey;
614 /* FIXME - verify opk->algorithmIdentifier here? */
615 SecAsn1Item senderPubKey = opk->publicKey;
616 SecAsn1Item *ukm = &kari->ukm;
617 bulkkey = SecCmsUtilDecryptSymKeyECDH(privkey, enckey, ukm, encalg, bulkalgtag, &senderPubKey);
618 break;
619 }
620 default:
621 error = SEC_ERROR_UNSUPPORTED_KEYALG;
622 goto loser;
623 }
624 break;
625 case SecCmsRecipientInfoIDKEK:
626 /* not supported yet */
627 error = SEC_ERROR_UNSUPPORTED_KEYALG;
628 goto loser;
629 break;
630 }
631 /* XXXX continue here */
632 return bulkkey;
633
634 loser:
635 PORT_SetError(error);
636 return NULL;
637 }