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