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 public key crypto
44 #include <security_asn1/secasn1.h>
45 #include <security_asn1/secerr.h>
46 #include <Security/SecCertificatePriv.h>
47 #include <Security/SecKeyPriv.h>
48 #include <Security/Security.h>
49 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
50 #include <Security/SecCmsBase.h>
51 #include <Security/secasn1t.h>
52 #include <security_asn1/plarenas.h>
53 #include <Security/keyTemplates.h>
55 /* ====== RSA ======================================================================= */
58 * SecCmsUtilEncryptSymKeyRSA - wrap a symmetric key with RSA
60 * this function takes a symmetric key and encrypts it using an RSA public key
61 * according to PKCS#1 and RFC2633 (S/MIME)
64 SecCmsUtilEncryptSymKeyRSA(PLArenaPool
*poolp
, SecCertificateRef cert
,
65 SecSymmetricKeyRef bulkkey
,
69 SecPublicKeyRef publickey
;
71 rv
= SecCertificateCopyPublicKey(cert
,&publickey
);
72 if (publickey
== NULL
)
75 rv
= SecCmsUtilEncryptSymKeyRSAPubKey(poolp
, publickey
, bulkkey
, encKey
);
81 SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool
*poolp
,
82 SecPublicKeyRef publickey
,
83 SecSymmetricKeyRef bulkkey
, CSSM_DATA_PTR encKey
)
86 unsigned int data_len
;
90 mark
= PORT_ArenaMark(poolp
);
96 keyType
= SECKEY_GetPublicKeyType(publickey
);
97 PORT_Assert(keyType
== rsaKey
);
98 if (keyType
!= rsaKey
) {
102 /* allocate memory for the encrypted key */
103 rv
= SecKeyGetStrengthInBits(publickey
, NULL
, &data_len
);
107 // Convert length to bytes;
109 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, data_len
);
110 encKey
->Length
= data_len
;
111 if (encKey
->Data
== NULL
)
114 /* encrypt the key now */
115 rv
= WRAP_PubWrapSymKey(publickey
, bulkkey
, encKey
);
116 if (rv
!= SECSuccess
)
119 PORT_ArenaUnmark(poolp
, mark
);
124 PORT_ArenaRelease(poolp
, mark
);
130 * SecCmsUtilDecryptSymKeyRSA - unwrap a RSA-wrapped symmetric key
132 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
133 * key handle. Please note that the actual unwrapped key data may not be allowed to leave
134 * a hardware token...
137 SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECOidTag bulkalgtag
)
140 return WRAP_PubUnwrapSymKey(privkey
, encKey
, bulkalgtag
);
144 // @@@ Implement Fortezza and Diffie hellman support
146 /* ====== MISSI (Fortezza) ========================================================== */
148 extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams
[];
151 SecCmsUtilEncryptSymKeyMISSI(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef bulkkey
,
152 SECOidTag symalgtag
, CSSM_DATA_PTR encKey
, CSSM_DATA_PTR
*pparams
, void *pwfn_arg
)
154 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
155 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
156 OSStatus rv
= SECFailure
;
157 CSSM_DATA_PTR params
= NULL
;
159 SecSymmetricKeyRef tek
;
160 SecCertificateRef ourCert
;
161 SecPublicKeyRef ourPubKey
, *publickey
= NULL
;
162 SecPrivateKeyRef ourPrivKey
= NULL
;
163 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
164 SecCmsSMIMEKEAParameters keaParams
;
165 PLArenaPool
*arena
= NULL
;
166 extern const SecAsn1Template
*nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate
);
167 const SECAlgorithmID
*algid
;
169 /* Clear keaParams, since cleanup code checks the lengths */
170 (void) memset(&keaParams
, 0, sizeof(keaParams
));
172 SecCertificateGetAlgorithmID(cert
,&algid
);
173 certalgtag
= SECOID_GetAlgorithmTag(algid
);
174 PORT_Assert(certalgtag
== SEC_OID_MISSI_KEA_DSS_OLD
||
175 certalgtag
== SEC_OID_MISSI_KEA_DSS
||
176 certalgtag
== SEC_OID_MISSI_KEA
);
178 #define SMIME_FORTEZZA_RA_LENGTH 128
179 #define SMIME_FORTEZZA_IV_LENGTH 24
180 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
182 /* We really want to show our KEA tag as the key exchange algorithm tag. */
183 encalgtag
= SEC_OID_NETSCAPE_SMIME_KEA
;
185 /* Get the public key of the recipient. */
186 publickey
= CERT_ExtractPublicKey(cert
);
187 if (publickey
== NULL
) goto loser
;
189 /* Find our own cert, and extract its keys. */
190 ourCert
= PK11_FindBestKEAMatch(cert
, pwfn_arg
);
191 if (ourCert
== NULL
) goto loser
;
193 arena
= PORT_NewArena(1024);
197 ourPubKey
= CERT_ExtractPublicKey(ourCert
);
198 if (ourPubKey
== NULL
) {
199 CERT_DestroyCertificate(ourCert
);
203 /* While we're here, copy the public key into the outgoing
205 SECITEM_CopyItem(arena
, &(keaParams
.originatorKEAKey
), &(ourPubKey
->u
.fortezza
.KEAKey
));
206 SECKEY_DestroyPublicKey(ourPubKey
);
209 /* Extract our private key in order to derive the KEA key. */
210 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
, pwfn_arg
);
211 CERT_DestroyCertificate(ourCert
); /* we're done with this */
215 /* Prepare raItem with 128 bytes (filled with zeros). */
216 keaParams
.originatorRA
.Data
= (unsigned char *)PORT_ArenaAlloc(arena
,SMIME_FORTEZZA_RA_LENGTH
);
217 keaParams
.originatorRA
.Length
= SMIME_FORTEZZA_RA_LENGTH
;
219 /* Generate the TEK (token exchange key) which we use
220 * to wrap the bulk encryption key. (keaparams.originatorRA) will be
221 * filled with a random seed which we need to send to
222 * the recipient. (user keying material in RFC2630/DSA speak) */
223 tek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
224 &keaParams
.originatorRA
, NULL
,
225 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
226 CKA_WRAP
, 0, pwfn_arg
);
228 SECKEY_DestroyPublicKey(publickey
);
229 SECKEY_DestroyPrivateKey(ourPrivKey
);
236 /* allocate space for the wrapped key data */
237 encKey
->Data
= (unsigned char *)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
238 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
240 if (encKey
->Data
== NULL
) {
245 /* Wrap the bulk key. What we do with the resulting data
246 depends on whether we're using Skipjack to wrap the key. */
247 switch (PK11_AlgtagToMechanism(symalgtag
)) {
248 case CKM_SKIPJACK_CBC64
:
249 case CKM_SKIPJACK_ECB64
:
250 case CKM_SKIPJACK_OFB64
:
251 case CKM_SKIPJACK_CFB64
:
252 case CKM_SKIPJACK_CFB32
:
253 case CKM_SKIPJACK_CFB16
:
254 case CKM_SKIPJACK_CFB8
:
255 /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
256 err
= PK11_WrapSymKey(CKM_SKIPJACK_WRAP
, NULL
, tek
, bulkkey
, encKey
);
257 whichKEA
= SecCmsKEAUsesSkipjack
;
260 /* Not SKIPJACK, we encrypt the raw key data */
261 keaParams
.nonSkipjackIV
.Data
=
262 (unsigned char *)PORT_ArenaAlloc(arena
, SMIME_FORTEZZA_IV_LENGTH
);
263 keaParams
.nonSkipjackIV
.Length
= SMIME_FORTEZZA_IV_LENGTH
;
264 err
= PK11_WrapSymKey(CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
, tek
, bulkkey
, encKey
);
265 if (err
!= SECSuccess
)
268 if (encKey
->Length
!= PK11_GetKeyLength(bulkkey
)) {
269 /* The size of the encrypted key is not the same as
270 that of the original bulk key, presumably due to
271 padding. Encode and store the real size of the
273 if (SEC_ASN1EncodeInteger(arena
, &keaParams
.bulkKeySize
, PK11_GetKeyLength(bulkkey
)) == NULL
)
274 err
= (OSStatus
)PORT_GetError();
276 /* use full template for encoding */
277 whichKEA
= SecCmsKEAUsesNonSkipjackWithPaddedEncKey
;
280 /* enc key length == bulk key length */
281 whichKEA
= SecCmsKEAUsesNonSkipjack
;
287 if (err
!= SECSuccess
)
290 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
292 /* Encode the KEA parameters into the recipient info. */
293 params
= SEC_ASN1EncodeItem(poolp
, NULL
, &keaParams
, nss_cms_get_kea_template(whichKEA
));
297 /* pass back the algorithm params */
304 PORT_FreeArena(arena
, PR_FALSE
);
306 SECKEY_DestroyPublicKey(publickey
);
308 SECKEY_DestroyPrivateKey(ourPrivKey
);
313 SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
315 /* fortezza: do a key exchange */
317 CK_MECHANISM_TYPE bulkType
;
318 SecSymmetricKeyRef tek
;
319 SecPublicKeyRef originatorPubKey
;
320 SecCmsSMIMEKEAParameters keaParams
;
321 SecSymmetricKeyRef bulkkey
;
324 (void) memset(&keaParams
, 0, sizeof(keaParams
));
326 /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
327 All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
329 /* Decode the KEA algorithm parameters. */
330 err
= SEC_ASN1DecodeItem(NULL
, &keaParams
, NSS_SMIMEKEAParamTemplateAllParams
,
331 &(keyEncAlg
->parameters
));
332 if (err
!= SECSuccess
)
335 /* get originator's public key */
336 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
337 keaParams
.originatorKEAKey
.Length
);
338 if (originatorPubKey
== NULL
)
341 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
342 The Derive function generates a shared secret and combines it with the originatorRA
343 data to come up with an unique session key */
344 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
345 &keaParams
.originatorRA
, NULL
,
346 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
347 CKA_WRAP
, 0, pwfn_arg
);
348 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
352 /* Now that we have the TEK, unwrap the bulk key
353 with which to decrypt the message. We have to
354 do one of two different things depending on
355 whether Skipjack was used for *bulk* encryption
357 bulkType
= PK11_AlgtagToMechanism(bulkalgtag
);
359 case CKM_SKIPJACK_CBC64
:
360 case CKM_SKIPJACK_ECB64
:
361 case CKM_SKIPJACK_OFB64
:
362 case CKM_SKIPJACK_CFB64
:
363 case CKM_SKIPJACK_CFB32
:
364 case CKM_SKIPJACK_CFB16
:
365 case CKM_SKIPJACK_CFB8
:
366 /* Skipjack is being used as the bulk encryption algorithm.*/
367 /* Unwrap the bulk key. */
368 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
369 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
372 /* Skipjack was not used for bulk encryption of this
373 message. Use Skipjack CBC64, with the nonSkipjackIV
374 part of the KEA key parameters, to decrypt
375 the bulk key. If the optional parameter bulkKeySize is present,
376 bulk key size is different than the encrypted key size */
377 if (keaParams
.bulkKeySize
.Length
> 0) {
378 err
= SEC_ASN1DecodeItem(NULL
, &bulkLength
,
379 SEC_ASN1_GET(SEC_IntegerTemplate
),
380 &keaParams
.bulkKeySize
);
381 if (err
!= SECSuccess
)
385 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
,
386 encKey
, bulkType
, CKA_DECRYPT
, bulkLength
);
394 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
397 SecCmsUtilEncryptSymKeyESDH(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef key
,
398 CSSM_DATA_PTR encKey
, CSSM_DATA_PTR ukm
, SECAlgorithmID
*keyEncAlg
,
399 CSSM_DATA_PTR pubKey
)
401 #if 0 /* not yet done */
402 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
403 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
405 CSSM_DATA_PTR params
= NULL
;
408 SecSymmetricKeyRef tek
;
409 SecCertificateRef ourCert
;
410 SecPublicKeyRef ourPubKey
;
411 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
413 certalgtag
= SECOID_GetAlgorithmTag(&(cert
->subjectPublicKeyInfo
.algorithm
));
414 PORT_Assert(certalgtag
== SEC_OID_X942_DIFFIE_HELMAN_KEY
);
416 /* We really want to show our KEA tag as the key exchange algorithm tag. */
417 encalgtag
= SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
;
419 /* Get the public key of the recipient. */
420 publickey
= CERT_ExtractPublicKey(cert
);
421 if (publickey
== NULL
) goto loser
;
423 /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
424 /* XXXX */ourCert
= PK11_FindBestKEAMatch(cert
, wincx
);
425 if (ourCert
== NULL
) goto loser
;
427 arena
= PORT_NewArena(1024);
428 if (arena
== NULL
) goto loser
;
430 /* While we're here, extract the key pair's public key data and copy it into */
431 /* the outgoing parameters. */
432 /* XXXX */ourPubKey
= CERT_ExtractPublicKey(ourCert
);
433 if (ourPubKey
== NULL
)
437 SECITEM_CopyItem(arena
, pubKey
, /* XXX */&(ourPubKey
->u
.fortezza
.KEAKey
));
438 SECKEY_DestroyPublicKey(ourPubKey
); /* we only need the private key from now on */
441 /* Extract our private key in order to derive the KEA key. */
442 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
,wincx
);
443 CERT_DestroyCertificate(ourCert
); /* we're done with this */
444 if (!ourPrivKey
) goto loser
;
446 /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
448 ukm
->Data
= (unsigned char*)PORT_ArenaZAlloc(arena
,/* XXXX */);
449 ukm
->Length
= /* XXXX */;
452 /* Generate the KEK (key exchange key) according to RFC2631 which we use
453 * to wrap the bulk encryption key. */
454 kek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
456 /* XXXX */CKM_KEA_KEY_DERIVE
, /* XXXX */CKM_SKIPJACK_WRAP
,
459 SECKEY_DestroyPublicKey(publickey
);
460 SECKEY_DestroyPrivateKey(ourPrivKey
);
467 /* allocate space for the encrypted CEK (bulk key) */
468 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
469 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
471 if (encKey
->Data
== NULL
)
478 /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
479 /* bulk encryption algorithm */
480 switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo
->encalg
))
482 case /* XXXX */CKM_SKIPJACK_CFB8
:
483 err
= PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP
, NULL
, kek
, bulkkey
, encKey
);
484 whichKEA
= SecCmsKEAUsesSkipjack
;
486 case /* XXXX */CKM_SKIPJACK_CFB8
:
487 err
= PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP
, NULL
, kek
, bulkkey
, encKey
);
488 whichKEA
= SecCmsKEAUsesSkipjack
;
491 /* XXXX what do we do here? Neither RC2 nor 3DES... */
497 CFRelease(kek
); /* we do not need the KEK anymore */
498 if (err
!= SECSuccess
)
501 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
503 /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
504 /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
505 params
= SEC_ASN1EncodeItem(arena
, NULL
, &keaParams
, sec_pkcs7_get_kea_template(whichKEA
));
509 /* now set keyEncAlg */
510 rv
= SECOID_SetAlgorithmID(poolp
, keyEncAlg
, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
, params
);
511 if (rv
!= SECSuccess
)
514 /* XXXXXXX this is not right yet */
517 PORT_FreeArena(arena
, PR_FALSE
);
520 SECKEY_DestroyPublicKey(publickey
);
523 SECKEY_DestroyPrivateKey(ourPrivKey
);
530 SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
532 #if 0 /* not yet done */
534 CK_MECHANISM_TYPE bulkType
;
535 SecSymmetricKeyRef tek
;
536 SecPublicKeyRef originatorPubKey
;
537 SecCmsSMIMEKEAParameters keaParams
;
539 /* XXXX get originator's public key */
540 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
541 keaParams
.originatorKEAKey
.Length
);
542 if (originatorPubKey
== NULL
)
545 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
546 The Derive function generates a shared secret and combines it with the originatorRA
547 data to come up with an unique session key */
548 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
549 &keaParams
.originatorRA
, NULL
,
550 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
551 CKA_WRAP
, 0, pwfn_arg
);
552 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
556 /* Now that we have the TEK, unwrap the bulk key
557 with which to decrypt the message. */
558 /* Skipjack is being used as the bulk encryption algorithm.*/
559 /* Unwrap the bulk key. */
560 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
561 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
570 #endif /* Fortezza, DIffie-Hellman */
572 #define CFRELEASE(cf) if(cf != NULL) { CFRelease(cf); }
574 /* ====== ECDH (Ephemeral-Static Diffie-Hellman) ==================================== */
576 #pragma mark ---- ECDH support functions ----
579 #define CSSM_PERROR(f, r)
580 #define dprintf(args...)
582 #define CSSM_PERROR(f, r) cssmPerror(f, r)
583 #define dprintf(args...) fprintf(stderr, args)
586 /* Length of KeyAgreeRecipientInfo.ukm we create */
589 /* KEK algorithm info we generate */
590 #define ECDH_KEK_ALG_TAG SEC_OID_DES_EDE3_CBC
591 #define ECDH_KEK_KEY_CSSM_ALGID CSSM_ALGID_3DES_3KEY
592 #define ECDH_KEK_ENCR_CSSM_ALGID CSSM_ALGID_3DES_3KEY_EDE
593 #define ECDH_KEK_KEY_LEN_BYTES 24
594 #define ECDH_KEK_IV_LEN_BYTES 8
596 #define CMS_DUMP_BUFS 0
605 printf("%s:\n ", label
);
606 for(dex
=0; dex
<cd
->Length
; dex
++) {
607 printf("%02X ", cd
->Data
[dex
]);
608 if(((dex
% 16) == 15) && (dex
!= (cd
->Length
- 1))) {
616 #define dumpBuf(l, d)
617 #endif /* CMS_DUMP_BUFS */
620 * The ECC-CMS-SharedInfo struct, as defined in RFC 3278 8.2, and the
621 * template for DER encoding and decoding it.
624 SECAlgorithmID algId
; /* KEK alg, NULL params */
625 CSSM_DATA entityUInfo
; /* optional, ukm */
626 CSSM_DATA suppPubInfo
; /* length of KEK in bits as 4-byte integer */
627 } ECC_CMS_SharedInfo
;
629 static const SecAsn1Template ECC_CMS_SharedInfoTemplate
[] = {
630 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(ECC_CMS_SharedInfo
) },
631 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 0,
632 offsetof(ECC_CMS_SharedInfo
,entityUInfo
),
633 kSecAsn1OctetStringTemplate
},
634 { SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 2,
635 offsetof(ECC_CMS_SharedInfo
,suppPubInfo
),
636 kSecAsn1OctetStringTemplate
},
641 * Given a context specified via a CSSM_CC_HANDLE, add a new
642 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
643 * AttributeLength, and an untyped pointer.
645 /* specify either 32-bit integer or a pointer as an added attribute value */
651 static CSSM_RETURN
cmsAddContextAttribute(
652 CSSM_CC_HANDLE CCHandle
,
653 uint32 AttributeType
,
654 uint32 AttributeLength
,
655 ContextAttrType attrType
,
656 /* specify exactly one of these */
657 const void *AttributePtr
,
660 CSSM_CONTEXT_ATTRIBUTE newAttr
;
663 newAttr
.AttributeType
= AttributeType
;
664 newAttr
.AttributeLength
= AttributeLength
;
665 if(attrType
== CAT_Uint32
) {
666 newAttr
.Attribute
.Uint32
= attributeInt
;
669 /* this is a union of a bunch of different pointers...*/
670 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
672 crtn
= CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
674 CSSM_PERROR("CSSM_UpdateContextAttributes", crtn
);
679 static CSSM_RETURN
cmsGenRand(
680 CSSM_CSP_HANDLE cspHand
,
684 CSSM_CC_HANDLE ccHand
= 0;
685 CSSM_DATA randData
= {len
, randOut
};
687 CSSM_RETURN crtn
= CSSM_CSP_CreateRandomGenContext(cspHand
,
688 CSSM_ALGID_APPLE_YARROW
,
693 CSSM_PERROR("CSSM_CSP_CreateRandomGenContext", crtn
);
696 crtn
= CSSM_GenerateRandom(ccHand
, &randData
);
697 CSSM_DeleteContext(ccHand
);
699 CSSM_PERROR("CSSM_GenerateRandom", crtn
);
704 /* convert uint32 to big-endian 4 bytes */
705 static void int32ToBytes(
710 for(dex
=3; dex
>=0; dex
--) {
717 * NULL wrap a ref key to raw key in default format.
719 static OSStatus
cmsNullWrapKey(
720 CSSM_CSP_HANDLE cspHand
,
721 const CSSM_KEY
*refKey
,
724 CSSM_DATA descData
= {0, 0};
726 CSSM_CC_HANDLE ccHand
;
727 CSSM_ACCESS_CREDENTIALS creds
;
730 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
731 memset(rawKey
, 0, sizeof(CSSM_KEY
));
733 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
737 NULL
, // unwrappingKey
743 CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", crtn
);
747 keyAttr
= rawKey
->KeyHeader
.KeyAttr
;
748 keyAttr
&= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
|
749 CSSM_KEYATTR_MODIFIABLE
);
750 keyAttr
|= CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
751 crtn
= CSSM_WrapKey(ccHand
,
756 if(crtn
!= CSSM_OK
) {
757 CSSM_PERROR("CSSM_WrapKey", crtn
);
759 CSSM_DeleteContext(ccHand
);
764 * Free memory via specified plugin's app-level allocator
766 static void cmsFreeCssmMemory(
770 CSSM_API_MEMORY_FUNCS memFuncs
;
771 CSSM_RETURN crtn
= CSSM_GetAPIMemoryFunctions(hand
, &memFuncs
);
775 memFuncs
.free_func(p
, memFuncs
.AllocRef
);
779 * Given an OID tag, return key size and mode.
780 * NOTE: ciphers with variable key sizes, like RC2, RC4, and RC5 cannot
781 * be used here because the message does not contain a key size
784 static OSStatus
encrAlgInfo(
786 uint32
*keySizeBits
, /* RETURNED */
787 CSSM_ENCRYPT_MODE
*mode
) /* RETURNED */
789 *keySizeBits
= 64; /* default */
790 *mode
= CSSM_ALGMODE_CBCPadIV8
; /* default */
793 case SEC_OID_RC2_CBC
:
795 case SEC_OID_RC5_CBC_PAD
:
796 dprintf("encrAlgInfo: key size unknowable\n");
797 return errSecDataNotAvailable
;
799 case SEC_OID_DES_EDE3_CBC
:
802 case SEC_OID_DES_EDE
:
803 /* Not sure about this; SecCmsCipherContextStart() treats this
804 * like SEC_OID_DES_EDE3_CBC... */
805 case SEC_OID_DES_ECB
:
806 *mode
= CSSM_ALGMODE_ECB
;
808 case SEC_OID_DES_CBC
:
809 *mode
= CSSM_ALGMODE_CBC
;
811 case SEC_OID_AES_128_CBC
:
814 case SEC_OID_AES_192_CBC
:
817 case SEC_OID_AES_256_CBC
:
820 case SEC_OID_AES_128_ECB
:
822 *mode
= CSSM_ALGMODE_ECB
;
824 case SEC_OID_AES_192_ECB
:
826 *mode
= CSSM_ALGMODE_ECB
;
828 case SEC_OID_AES_256_ECB
:
830 *mode
= CSSM_ALGMODE_ECB
;
832 case SEC_OID_DES_OFB
:
833 *mode
= CSSM_ALGMODE_OFB
;
835 case SEC_OID_DES_CFB
:
836 *mode
= CSSM_ALGMODE_CFB
;
839 dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag
);
840 return errSecDataNotAvailable
;
845 #pragma mark ---- ECDH CEK key wrap ----
848 * Encrypt bulk encryption key (a.k.a. content encryption key, CEK) using ECDH
851 SecCmsUtilEncryptSymKeyECDH(
853 SecCertificateRef cert
, /* recipient's cert */
854 SecSymmetricKeyRef key
, /* bulk key */
855 /* remaining fields RETURNED */
856 CSSM_DATA_PTR encKey
, /* encrypted key --> recipientEncryptedKeys[0].EncryptedKey */
857 CSSM_DATA_PTR ukm
, /* random UKM --> KeyAgreeRecipientInfo.ukm */
858 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
859 * params := another encoded AlgId, with the KEK alg and IV */
860 CSSM_DATA_PTR pubKey
) /* our pub key as ECPoint -->
861 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
864 CSSM_KEY ourPrivKeyCssm
;
865 CSSM_KEY ourPubKeyCssm
;
866 SecKeyRef theirPubKeyRef
= NULL
;
867 CSSM_KEY_PTR theirPubKeyCssm
= NULL
;
868 const CSSM_KEY
*cekCssmRef
= NULL
;
869 uint32 ecdhKeySizeBits
;
870 CSSM_CSP_HANDLE rawCspHand
= SecCspHandleForAlgorithm(CSSM_ALGID_ECDH
);
871 CSSM_CC_HANDLE ccHand
= 0;
873 CSSM_DATA keyLabel
= {8, (uint8
*)"tempKey"};
874 SECAlgorithmID kekAlgId
;
875 uint8 iv
[ECDH_KEK_IV_LEN_BYTES
];
876 CSSM_DATA ivData
= {ECDH_KEK_IV_LEN_BYTES
, iv
};
878 ECC_CMS_SharedInfo sharedInfo
;
879 CSSM_DATA sharedInfoEnc
= {0, NULL
};
880 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
881 uint8 keyLenAsBytes
[4];
884 CSSM_CL_HANDLE clHand
;
885 CSSM_ACCESS_CREDENTIALS creds
;
886 CSSM_DATA paramData
= {0, NULL
};
888 CSSM_CSP_HANDLE refCspHand
;
889 CSSM_SIZE bytesEncrypted
;
890 CSSM_DATA remData
= {0, NULL
};
891 CSSM_DATA ctext
= {0, NULL
};
892 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKey
;
894 if(rawCspHand
== 0) {
895 return internalComponentErr
;
898 memset(&ourPrivKeyCssm
, 0, sizeof(CSSM_KEY
));
899 memset(&ourPubKeyCssm
, 0, sizeof(CSSM_KEY
));
900 memset(&cekCssm
, 0, sizeof(CSSM_KEY
));
901 memset(&kekDerive
, 0, sizeof(kekDerive
));
907 * Create our ECDH key pair matching the recipient's key.
908 * Get the public key in "read-only" OCTET_STRING format, which
909 * is the ECPoint we put in
910 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey.
912 rv
= SecCertificateGetData(cert
, &certData
);
914 CSSM_PERROR("SecCertificateGetData", rv
);
917 rv
= SecCertificateGetCLHandle(cert
, &clHand
);
919 CSSM_PERROR("SecCertificateGetCLHandle", rv
);
922 rv
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, &theirPubKeyCssm
);
924 CSSM_PERROR("CSSM_CL_CertGetKeyInfo", rv
);
929 * Verify the EC curve of the recipient's public key. It's in the
930 * public key's AlgId.parameters as an OID. The key we were
931 * given is in CSSM_X509_SUBJECT_PUBLIC_KEY_INFO form.
933 memset(&subjPubKey
, 0, sizeof(subjPubKey
));
934 if(SEC_ASN1DecodeItem(poolp
, &subjPubKey
, kSecAsn1SubjectPublicKeyInfoTemplate
,
935 &theirPubKeyCssm
->KeyData
)) {
936 dprintf("SecCmsUtilEncryptSymKeyECDH: error decoding SubjPubKey\n");
937 /* oh well, keep going */
940 if(subjPubKey
.algorithm
.parameters
.Data
!= NULL
) {
942 if(SEC_ASN1DecodeItem(poolp
, &curveOid
, kSecAsn1ObjectIDTemplate
,
943 &subjPubKey
.algorithm
.parameters
)) {
944 dprintf("SecCmsUtilEncryptSymKeyECDH: error decoding curveOid\n");
945 /* oh well, keep going */
948 /* We have the curve OID. Any other errors are fatal. */
949 SECOidTag oidTag
= SECOID_FindOIDTag(&curveOid
);
951 case SEC_OID_SECP_256_R1
:
952 case SEC_OID_SECP_384_R1
:
953 case SEC_OID_SECP_521_R1
:
956 dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported curveOid\n");
957 rv
= CSSMERR_CSP_INVALID_KEY
;
964 ecdhKeySizeBits
= theirPubKeyCssm
->KeyHeader
.LogicalKeySizeInBits
;
965 crtn
= CSSM_CSP_CreateKeyGenContext(rawCspHand
,
975 CSSM_PERROR("CSSM_CSP_CreateKeyGenContext", crtn
);
979 crtn
= cmsAddContextAttribute(ccHand
,
980 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT
,
984 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
);
986 CSSM_PERROR("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn
);
991 crtn
= CSSM_GenerateKeyPair(ccHand
,
993 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
997 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
,
999 NULL
, // CredAndAclEntry
1001 CSSM_DeleteContext(ccHand
);
1004 CSSM_PERROR("CSSM_GenerateKeyPair", crtn
);
1008 pubKey
->Length
= ourPubKeyCssm
.KeyData
.Length
;
1009 pubKey
->Data
= (uint8
*)PORT_ArenaAlloc(poolp
, pubKey
->Length
);
1010 memmove(pubKey
->Data
, ourPubKeyCssm
.KeyData
.Data
, pubKey
->Length
);
1011 dumpBuf("sender's public key", pubKey
);
1014 * Cook up random UKM
1016 ukm
->Data
= (uint8
*)PORT_ArenaAlloc(poolp
, UKM_LENGTH
);
1017 ukm
->Length
= UKM_LENGTH
;
1018 crtn
= cmsGenRand(rawCspHand
, UKM_LENGTH
, ukm
->Data
);
1022 dumpBuf("sender UKM", ukm
);
1025 * OK, we have to set up a weird SECAlgorithmID.
1026 * algorithm = dhSinglePass-stdDH-sha1kdf-scheme
1027 * params = an encoded SECAlgorithmID representing the KEK algorithm, with
1028 * algorithm = whatever we pick
1029 * parameters = IV as octet string (though I haven't seen that specified
1030 * anywhere; it's how the CEK IV is encoded)
1032 * First, the 8-byte random IV, encoded as octet string
1034 crtn
= cmsGenRand(rawCspHand
, ECDH_KEK_IV_LEN_BYTES
, iv
);
1038 dumpBuf("sender IV", &ivData
);
1040 memset(&kekAlgId
, 0, sizeof(kekAlgId
));
1041 if (!SEC_ASN1EncodeItem(poolp
, &kekAlgId
.parameters
,
1042 &ivData
, kSecAsn1OctetStringTemplate
)) {
1043 rv
= internalComponentErr
;
1047 /* Drop in the KEK OID and encode the whole thing */
1048 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
1049 if(kekOid
== NULL
) {
1050 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
1051 rv
= internalComponentErr
;
1054 kekAlgId
.algorithm
= kekOid
->oid
;
1055 memset(keyEncAlg
, 0, sizeof(*keyEncAlg
));
1056 if (!SEC_ASN1EncodeItem(poolp
, &keyEncAlg
->parameters
,
1057 &kekAlgId
, SECOID_AlgorithmIDTemplate
)) {
1058 rv
= internalComponentErr
;
1061 kekOid
= SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF
);
1062 if(kekOid
== NULL
) {
1063 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
1064 rv
= internalComponentErr
;
1067 keyEncAlg
->algorithm
= kekOid
->oid
;
1070 * Now in order to derive the KEK proper, we have to create a
1071 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
1072 * encode that struct, the result of which is used as the
1073 * SharedInfo value in the KEK key derive.
1075 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
1076 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
1077 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
1078 sharedInfo
.algId
.parameters
.Data
= nullData
;
1079 sharedInfo
.algId
.parameters
.Length
= 2;
1080 sharedInfo
.entityUInfo
= *ukm
;
1081 int32ToBytes(ECDH_KEK_KEY_LEN_BYTES
<< 3, keyLenAsBytes
);
1082 sharedInfo
.suppPubInfo
.Length
= 4;
1083 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
1084 if (!SEC_ASN1EncodeItem(poolp
, &sharedInfoEnc
,
1085 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
1086 rv
= internalComponentErr
;
1089 dumpBuf("sender encoded SharedInfo", &sharedInfoEnc
);
1092 * Since we're using the raw CSP here, we can provide the "other" public
1093 * key as an actual CSSM_KEY. When unwrapping, we won't be able to do that
1094 * since we'll be using our private key obtained from a SecIdentityRef.
1096 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1097 crtn
= CSSM_CSP_CreateDeriveKeyContext(rawCspHand
,
1098 CSSM_ALGID_ECDH_X963_KDF
,
1099 ECDH_KEK_KEY_CSSM_ALGID
, // algorithm of the KEK
1100 ECDH_KEK_KEY_LEN_BYTES
* 8,
1102 &ourPrivKeyCssm
, // BaseKey
1103 0, // IterationCount
1104 &sharedInfoEnc
, // Salt
1108 CSSM_PERROR("CSSM_CSP_CreateDeriveKeyContext", crtn
);
1113 /* add recipient's pub key as a context attr */
1114 crtn
= cmsAddContextAttribute(ccHand
,
1115 CSSM_ATTRIBUTE_PUBLIC_KEY
,
1118 (void *)theirPubKeyCssm
,
1125 /* Derive the KEK */
1126 crtn
= CSSM_DeriveKey(ccHand
,
1129 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1134 CSSM_PERROR("CSSM_DeriveKey", crtn
);
1138 CSSM_DeleteContext(ccHand
);
1142 * Obtain the raw CEK bits.
1144 rv
= SecKeyGetCSSMKey(key
, &cekCssmRef
);
1146 CSSM_PERROR("SecKeyGetCSSMKey", rv
);
1149 rv
= SecKeyGetCSPHandle(key
, &refCspHand
);
1151 CSSM_PERROR("SecKeyGetCSPHandle", rv
);
1154 rv
= cmsNullWrapKey(refCspHand
, cekCssmRef
, &cekCssm
);
1160 * Finally, encrypt the raw CEK bits with the KEK we just derived
1162 crtn
= CSSM_CSP_CreateSymmetricContext(rawCspHand
,
1163 ECDH_KEK_ENCR_CSSM_ALGID
,
1164 CSSM_ALGMODE_CBCPadIV8
,
1165 NULL
, // access cred
1167 &ivData
, // InitVector
1172 CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", rv
);
1175 rv
= CSSM_EncryptData(ccHand
,
1183 CSSM_PERROR("CSSM_EncryptData", rv
);
1186 encKey
->Data
= PORT_ArenaAlloc(poolp
, bytesEncrypted
);
1187 encKey
->Length
= bytesEncrypted
;
1188 memmove(encKey
->Data
, ctext
.Data
, ctext
.Length
);
1189 if(bytesEncrypted
!= ctext
.Length
) {
1190 memmove(encKey
->Data
+ ctext
.Length
, remData
.Data
, remData
.Length
);
1192 dumpBuf("sender encKey", encKey
);
1196 CSSM_DeleteContext(ccHand
);
1198 CFRELEASE(theirPubKeyRef
);
1199 if(ourPubKeyCssm
.KeyData
.Data
) {
1200 CSSM_FreeKey(rawCspHand
, NULL
, &ourPubKeyCssm
, CSSM_FALSE
);
1202 if(ourPrivKeyCssm
.KeyData
.Data
) {
1203 CSSM_FreeKey(rawCspHand
, NULL
, &ourPrivKeyCssm
, CSSM_FALSE
);
1206 cmsFreeCssmMemory(rawCspHand
, ctext
.Data
);
1209 cmsFreeCssmMemory(rawCspHand
, remData
.Data
);
1211 if(cekCssm
.KeyData
.Data
) {
1212 CSSM_FreeKey(refCspHand
, NULL
, &cekCssm
, CSSM_FALSE
);
1214 if(kekDerive
.KeyData
.Data
) {
1215 CSSM_FreeKey(rawCspHand
, NULL
, &kekDerive
, CSSM_FALSE
);
1217 if(theirPubKeyCssm
) {
1218 /* Allocated by CL */
1219 cmsFreeCssmMemory(clHand
, theirPubKeyCssm
->KeyData
.Data
);
1220 cmsFreeCssmMemory(clHand
, theirPubKeyCssm
);
1225 #pragma mark ---- ECDH CEK key unwrap ----
1228 SecCmsUtilDecryptSymKeyECDH(
1229 SecPrivateKeyRef privkey
, /* our private key */
1230 CSSM_DATA_PTR encKey
, /* encrypted CEK */
1231 CSSM_DATA_PTR ukm
, /* random UKM from KeyAgreeRecipientInfo.ukm */
1232 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
1233 * params := another encoded AlgId, with the KEK alg and IV */
1234 SECOidTag bulkalgtag
, /* algorithm of returned key */
1235 CSSM_DATA_PTR pubKey
) /* sender's pub key as ECPoint from
1236 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
1239 SecSymmetricKeyRef outKey
= NULL
;
1240 OSStatus rv
= noErr
;
1241 const CSSM_KEY
*ourPrivKeyCssm
;
1242 PLArenaPool
*pool
= NULL
;
1243 SECAlgorithmID keyAlgParam
;
1244 SECOidData
*kekOid
= NULL
;
1245 CSSM_DATA iv
= {0, NULL
};
1246 ECC_CMS_SharedInfo sharedInfo
;
1247 CSSM_DATA sharedInfoEnc
= {0, NULL
};
1248 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
1249 uint8 keyLenAsBytes
[4];
1250 CSSM_ENCRYPT_MODE kekMode
;
1254 CSSM_ACCESS_CREDENTIALS creds
;
1255 CSSM_CSP_HANDLE refCspHand
;
1256 CSSM_CC_HANDLE ccHand
= 0;
1257 CSSM_DATA keyLabel
= {8, (uint8
*)"tempKey"};
1258 const CSSM_ACCESS_CREDENTIALS
*accessCred
;
1259 CSSM_KEY wrappedKey
;
1260 CSSM_KEY unwrappedKey
;
1261 CSSM_ALGORITHMS bulkAlg
;
1262 CSSM_DATA descriptiveData
= {0, NULL
};
1264 dumpBuf("receiver encKey", encKey
);
1266 memset(&kekDerive
, 0, sizeof(kekDerive
));
1268 /* our private key in CSSM form */
1269 rv
= SecKeyGetCSSMKey(privkey
, &ourPrivKeyCssm
);
1271 CSSM_PERROR("SecKeyGetCSSMKey", rv
);
1276 * Decode keyEncAlg.params to get KEK algorithm and IV
1278 pool
= PORT_NewArena(1024);
1282 memset(&keyAlgParam
, 0, sizeof(keyAlgParam
));
1283 if(SEC_ASN1DecodeItem(pool
, &keyAlgParam
, SECOID_AlgorithmIDTemplate
,
1284 &keyEncAlg
->parameters
)) {
1285 dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n");
1288 kekOid
= SECOID_FindOID(&keyAlgParam
.algorithm
);
1289 if(kekOid
== NULL
) {
1290 dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n");
1293 rv
= encrAlgInfo(kekOid
->offset
, &kekSizeBits
, &kekMode
);
1297 /* IV is OCTET STRING in the alg params */
1298 if(SEC_ASN1DecodeItem(pool
, &iv
, kSecAsn1OctetStringTemplate
,
1299 &keyAlgParam
.parameters
)) {
1301 * Not sure here - is it legal to have no IV? I haven't seen this
1302 * addressed in any spec. Maybe we should condition the behavior
1303 * here on the KEK algorithm.
1305 dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n");
1310 * Now in order to derive the KEK proper, we have to create a
1311 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
1312 * encode that struct, the result of which is used as the
1313 * SharedInfo value in the KEK key derive.
1315 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
1316 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
1317 sharedInfo
.algId
.parameters
.Data
= nullData
;
1318 sharedInfo
.algId
.parameters
.Length
= 2;
1319 sharedInfo
.entityUInfo
= *ukm
;
1320 int32ToBytes(kekSizeBits
, keyLenAsBytes
);
1321 sharedInfo
.suppPubInfo
.Length
= 4;
1322 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
1323 if (!SEC_ASN1EncodeItem(pool
, &sharedInfoEnc
,
1324 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
1325 rv
= internalComponentErr
;
1328 dumpBuf("receiver encoded SharedInfo", &sharedInfoEnc
);
1329 dumpBuf("receiver IV", &iv
);
1330 dumpBuf("receiver UKM", ukm
);
1331 dumpBuf("sender's public key", pubKey
);
1334 * Using the Sec-layer CSPDL, "other's" public key specified as ECPOint param. Which
1335 * is fortunate because that's what we have...
1337 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1338 rv
= SecKeyGetCSPHandle(privkey
, &refCspHand
);
1340 CSSM_PERROR("SecKeyGetCSPHandle", rv
);
1343 rv
= SecKeyGetCredentials(privkey
,
1344 CSSM_ACL_AUTHORIZATION_DERIVE
,
1345 kSecCredentialTypeDefault
,
1348 CSSM_PERROR("SecKeyGetCredentials", rv
);
1351 crtn
= CSSM_CSP_CreateDeriveKeyContext(refCspHand
,
1352 CSSM_ALGID_ECDH_X963_KDF
,
1353 kekOid
->cssmAlgorithm
, // algorithm of the KEK
1356 ourPrivKeyCssm
, // BaseKey
1357 0, // IterationCount
1358 &sharedInfoEnc
, // Salt
1362 CSSM_PERROR("CSSM_CSP_CreateDeriveKeyContext", crtn
);
1365 crtn
= CSSM_DeriveKey(ccHand
,
1368 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
,
1372 CSSM_DeleteContext(ccHand
);
1375 CSSM_PERROR("CSSM_DeriveKey", crtn
);
1380 * Decrypt the encrypted key bits with the KEK key.
1382 crtn
= CSSM_CSP_CreateSymmetricContext(refCspHand
,
1383 kekOid
->cssmAlgorithm
,
1385 NULL
, // access cred
1388 /* FIXME is this variable too? */
1393 CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", rv
);
1397 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
1398 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
1400 bulkAlg
= SECOID_FindyCssmAlgorithmByTag(bulkalgtag
);
1401 if(bulkAlg
== CSSM_ALGID_NONE
) {
1402 dprintf("SecCmsUtilDecryptSymKeyECDH: unknown bulk alg\n");
1406 wrappedKey
.KeyHeader
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
1407 wrappedKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_WRAPPED
;
1408 wrappedKey
.KeyHeader
.Format
= CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
;
1409 wrappedKey
.KeyHeader
.AlgorithmId
= bulkAlg
;
1410 wrappedKey
.KeyHeader
.KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1411 wrappedKey
.KeyHeader
.WrapAlgorithmId
= kekOid
->cssmAlgorithm
;
1412 wrappedKey
.KeyHeader
.WrapMode
= CSSM_ALGMODE_NONE
;
1413 wrappedKey
.KeyData
= *encKey
;
1415 crtn
= CSSM_UnwrapKey(ccHand
,
1416 NULL
, /* publicKey */
1418 CSSM_KEYUSE_DECRYPT
,
1419 CSSM_KEYATTR_EXTRACTABLE
,
1424 CSSM_DeleteContext(ccHand
);
1427 CSSM_PERROR("CSSM_UnwrapKey", crtn
);
1430 rv
= SecKeyCreateWithCSSMKey(&unwrappedKey
, &outKey
);
1432 CSSM_PERROR("SecKeyCreateWithCSSMKey", rv
);
1437 PORT_FreeArena(pool
, PR_FALSE
);
1439 if(kekDerive
.KeyData
.Data
) {
1440 CSSM_FreeKey(refCspHand
, NULL
, &kekDerive
, CSSM_FALSE
);
1442 if(outKey
== NULL
) {
1443 PORT_SetError(SEC_ERROR_NO_KEY
);