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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * CMS recipientInfo methods.
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>
51 nss_cmsrecipientinfo_usessubjectkeyid(SecCmsRecipientInfoRef ri
)
53 if (ri
->recipientInfoType
== SecCmsRecipientInfoIDKeyTrans
) {
54 SecCmsRecipientIdentifier
*rid
;
55 rid
= &ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
;
56 if (rid
->identifierType
== SecCmsRecipientIDSubjectKeyID
) {
64 static SecCmsRecipientInfoRef
65 nss_cmsrecipientinfo_create(SecCmsMessageRef cmsg
, SecCmsRecipientIDSelector type
,
66 SecCertificateRef cert
, SecPublicKeyRef pubKey
,
67 CSSM_DATA_PTR subjKeyID
)
69 SecCmsRecipientInfoRef ri
;
72 OSStatus rv
= SECSuccess
;
73 SecCmsRecipientEncryptedKey
*rek
;
74 SecCmsOriginatorIdentifierOrKey
*oiok
;
75 unsigned long version
;
78 const SECAlgorithmID
*algid
;
79 SecCmsRecipientIdentifier
*rid
;
83 mark
= PORT_ArenaMark(poolp
);
85 ri
= (SecCmsRecipientInfoRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsRecipientInfo
));
90 if (type
== SecCmsRecipientIDIssuerSN
)
92 ri
->cert
= CERT_DupCertificate(cert
);
95 rv
= SecCertificateGetAlgorithmID(cert
,&algid
);
99 rv
= SecKeyGetAlgorithmID(pubKey
,&algid
);
101 /* TBD: Unify this code. Currently, iOS has an incompatible
102 * SecKeyGetAlgorithmID implementation. */
107 certalgtag
= SECOID_GetAlgorithmTag(algid
);
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
) {
119 } else if (type
== SecCmsRecipientIDSubjectKeyID
){
121 rid
->id
.subjectKeyID
= PORT_ArenaNew(poolp
, CSSM_DATA
);
122 if (rid
->id
.subjectKeyID
== NULL
) {
124 PORT_SetError(SEC_ERROR_NO_MEMORY
);
127 if (SECITEM_CopyItem(poolp
, rid
->id
.subjectKeyID
, subjKeyID
)) {
129 PORT_SetError(SEC_ERROR_UNKNOWN_CERT
);
132 if (rid
->id
.subjectKeyID
->Data
== NULL
) {
134 PORT_SetError(SEC_ERROR_NO_MEMORY
);
138 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
142 case SEC_OID_MISSI_KEA_DSS_OLD
:
143 case SEC_OID_MISSI_KEA_DSS
:
144 case SEC_OID_MISSI_KEA
:
145 PORT_Assert(type
!= SecCmsRecipientIDSubjectKeyID
);
146 if (type
== SecCmsRecipientIDSubjectKeyID
) {
150 /* backward compatibility - this is not really a keytrans operation */
151 ri
->recipientInfoType
= SecCmsRecipientInfoIDKeyTrans
;
152 /* hardcoded issuerSN choice for now */
153 ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.identifierType
= SecCmsRecipientIDIssuerSN
;
154 ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
);
155 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
== NULL
) {
160 case SEC_OID_X942_DIFFIE_HELMAN_KEY
: /* dh-public-number */
161 PORT_Assert(type
!= SecCmsRecipientIDSubjectKeyID
);
162 if (type
== SecCmsRecipientIDSubjectKeyID
) {
166 /* a key agreement op */
167 ri
->recipientInfoType
= SecCmsRecipientInfoIDKeyAgree
;
169 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
== NULL
) {
173 /* we do not support the case where multiple recipients
174 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
175 * in this case, we would need to walk all the recipientInfos, take the
176 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
177 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
179 /* only epheremal-static Diffie-Hellman is supported for now
180 * this is the only form of key agreement that provides potential anonymity
181 * of the sender, plus we do not have to include certs in the message */
183 /* force single recipientEncryptedKey for now */
184 if ((rek
= SecCmsRecipientEncryptedKeyCreate(poolp
)) == NULL
) {
189 /* hardcoded IssuerSN choice for now */
190 rek
->recipientIdentifier
.identifierType
= SecCmsKeyAgreeRecipientIDIssuerSN
;
191 if ((rek
->recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
) {
196 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
198 /* see RFC2630 12.3.1.1 */
199 oiok
->identifierType
= SecCmsOriginatorIDOrKeyOriginatorPublicKey
;
201 rv
= SecCmsArrayAdd(poolp
, (void ***)&ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
,
206 case SEC_OID_EC_PUBLIC_KEY
:
207 /* ephemeral-static ECDH - issuerAndSN, OriginatorPublicKey only */
208 PORT_Assert(type
!= SecCmsRecipientIDSubjectKeyID
);
209 if (type
== SecCmsRecipientIDSubjectKeyID
) {
213 /* a key agreement op */
214 ri
->recipientInfoType
= SecCmsRecipientInfoIDKeyAgree
;
215 ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
);
216 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
== NULL
) {
220 /* we do not support the case where multiple recipients
221 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
222 * in this case, we would need to walk all the recipientInfos, take the
223 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
224 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
226 /* force single recipientEncryptedKey for now */
227 if ((rek
= SecCmsRecipientEncryptedKeyCreate(poolp
)) == NULL
) {
232 /* hardcoded IssuerSN choice for now */
233 rek
->recipientIdentifier
.identifierType
= SecCmsKeyAgreeRecipientIDIssuerSN
;
234 if ((rek
->recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
) {
239 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
241 /* see RFC 3278 3.1.1 */
242 oiok
->identifierType
= SecCmsOriginatorIDOrKeyOriginatorPublicKey
;
244 rv
= SecCmsArrayAdd(poolp
, (void ***)&ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
,
250 /* other algorithms not supported yet */
251 /* NOTE that we do not support any KEK algorithm */
252 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
257 if (rv
== SECFailure
)
261 switch (ri
->recipientInfoType
) {
262 case SecCmsRecipientInfoIDKeyTrans
:
263 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.identifierType
== SecCmsRecipientIDIssuerSN
)
264 version
= SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN
;
266 version
= SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY
;
267 dummy
= SEC_ASN1EncodeInteger(poolp
, &(ri
->ri
.keyTransRecipientInfo
.version
), version
);
271 case SecCmsRecipientInfoIDKeyAgree
:
272 dummy
= SEC_ASN1EncodeInteger(poolp
, &(ri
->ri
.keyAgreeRecipientInfo
.version
),
273 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION
);
277 case SecCmsRecipientInfoIDKEK
:
278 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
279 dummy
= SEC_ASN1EncodeInteger(poolp
, &(ri
->ri
.kekRecipientInfo
.version
),
280 SEC_CMS_KEK_RECIPIENT_INFO_VERSION
);
287 PORT_ArenaUnmark (poolp
, mark
);
290 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
297 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
299 PORT_ArenaRelease (poolp
, mark
);
304 * SecCmsRecipientInfoCreate - create a recipientinfo
306 * we currently do not create KeyAgreement recipientinfos with multiple
307 * recipientEncryptedKeys the certificate is supposed to have been
308 * verified by the caller
310 SecCmsRecipientInfoRef
311 SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg
, SecCertificateRef cert
)
313 return nss_cmsrecipientinfo_create(cmsg
, SecCmsRecipientIDIssuerSN
, cert
,
317 SecCmsRecipientInfoRef
318 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg
,
319 CSSM_DATA_PTR subjKeyID
,
320 SecPublicKeyRef pubKey
)
322 return nss_cmsrecipientinfo_create(cmsg
, SecCmsRecipientIDSubjectKeyID
,
323 NULL
, pubKey
, subjKeyID
);
326 /* This is exported out of the Security framework, but it's in
327 * SecCertificateInternal.h, which we don't have access to from
328 * the libsecurity_smime project. */
329 CFDataRef
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
);
331 SecCmsRecipientInfoRef
332 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsMessageRef cmsg
,
333 SecCertificateRef cert
)
335 SecKeyRef pubKey
= NULL
;
336 CSSM_DATA subjKeyID
= {0, NULL
};
337 SecCmsRecipientInfoRef retVal
= NULL
;
338 CFDataRef subjectKeyIDData
= NULL
;
341 if (!cmsg
|| !cert
) {
345 subjectKeyIDData
= SecCertificateGetSubjectKeyID(cert
);
346 if (!subjectKeyIDData
)
349 CFDataGetLength(subjectKeyIDData
);
350 subjKeyID
.Data
= (uint8_t *)CFDataGetBytePtr(subjectKeyIDData
);
352 retVal
= SecCmsRecipientInfoCreateWithSubjKeyID(cmsg
, &subjKeyID
, pubKey
);
355 SECKEY_DestroyPublicKey(pubKey
);
358 SECITEM_FreeItem(&subjKeyID
, PR_FALSE
);
364 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri
)
366 /* version was allocated on the pool, so no need to destroy it */
367 /* issuerAndSN was allocated on the pool, so no need to destroy it */
368 if (ri
->cert
!= NULL
)
369 CERT_DestroyCertificate(ri
->cert
);
371 if (nss_cmsrecipientinfo_usessubjectkeyid(ri
)) {
372 SecCmsKeyTransRecipientInfoEx
*extra
;
373 extra
= &ri
->ri
.keyTransRecipientInfoEx
;
375 SECKEY_DestroyPublicKey(extra
->pubKey
);
378 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
383 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri
)
385 unsigned long version
;
386 CSSM_DATA_PTR versionitem
= NULL
;
388 switch (ri
->recipientInfoType
) {
389 case SecCmsRecipientInfoIDKeyTrans
:
390 /* ignore subIndex */
391 versionitem
= &(ri
->ri
.keyTransRecipientInfo
.version
);
393 case SecCmsRecipientInfoIDKEK
:
394 /* ignore subIndex */
395 versionitem
= &(ri
->ri
.kekRecipientInfo
.version
);
397 case SecCmsRecipientInfoIDKeyAgree
:
398 versionitem
= &(ri
->ri
.keyAgreeRecipientInfo
.version
);
402 PORT_Assert(versionitem
);
403 if (versionitem
== NULL
)
406 /* always take apart the CSSM_DATA */
407 if (SEC_ASN1DecodeInteger(versionitem
, &version
) != SECSuccess
)
414 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri
, int subIndex
)
416 CSSM_DATA_PTR enckey
= NULL
;
418 switch (ri
->recipientInfoType
) {
419 case SecCmsRecipientInfoIDKeyTrans
:
420 /* ignore subIndex */
421 enckey
= &(ri
->ri
.keyTransRecipientInfo
.encKey
);
423 case SecCmsRecipientInfoIDKEK
:
424 /* ignore subIndex */
425 enckey
= &(ri
->ri
.kekRecipientInfo
.encKey
);
427 case SecCmsRecipientInfoIDKeyAgree
:
428 enckey
= &(ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
[subIndex
]->encKey
);
436 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri
)
438 SECOidTag encalgtag
= SEC_OID_UNKNOWN
; /* an invalid encryption alg */
440 switch (ri
->recipientInfoType
) {
441 case SecCmsRecipientInfoIDKeyTrans
:
442 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
));
444 case SecCmsRecipientInfoIDKeyAgree
:
445 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
));
447 case SecCmsRecipientInfoIDKEK
:
448 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.kekRecipientInfo
.keyEncAlg
));
455 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri
, SecSymmetricKeyRef bulkkey
,
456 SECOidTag bulkalgtag
)
458 SecCertificateRef cert
;
459 SECOidTag certalgtag
;
460 OSStatus rv
= SECSuccess
;
462 CSSM_DATA_PTR params
= NULL
;
464 SecCmsRecipientEncryptedKey
*rek
;
465 SecCmsOriginatorIdentifierOrKey
*oiok
;
466 const SECAlgorithmID
*algid
;
468 SecCmsKeyTransRecipientInfoEx
*extra
= NULL
;
469 Boolean usesSubjKeyID
;
470 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
472 SecCmsKeyAgreeRecipientInfo
*kari
;
474 poolp
= ri
->cmsg
->poolp
;
476 usesSubjKeyID
= nss_cmsrecipientinfo_usessubjectkeyid(ri
);
478 rv
= SecCertificateGetAlgorithmID(cert
,&algid
);
481 certalgtag
= SECOID_GetAlgorithmTag(algid
);
482 } else if (usesSubjKeyID
) {
483 extra
= &ri
->ri
.keyTransRecipientInfoEx
;
485 PORT_Assert(extra
->pubKey
);
486 if (!extra
->pubKey
) {
487 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
490 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
491 rv
= SecKeyGetAlgorithmID(extra
->pubKey
,&algid
);
493 /* TBD: Unify this code. Currently, iOS has an incompatible
494 * SecKeyGetAlgorithmID implementation. */
499 certalgtag
= SECOID_GetAlgorithmTag(algid
);
501 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
505 /* XXX set ri->recipientInfoType to the proper value here */
506 /* or should we look if it's been set already ? */
508 certalgtag
= SECOID_GetAlgorithmTag(algid
);
509 switch (certalgtag
) {
510 case SEC_OID_PKCS1_RSA_ENCRYPTION
:
511 /* wrap the symkey */
513 rv
= SecCmsUtilEncryptSymKeyRSA(poolp
, cert
, bulkkey
,
514 &ri
->ri
.keyTransRecipientInfo
.encKey
);
515 if (rv
!= SECSuccess
)
517 } else if (usesSubjKeyID
) {
518 PORT_Assert(extra
!= NULL
);
519 rv
= SecCmsUtilEncryptSymKeyRSAPubKey(poolp
, extra
->pubKey
,
520 bulkkey
, &ri
->ri
.keyTransRecipientInfo
.encKey
);
521 if (rv
!= SECSuccess
)
525 rv
= SECOID_SetAlgorithmID(poolp
, &(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
), certalgtag
, NULL
);
528 case SEC_OID_MISSI_KEA_DSS_OLD
:
529 case SEC_OID_MISSI_KEA_DSS
:
530 case SEC_OID_MISSI_KEA
:
531 rv
= SecCmsUtilEncryptSymKeyMISSI(poolp
, cert
, bulkkey
,
533 &ri
->ri
.keyTransRecipientInfo
.encKey
,
534 ¶ms
, ri
->cmsg
->pwfn_arg
);
535 if (rv
!= SECSuccess
)
538 /* here, we DO need to pass the params to the wrap function because, with
539 * RSA, there is no funny stuff going on with generation of IV vectors or so */
540 rv
= SECOID_SetAlgorithmID(poolp
, &(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
), certalgtag
, params
);
542 case SEC_OID_X942_DIFFIE_HELMAN_KEY
: /* dh-public-number */
543 rek
= ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
[0];
549 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
550 PORT_Assert(oiok
->identifierType
== SecCmsOriginatorIDOrKeyOriginatorPublicKey
);
552 /* see RFC2630 12.3.1.1 */
553 if (SECOID_SetAlgorithmID(poolp
, &oiok
->id
.originatorPublicKey
.algorithmIdentifier
,
554 SEC_OID_X942_DIFFIE_HELMAN_KEY
, NULL
) != SECSuccess
) {
559 /* this will generate a key pair, compute the shared secret, */
560 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
561 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
562 rv
= SecCmsUtilEncryptSymKeyESDH(poolp
, cert
, bulkkey
,
564 &ri
->ri
.keyAgreeRecipientInfo
.ukm
,
565 &ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
,
566 &oiok
->id
.originatorPublicKey
.publicKey
);
571 case SEC_OID_EC_PUBLIC_KEY
:
572 /* These were set up in nss_cmsrecipientinfo_create() */
573 kari
= &ri
->ri
.keyAgreeRecipientInfo
;
574 rek
= kari
->recipientEncryptedKeys
[0];
580 oiok
= &(kari
->originatorIdentifierOrKey
);
581 PORT_Assert(oiok
->identifierType
== SecCmsOriginatorIDOrKeyOriginatorPublicKey
);
584 * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to
585 * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one
586 * explicitly instead of mucking up the login in SECOID_SetAlgorithmID().
588 nullItem
.Data
= nullData
;
590 if (SECOID_SetAlgorithmID(poolp
, &oiok
->id
.originatorPublicKey
.algorithmIdentifier
,
591 SEC_OID_EC_PUBLIC_KEY
, &nullItem
) != SECSuccess
) {
596 /* this will generate a key pair, compute the shared secret, */
597 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
598 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
599 rv
= SecCmsUtilEncryptSymKeyECDH(poolp
, cert
, bulkkey
,
603 &oiok
->id
.originatorPublicKey
.publicKey
);
607 /* other algorithms not supported yet */
608 /* NOTE that we do not support any KEK algorithm */
609 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
615 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
622 #define dprintf(args...)
624 #define dprintf(args...) fprintf(stderr, args)
628 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri
, int subIndex
,
629 SecCertificateRef cert
, SecPrivateKeyRef privkey
, SECOidTag bulkalgtag
)
631 SecSymmetricKeyRef bulkkey
= NULL
;
632 SECAlgorithmID
*encalg
;
634 CSSM_DATA_PTR enckey
;
637 ri
->cert
= CERT_DupCertificate(cert
);
638 /* mark the recipientInfo so we can find it later */
640 switch (ri
->recipientInfoType
) {
641 case SecCmsRecipientInfoIDKeyTrans
:
642 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
));
643 enckey
= &(ri
->ri
.keyTransRecipientInfo
.encKey
); /* ignore subIndex */
645 case SEC_OID_PKCS1_RSA_ENCRYPTION
:
646 /* RSA encryption algorithm: */
647 /* get the symmetric (bulk) key by unwrapping it using our private key */
648 bulkkey
= SecCmsUtilDecryptSymKeyRSA(privkey
, enckey
, bulkalgtag
);
651 case SEC_OID_NETSCAPE_SMIME_KEA
:
652 /* FORTEZZA key exchange algorithm */
653 /* the supplemental data is in the parameters of encalg */
654 encalg
= &(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
);
655 bulkkey
= SecCmsUtilDecryptSymKeyMISSI(privkey
, enckey
, encalg
, bulkalgtag
, ri
->cmsg
->pwfn_arg
);
659 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
663 case SecCmsRecipientInfoIDKeyAgree
:
664 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
));
666 case SEC_OID_X942_DIFFIE_HELMAN_KEY
:
667 /* Diffie-Helman key exchange */
668 /* XXX not yet implemented */
669 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
670 /* we support ephemeral-static DH only, so if the recipientinfo */
671 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
672 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
673 /* content encryption key using a Unwrap op */
674 /* the derive operation has to generate the key using the algorithm in RFC2631 */
675 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
677 case SEC_OID_DH_SINGLE_STD_SHA1KDF
:
679 /* ephemeral-static ECDH */
680 enckey
= &(ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
[subIndex
]->encKey
);
681 encalg
= &(ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
);
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 error
= SEC_ERROR_LIBRARY_FAILURE
;
689 SecCmsOriginatorPublicKey
*opk
= &oiok
->id
.originatorPublicKey
;
690 /* FIXME - verify opk->algorithmIdentifier here? */
691 CSSM_DATA senderPubKey
= opk
->publicKey
;
692 CSSM_DATA_PTR ukm
= &kari
->ukm
;
693 bulkkey
= SecCmsUtilDecryptSymKeyECDH(privkey
, enckey
, ukm
, encalg
, bulkalgtag
, &senderPubKey
);
697 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
701 case SecCmsRecipientInfoIDKEK
:
702 /* not supported yet */
703 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
707 /* XXXX continue here */
711 PORT_SetError(error
);