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>
50 nss_cmsrecipientinfo_usessubjectkeyid(SecCmsRecipientInfoRef ri
)
52 if (ri
->recipientInfoType
== SecCmsRecipientInfoIDKeyTrans
) {
53 SecCmsRecipientIdentifier
*rid
;
54 rid
= &ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
;
55 if (rid
->identifierType
== SecCmsRecipientIDSubjectKeyID
) {
63 SecCmsRecipientInfoRef
64 nss_cmsrecipientinfo_create(SecCmsMessageRef cmsg
, SecCmsRecipientIDSelector type
,
65 SecCertificateRef cert
, SecPublicKeyRef pubKey
,
66 CSSM_DATA_PTR subjKeyID
)
68 SecCmsRecipientInfoRef ri
;
71 OSStatus rv
= SECSuccess
;
72 SecCmsRecipientEncryptedKey
*rek
;
73 SecCmsOriginatorIdentifierOrKey
*oiok
;
74 unsigned long version
;
77 const SECAlgorithmID
*algid
;
78 SecCmsRecipientIdentifier
*rid
;
82 mark
= PORT_ArenaMark(poolp
);
84 ri
= (SecCmsRecipientInfoRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsRecipientInfo
));
89 if (type
== SecCmsRecipientIDIssuerSN
)
91 ri
->cert
= CERT_DupCertificate(cert
);
94 rv
= SecCertificateGetAlgorithmID(cert
,&algid
);
97 rv
= SecKeyGetAlgorithmID(pubKey
,&algid
);
100 certalgtag
= SECOID_GetAlgorithmTag(algid
);
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
) {
112 } else if (type
== SecCmsRecipientIDSubjectKeyID
){
113 SecCmsKeyTransRecipientInfoEx
*riExtra
;
115 rid
->id
.subjectKeyID
= PORT_ArenaNew(poolp
, CSSM_DATA
);
116 if (rid
->id
.subjectKeyID
== NULL
) {
118 PORT_SetError(SEC_ERROR_NO_MEMORY
);
121 SECITEM_CopyItem(poolp
, rid
->id
.subjectKeyID
, subjKeyID
);
122 if (rid
->id
.subjectKeyID
->Data
== NULL
) {
124 PORT_SetError(SEC_ERROR_NO_MEMORY
);
127 riExtra
= &ri
->ri
.keyTransRecipientInfoEx
;
128 riExtra
->version
= 0;
129 riExtra
->pubKey
= SECKEY_CopyPublicKey(pubKey
);
130 if (riExtra
->pubKey
== NULL
) {
132 PORT_SetError(SEC_ERROR_NO_MEMORY
);
136 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
) {
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
) {
158 case SEC_OID_X942_DIFFIE_HELMAN_KEY
: /* dh-public-number */
159 PORT_Assert(type
!= SecCmsRecipientIDSubjectKeyID
);
160 if (type
== SecCmsRecipientIDSubjectKeyID
) {
164 /* a key agreement op */
165 ri
->recipientInfoType
= SecCmsRecipientInfoIDKeyAgree
;
167 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.id
.issuerAndSN
== NULL
) {
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 */
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 */
181 /* force single recipientEncryptedKey for now */
182 if ((rek
= SecCmsRecipientEncryptedKeyCreate(poolp
)) == NULL
) {
187 /* hardcoded IssuerSN choice for now */
188 rek
->recipientIdentifier
.identifierType
= SecCmsKeyAgreeRecipientIDIssuerSN
;
189 if ((rek
->recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
) {
194 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
196 /* see RFC2630 12.3.1.1 */
197 oiok
->identifierType
= SecCmsOriginatorIDOrKeyOriginatorPublicKey
;
199 rv
= SecCmsArrayAdd(poolp
, (void ***)&ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
,
204 case SEC_OID_EC_PUBLIC_KEY
:
205 /* ephemeral-static ECDH - issuerAndSN, OriginatorPublicKey only */
206 PORT_Assert(type
!= SecCmsRecipientIDSubjectKeyID
);
207 if (type
== SecCmsRecipientIDSubjectKeyID
) {
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
) {
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 */
224 /* force single recipientEncryptedKey for now */
225 if ((rek
= SecCmsRecipientEncryptedKeyCreate(poolp
)) == NULL
) {
230 /* hardcoded IssuerSN choice for now */
231 rek
->recipientIdentifier
.identifierType
= SecCmsKeyAgreeRecipientIDIssuerSN
;
232 if ((rek
->recipientIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
) {
237 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
239 /* see RFC 3278 3.1.1 */
240 oiok
->identifierType
= SecCmsOriginatorIDOrKeyOriginatorPublicKey
;
242 rv
= SecCmsArrayAdd(poolp
, (void ***)&ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
,
248 /* other algorithms not supported yet */
249 /* NOTE that we do not support any KEK algorithm */
250 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
255 if (rv
== SECFailure
)
259 switch (ri
->recipientInfoType
) {
260 case SecCmsRecipientInfoIDKeyTrans
:
261 if (ri
->ri
.keyTransRecipientInfo
.recipientIdentifier
.identifierType
== SecCmsRecipientIDIssuerSN
)
262 version
= SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN
;
264 version
= SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY
;
265 dummy
= SEC_ASN1EncodeInteger(poolp
, &(ri
->ri
.keyTransRecipientInfo
.version
), version
);
269 case SecCmsRecipientInfoIDKeyAgree
:
270 dummy
= SEC_ASN1EncodeInteger(poolp
, &(ri
->ri
.keyAgreeRecipientInfo
.version
),
271 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION
);
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
);
285 PORT_ArenaUnmark (poolp
, mark
);
288 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
295 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
297 PORT_ArenaRelease (poolp
, mark
);
302 * SecCmsRecipientInfoCreate - create a recipientinfo
304 * we currently do not create KeyAgreement recipientinfos with multiple
305 * recipientEncryptedKeys the certificate is supposed to have been
306 * verified by the caller
308 SecCmsRecipientInfoRef
309 SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg
, SecCertificateRef cert
)
311 return nss_cmsrecipientinfo_create(cmsg
, SecCmsRecipientIDIssuerSN
, cert
,
315 SecCmsRecipientInfoRef
316 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg
,
317 CSSM_DATA_PTR subjKeyID
,
318 SecPublicKeyRef pubKey
)
320 return nss_cmsrecipientinfo_create(cmsg
, SecCmsRecipientIDSubjectKeyID
,
321 NULL
, pubKey
, subjKeyID
);
324 SecCmsRecipientInfoRef
325 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsMessageRef cmsg
,
326 SecCertificateRef cert
)
328 SecPublicKeyRef pubKey
= NULL
;
329 CSSM_DATA subjKeyID
= {0, NULL
};
330 SecCmsRecipientInfoRef retVal
= NULL
;
332 if (!cmsg
|| !cert
) {
335 pubKey
= CERT_ExtractPublicKey(cert
);
339 if (CERT_FindSubjectKeyIDExtension(cert
, &subjKeyID
) != SECSuccess
||
340 subjKeyID
.Data
== NULL
) {
343 retVal
= SecCmsRecipientInfoCreateWithSubjKeyID(cmsg
, &subjKeyID
, pubKey
);
346 SECKEY_DestroyPublicKey(pubKey
);
349 SECITEM_FreeItem(&subjKeyID
, PR_FALSE
);
355 SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri
)
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
);
362 if (nss_cmsrecipientinfo_usessubjectkeyid(ri
)) {
363 SecCmsKeyTransRecipientInfoEx
*extra
;
364 extra
= &ri
->ri
.keyTransRecipientInfoEx
;
366 SECKEY_DestroyPublicKey(extra
->pubKey
);
369 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
374 SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri
)
376 unsigned long version
;
377 CSSM_DATA_PTR versionitem
= NULL
;
379 switch (ri
->recipientInfoType
) {
380 case SecCmsRecipientInfoIDKeyTrans
:
381 /* ignore subIndex */
382 versionitem
= &(ri
->ri
.keyTransRecipientInfo
.version
);
384 case SecCmsRecipientInfoIDKEK
:
385 /* ignore subIndex */
386 versionitem
= &(ri
->ri
.kekRecipientInfo
.version
);
388 case SecCmsRecipientInfoIDKeyAgree
:
389 versionitem
= &(ri
->ri
.keyAgreeRecipientInfo
.version
);
393 PORT_Assert(versionitem
);
394 if (versionitem
== NULL
)
397 /* always take apart the CSSM_DATA */
398 if (SEC_ASN1DecodeInteger(versionitem
, &version
) != SECSuccess
)
405 SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri
, int subIndex
)
407 CSSM_DATA_PTR enckey
= NULL
;
409 switch (ri
->recipientInfoType
) {
410 case SecCmsRecipientInfoIDKeyTrans
:
411 /* ignore subIndex */
412 enckey
= &(ri
->ri
.keyTransRecipientInfo
.encKey
);
414 case SecCmsRecipientInfoIDKEK
:
415 /* ignore subIndex */
416 enckey
= &(ri
->ri
.kekRecipientInfo
.encKey
);
418 case SecCmsRecipientInfoIDKeyAgree
:
419 enckey
= &(ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
[subIndex
]->encKey
);
427 SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri
)
429 SECOidTag encalgtag
= SEC_OID_UNKNOWN
; /* an invalid encryption alg */
431 switch (ri
->recipientInfoType
) {
432 case SecCmsRecipientInfoIDKeyTrans
:
433 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
));
435 case SecCmsRecipientInfoIDKeyAgree
:
436 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
));
438 case SecCmsRecipientInfoIDKEK
:
439 encalgtag
= SECOID_GetAlgorithmTag(&(ri
->ri
.kekRecipientInfo
.keyEncAlg
));
446 SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri
, SecSymmetricKeyRef bulkkey
,
447 SECOidTag bulkalgtag
)
449 SecCertificateRef cert
;
450 SECOidTag certalgtag
;
451 OSStatus rv
= SECSuccess
;
453 CSSM_DATA_PTR params
= NULL
;
455 SecCmsRecipientEncryptedKey
*rek
;
456 SecCmsOriginatorIdentifierOrKey
*oiok
;
457 const SECAlgorithmID
*algid
;
459 SecCmsKeyTransRecipientInfoEx
*extra
= NULL
;
460 Boolean usesSubjKeyID
;
461 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
463 SecCmsKeyAgreeRecipientInfo
*kari
;
465 poolp
= ri
->cmsg
->poolp
;
467 usesSubjKeyID
= nss_cmsrecipientinfo_usessubjectkeyid(ri
);
469 rv
= SecCertificateGetAlgorithmID(cert
,&algid
);
472 certalgtag
= SECOID_GetAlgorithmTag(algid
);
473 } else if (usesSubjKeyID
) {
474 extra
= &ri
->ri
.keyTransRecipientInfoEx
;
476 PORT_Assert(extra
->pubKey
);
477 if (!extra
->pubKey
) {
478 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
481 rv
= SecKeyGetAlgorithmID(extra
->pubKey
,&algid
);
484 certalgtag
= SECOID_GetAlgorithmTag(algid
);
486 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
490 /* XXX set ri->recipientInfoType to the proper value here */
491 /* or should we look if it's been set already ? */
493 certalgtag
= SECOID_GetAlgorithmTag(algid
);
494 switch (certalgtag
) {
495 case SEC_OID_PKCS1_RSA_ENCRYPTION
:
496 /* wrap the symkey */
498 rv
= SecCmsUtilEncryptSymKeyRSA(poolp
, cert
, bulkkey
,
499 &ri
->ri
.keyTransRecipientInfo
.encKey
);
500 if (rv
!= SECSuccess
)
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
)
510 rv
= SECOID_SetAlgorithmID(poolp
, &(ri
->ri
.keyTransRecipientInfo
.keyEncAlg
), certalgtag
, NULL
);
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
,
518 &ri
->ri
.keyTransRecipientInfo
.encKey
,
519 ¶ms
, ri
->cmsg
->pwfn_arg
);
520 if (rv
!= SECSuccess
)
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
);
527 case SEC_OID_X942_DIFFIE_HELMAN_KEY
: /* dh-public-number */
528 rek
= ri
->ri
.keyAgreeRecipientInfo
.recipientEncryptedKeys
[0];
534 oiok
= &(ri
->ri
.keyAgreeRecipientInfo
.originatorIdentifierOrKey
);
535 PORT_Assert(oiok
->identifierType
== SecCmsOriginatorIDOrKeyOriginatorPublicKey
);
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
) {
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
,
549 &ri
->ri
.keyAgreeRecipientInfo
.ukm
,
550 &ri
->ri
.keyAgreeRecipientInfo
.keyEncAlg
,
551 &oiok
->id
.originatorPublicKey
.publicKey
);
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];
565 oiok
= &(kari
->originatorIdentifierOrKey
);
566 PORT_Assert(oiok
->identifierType
== SecCmsOriginatorIDOrKeyOriginatorPublicKey
);
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().
573 nullItem
.Data
= nullData
;
575 if (SECOID_SetAlgorithmID(poolp
, &oiok
->id
.originatorPublicKey
.algorithmIdentifier
,
576 SEC_OID_EC_PUBLIC_KEY
, &nullItem
) != SECSuccess
) {
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
,
588 &oiok
->id
.originatorPublicKey
.publicKey
);
589 /* this is a BIT STRING */
590 oiok
->id
.originatorPublicKey
.publicKey
.Length
<<= 3;
594 /* other algorithms not supported yet */
595 /* NOTE that we do not support any KEK algorithm */
596 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
602 SECKEY_DestroySubjectPublicKeyInfo(freeSpki
);
609 #define dprintf(args...)
611 #define dprintf(args...) printf(args)
615 SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri
, int subIndex
,
616 SecCertificateRef cert
, SecPrivateKeyRef privkey
, SECOidTag bulkalgtag
)
618 SecSymmetricKeyRef bulkkey
= NULL
;
619 SECAlgorithmID
*encalg
;
621 CSSM_DATA_PTR enckey
;
624 ri
->cert
= CERT_DupCertificate(cert
);
625 /* mark the recipientInfo so we can find it later */
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 */
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
);
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
);
646 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
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
);
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
;
666 case SEC_OID_DH_SINGLE_STD_SHA1KDF
:
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");
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
);
685 error
= SEC_ERROR_UNSUPPORTED_KEYALG
;
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
;
698 /* XXXX continue here */