]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsrecinfo.c
Security-57740.31.2.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 case SEC_OID_EC_PUBLIC_KEY:
225 /* ephemeral-static ECDH - issuerAndSN, OriginatorPublicKey only */
226 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID);
227 if (type == SecCmsRecipientIDSubjectKeyID) {
228 rv = SECFailure;
229 break;
230 }
231 /* a key agreement op */
232 ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree;
233 ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
234 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
235 rv = SECFailure;
236 break;
237 }
238 /* we do not support the case where multiple recipients
239 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
240 * in this case, we would need to walk all the recipientInfos, take the
241 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
242 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
243
244 /* force single recipientEncryptedKey for now */
245 if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) {
246 rv = SECFailure;
247 break;
248 }
249
250 /* hardcoded IssuerSN choice for now */
251 rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN;
252 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
253 rv = SECFailure;
254 break;
255 }
256
257 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
258
259 /* see RFC 3278 3.1.1 */
260 oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey;
261
262 rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
263 (void *)rek);
264
265 break;
266 default:
267 /* other algorithms not supported yet */
268 /* NOTE that we do not support any KEK algorithm */
269 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
270 rv = SECFailure;
271 break;
272 }
273
274 if (rv == SECFailure)
275 goto loser;
276
277 /* set version */
278 switch (ri->recipientInfoType) {
279 case SecCmsRecipientInfoIDKeyTrans:
280 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN)
281 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
282 else
283 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
284 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
285 if (dummy == NULL)
286 goto loser;
287 break;
288 case SecCmsRecipientInfoIDKeyAgree:
289 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
290 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
291 if (dummy == NULL)
292 goto loser;
293 break;
294 case SecCmsRecipientInfoIDKEK:
295 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
296 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
297 SEC_CMS_KEK_RECIPIENT_INFO_VERSION);
298 if (dummy == NULL)
299 goto loser;
300 break;
301
302 }
303
304 if (SecCmsEnvelopedDataAddRecipient(envd, ri))
305 goto loser;
306
307 PORT_ArenaUnmark (poolp, mark);
308 #if 0
309 if (freeSpki)
310 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
311 #endif
312 return ri;
313
314 loser:
315 #if 0
316 if (freeSpki)
317 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
318 #endif
319 PORT_ArenaRelease (poolp, mark);
320 return NULL;
321 }
322
323 /*
324 * SecCmsRecipientInfoCreate - create a recipientinfo
325 *
326 * we currently do not create KeyAgreement recipientinfos with multiple
327 * recipientEncryptedKeys the certificate is supposed to have been
328 * verified by the caller
329 */
330 SecCmsRecipientInfoRef
331 SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert)
332 {
333 /* TODO: We might want to prefer subjkeyid */
334 #if 0
335 SecCmsRecipientInfoRef info = SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(envd, cert);
336
337 if (info)
338 return info;
339 else
340 #endif
341 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDIssuerSN, cert,
342 NULL, NULL);
343 }
344
345 SecCmsRecipientInfoRef
346 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
347 const SecAsn1Item * subjKeyID,
348 SecPublicKeyRef pubKey)
349 {
350 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
351 NULL, pubKey, subjKeyID);
352 }
353
354 #if USE_CDSA_CRYPTO
355 SecCmsRecipientInfoRef
356 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
357 SecCertificateRef cert)
358 {
359 SecPublicKeyRef pubKey = NULL;
360 SecAsn1Item subjKeyID = {0, NULL};
361 SecCmsRecipientInfoRef retVal = NULL;
362
363 if (!envd || !cert) {
364 return NULL;
365 }
366 pubKey = CERT_ExtractPublicKey(cert);
367 if (!pubKey) {
368 goto done;
369 }
370 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
371 subjKeyID.Data == NULL) {
372 goto done;
373 }
374 retVal = SecCmsRecipientInfoCreateWithSubjKeyID(envd, &subjKeyID, pubKey);
375 done:
376 if (pubKey)
377 SECKEY_DestroyPublicKey(pubKey);
378
379 if (subjKeyID.Data)
380 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
381
382 return retVal;
383 }
384 #else
385 SecCmsRecipientInfoRef
386 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
387 SecCertificateRef cert)
388 {
389 SecPublicKeyRef pubKey = NULL;
390 SecAsn1Item subjKeyID = {0, NULL};
391 SecCmsRecipientInfoRef retVal = NULL;
392 CFDataRef subjectKeyIDData = NULL;
393
394 if (!envd || !cert) {
395 return NULL;
396 }
397 subjectKeyIDData = SecCertificateGetSubjectKeyID(cert);
398 if (!subjectKeyIDData)
399 goto done;
400 subjKeyID.Length =
401 CFDataGetLength(subjectKeyIDData);
402 subjKeyID.Data = (uint8_t *)CFDataGetBytePtr(subjectKeyIDData);
403 retVal = nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID,
404 cert, pubKey, &subjKeyID);
405
406 done:
407
408 return retVal;
409 }
410 #endif
411
412 void
413 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri)
414 {
415 /* version was allocated on the pool, so no need to destroy it */
416 /* issuerAndSN was allocated on the pool, so no need to destroy it */
417 if (ri->cert != NULL)
418 CERT_DestroyCertificate(ri->cert);
419
420 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
421 SecCmsKeyTransRecipientInfoEx *extra;
422 extra = &ri->ri.keyTransRecipientInfoEx;
423 if (extra->pubKey)
424 SECKEY_DestroyPublicKey(extra->pubKey);
425 }
426
427 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
428 /* we're done. */
429 }
430
431 int
432 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri)
433 {
434 unsigned long version;
435 SecAsn1Item * versionitem = NULL;
436
437 switch (ri->recipientInfoType) {
438 case SecCmsRecipientInfoIDKeyTrans:
439 /* ignore subIndex */
440 versionitem = &(ri->ri.keyTransRecipientInfo.version);
441 break;
442 case SecCmsRecipientInfoIDKEK:
443 /* ignore subIndex */
444 versionitem = &(ri->ri.kekRecipientInfo.version);
445 break;
446 case SecCmsRecipientInfoIDKeyAgree:
447 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
448 break;
449 }
450
451 PORT_Assert(versionitem);
452 if (versionitem == NULL)
453 return 0;
454
455 /* always take apart the SecAsn1Item */
456 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
457 return 0;
458 else
459 return (int)version;
460 }
461
462 SecAsn1Item *
463 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri, int subIndex)
464 {
465 SecAsn1Item * enckey = NULL;
466
467 switch (ri->recipientInfoType) {
468 case SecCmsRecipientInfoIDKeyTrans:
469 /* ignore subIndex */
470 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
471 break;
472 case SecCmsRecipientInfoIDKEK:
473 /* ignore subIndex */
474 enckey = &(ri->ri.kekRecipientInfo.encKey);
475 break;
476 case SecCmsRecipientInfoIDKeyAgree:
477 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
478 break;
479 }
480 return enckey;
481 }
482
483
484 SECOidTag
485 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri)
486 {
487 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
488
489 switch (ri->recipientInfoType) {
490 case SecCmsRecipientInfoIDKeyTrans:
491 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
492 break;
493 case SecCmsRecipientInfoIDKeyAgree:
494 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
495 break;
496 case SecCmsRecipientInfoIDKEK:
497 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
498 break;
499 }
500 return encalgtag;
501 }
502
503 OSStatus
504 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey,
505 SECOidTag bulkalgtag)
506 {
507 SecCertificateRef cert;
508 SECOidTag certalgtag;
509 OSStatus rv = SECSuccess;
510 #if 0
511 SecAsn1Item * params = NULL;
512 #endif /* 0 */
513 SecCmsRecipientEncryptedKey *rek;
514 SecCmsOriginatorIdentifierOrKey *oiok;
515 const SECAlgorithmID *algid;
516 SECAlgorithmID freeAlgID;
517 PLArenaPool *poolp;
518 SecCmsKeyTransRecipientInfoEx *extra = NULL;
519 Boolean usesSubjKeyID;
520 uint8_t nullData[2] = {SEC_ASN1_NULL, 0};
521 SECItem nullItem;
522 SecCmsKeyAgreeRecipientInfo *kari;
523
524 poolp = ri->envelopedData->contentInfo.cmsg->poolp;
525 cert = ri->cert;
526 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
527 if (cert) {
528 #if USE_CDSA_CRYPTO
529 rv = SecCertificateGetAlgorithmID(cert,&algid);
530 if (rv)
531 return SECFailure;
532 #else
533 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
534 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
535 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
536 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
537 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
538 algid = &freeAlgID;
539 #endif
540 } else if (usesSubjKeyID) {
541 extra = &ri->ri.keyTransRecipientInfoEx;
542 /* sanity check */
543 PORT_Assert(extra->pubKey);
544 if (!extra->pubKey) {
545 PORT_SetError(SEC_ERROR_INVALID_ARGS);
546 return SECFailure;
547 }
548 #if USE_CDSA_CRYPTO
549 rv = SecKeyGetAlgorithmID(extra->pubKey,&algid);
550 if (rv)
551 #endif
552 return SECFailure;
553 certalgtag = SECOID_GetAlgorithmTag(algid);
554 } else {
555 PORT_SetError(SEC_ERROR_INVALID_ARGS);
556 return SECFailure;
557 }
558
559 /* XXX set ri->recipientInfoType to the proper value here */
560 /* or should we look if it's been set already ? */
561
562 certalgtag = SECOID_GetAlgorithmTag(algid);
563 switch (certalgtag) {
564 case SEC_OID_PKCS1_RSA_ENCRYPTION:
565 /* wrap the symkey */
566 if (cert) {
567 rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey,
568 &ri->ri.keyTransRecipientInfo.encKey);
569 if (rv != SECSuccess)
570 break;
571 } else if (usesSubjKeyID) {
572 PORT_Assert(extra != NULL);
573 rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey,
574 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
575 if (rv != SECSuccess)
576 break;
577 }
578
579 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
580 break;
581 #if 0
582 case SEC_OID_MISSI_KEA_DSS_OLD:
583 case SEC_OID_MISSI_KEA_DSS:
584 case SEC_OID_MISSI_KEA:
585 rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey,
586 bulkalgtag,
587 &ri->ri.keyTransRecipientInfo.encKey,
588 &params, ri->cmsg->pwfn_arg);
589 if (rv != SECSuccess)
590 break;
591
592 /* here, we DO need to pass the params to the wrap function because, with
593 * RSA, there is no funny stuff going on with generation of IV vectors or so */
594 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);
595 break;
596 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
597 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
598 if (rek == NULL) {
599 rv = SECFailure;
600 break;
601 }
602
603 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
604 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);
605
606 /* see RFC2630 12.3.1.1 */
607 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
608 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
609 rv = SECFailure;
610 break;
611 }
612
613 /* this will generate a key pair, compute the shared secret, */
614 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
615 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
616 rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey,
617 &rek->encKey,
618 &ri->ri.keyAgreeRecipientInfo.ukm,
619 &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
620 &oiok->id.originatorPublicKey.publicKey);
621
622 break;
623 #endif /* 0 */
624 case SEC_OID_EC_PUBLIC_KEY:
625 /* These were set up in nss_cmsrecipientinfo_create() */
626 kari = &ri->ri.keyAgreeRecipientInfo;
627 rek = kari->recipientEncryptedKeys[0];
628 if (rek == NULL) {
629 rv = SECFailure;
630 break;
631 }
632
633 oiok = &(kari->originatorIdentifierOrKey);
634 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);
635
636 /*
637 * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to
638 * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one
639 * explicitly instead of mucking up the login in SECOID_SetAlgorithmID().
640 */
641 nullItem.Data = nullData;
642 nullItem.Length = 2;
643 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
644 SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) {
645 rv = SECFailure;
646 break;
647 }
648 /* this will generate a key pair, compute the shared secret, */
649 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
650 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
651 rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey,
652 &rek->encKey,
653 &kari->ukm,
654 &kari->keyEncAlg,
655 &oiok->id.originatorPublicKey.publicKey);
656 break;
657 default:
658 /* other algorithms not supported yet */
659 /* NOTE that we do not support any KEK algorithm */
660 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
661 rv = SECFailure;
662 break;
663 }
664 #if 0
665 if (freeSpki)
666 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
667 #endif
668
669 return rv;
670 }
671
672 #ifdef NDEBUG
673 #define dprintf(args...)
674 #else
675 #define dprintf(args...) fprintf(stderr, args)
676 #endif
677
678 SecSymmetricKeyRef
679 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri, int subIndex,
680 SecCertificateRef cert, SecPrivateKeyRef privkey, SECOidTag bulkalgtag)
681 {
682 SecSymmetricKeyRef bulkkey = NULL;
683 SECAlgorithmID *encalg;
684 SECOidTag encalgtag;
685 SecAsn1Item * enckey;
686 int error;
687
688 ri->cert = CERT_DupCertificate(cert);
689 /* mark the recipientInfo so we can find it later */
690
691 switch (ri->recipientInfoType) {
692 case SecCmsRecipientInfoIDKeyTrans:
693 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
694 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
695 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
696 switch (encalgtag) {
697 case SEC_OID_PKCS1_RSA_ENCRYPTION:
698 /* RSA encryption algorithm: */
699 /* get the symmetric (bulk) key by unwrapping it using our private key */
700 bulkkey = SecCmsUtilDecryptSymKeyRSA(privkey, enckey, bulkalgtag);
701 break;
702 #if 0
703 case SEC_OID_NETSCAPE_SMIME_KEA:
704 /* FORTEZZA key exchange algorithm */
705 /* the supplemental data is in the parameters of encalg */
706 bulkkey = SecCmsUtilDecryptSymKeyMISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);
707 break;
708 #endif /* 0 */
709 default:
710 error = SEC_ERROR_UNSUPPORTED_KEYALG;
711 goto loser;
712 }
713 break;
714 case SecCmsRecipientInfoIDKeyAgree:
715 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
716 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
717 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
718 switch (encalgtag) {
719 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
720 /* Diffie-Helman key exchange */
721 /* XXX not yet implemented */
722 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
723 /* we support ephemeral-static DH only, so if the recipientinfo */
724 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
725 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
726 /* content encryption key using a Unwrap op */
727 /* the derive operation has to generate the key using the algorithm in RFC2631 */
728 error = SEC_ERROR_UNSUPPORTED_KEYALG;
729 break;
730 case SEC_OID_DH_SINGLE_STD_SHA1KDF:
731 {
732 /* ephemeral-static ECDH */
733 SecCmsKeyAgreeRecipientInfo *kari = &ri->ri.keyAgreeRecipientInfo;
734 SecCmsOriginatorIdentifierOrKey *oiok = &kari->originatorIdentifierOrKey;
735 if(oiok->identifierType != SecCmsOriginatorIDOrKeyOriginatorPublicKey) {
736 dprintf("SEC_OID_EC_PUBLIC_KEY unwrap key: bad oiok.id\n");
737 goto loser;
738 }
739 SecCmsOriginatorPublicKey *opk = &oiok->id.originatorPublicKey;
740 /* FIXME - verify opk->algorithmIdentifier here? */
741 SecAsn1Item senderPubKey = opk->publicKey;
742 SecAsn1Item *ukm = &kari->ukm;
743 bulkkey = SecCmsUtilDecryptSymKeyECDH(privkey, enckey, ukm, encalg, bulkalgtag, &senderPubKey);
744 break;
745 }
746 default:
747 error = SEC_ERROR_UNSUPPORTED_KEYALG;
748 goto loser;
749 }
750 break;
751 case SecCmsRecipientInfoIDKEK:
752 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
753 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
754 enckey = &(ri->ri.kekRecipientInfo.encKey);
755 /* not supported yet */
756 error = SEC_ERROR_UNSUPPORTED_KEYALG;
757 goto loser;
758 break;
759 }
760 /* XXXX continue here */
761 return bulkkey;
762
763 loser:
764 return NULL;
765 }