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