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