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