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/SecItemPriv.h>
49 #include <Security/Security.h>
50 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
51 #include <Security/SecCmsBase.h>
52 #include <Security/secasn1t.h>
53 #include <security_asn1/plarenas.h>
54 #include <Security/keyTemplates.h>
55 #include <CommonCrypto/CommonCryptor.h>
56 #include <CommonCrypto/CommonRandomSPI.h>
57 #include <CommonCrypto/CommonRandom.h>
59 /* ====== RSA ======================================================================= */
62 * SecCmsUtilEncryptSymKeyRSA - wrap a symmetric key with RSA
64 * this function takes a symmetric key and encrypts it using an RSA public key
65 * according to PKCS#1 and RFC2633 (S/MIME)
68 SecCmsUtilEncryptSymKeyRSA(PLArenaPool
*poolp
, SecCertificateRef cert
,
69 SecSymmetricKeyRef bulkkey
,
72 SecPublicKeyRef publickey
= SecCertificateCopyPublicKey_ios(cert
);
73 if (publickey
== NULL
)
76 OSStatus rv
= SecCmsUtilEncryptSymKeyRSAPubKey(poolp
, publickey
, bulkkey
, encKey
);
82 SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool
*poolp
,
83 SecPublicKeyRef publickey
,
84 SecSymmetricKeyRef bulkkey
, CSSM_DATA_PTR encKey
)
87 unsigned int data_len
;
90 CFDictionaryRef theirKeyAttrs
= NULL
;
92 mark
= PORT_ArenaMark(poolp
);
98 keyType
= SECKEY_GetPublicKeyType(publickey
);
99 PORT_Assert(keyType
== rsaKey
);
100 if (keyType
!= rsaKey
) {
104 /* allocate memory for the encrypted key */
105 theirKeyAttrs
= SecKeyCopyAttributes(publickey
);
106 if (!theirKeyAttrs
) {
110 CFNumberRef keySizeNum
= CFDictionaryGetValue(theirKeyAttrs
, kSecAttrKeySizeInBits
);
111 if (!CFNumberGetValue(keySizeNum
, kCFNumberIntType
, &data_len
)) {
114 // Convert length to bytes;
117 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, data_len
);
118 encKey
->Length
= data_len
;
119 if (encKey
->Data
== NULL
)
122 /* encrypt the key now */
123 rv
= WRAP_PubWrapSymKey(publickey
, bulkkey
, encKey
);
124 if (rv
!= SECSuccess
)
127 PORT_ArenaUnmark(poolp
, mark
);
132 CFRelease(theirKeyAttrs
);
135 PORT_ArenaRelease(poolp
, mark
);
141 * SecCmsUtilDecryptSymKeyRSA - unwrap a RSA-wrapped symmetric key
143 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
144 * key handle. Please note that the actual unwrapped key data may not be allowed to leave
145 * a hardware token...
148 SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECOidTag bulkalgtag
)
151 return WRAP_PubUnwrapSymKey(privkey
, encKey
, bulkalgtag
);
155 // @@@ Implement Fortezza and Diffie hellman support
157 /* ====== MISSI (Fortezza) ========================================================== */
159 extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams
[];
162 SecCmsUtilEncryptSymKeyMISSI(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef bulkkey
,
163 SECOidTag symalgtag
, CSSM_DATA_PTR encKey
, CSSM_DATA_PTR
*pparams
, void *pwfn_arg
)
165 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
166 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
167 OSStatus rv
= SECFailure
;
168 CSSM_DATA_PTR params
= NULL
;
170 SecSymmetricKeyRef tek
;
171 SecCertificateRef ourCert
;
172 SecPublicKeyRef ourPubKey
, *publickey
= NULL
;
173 SecPrivateKeyRef ourPrivKey
= NULL
;
174 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
175 SecCmsSMIMEKEAParameters keaParams
;
176 PLArenaPool
*arena
= NULL
;
177 extern const SecAsn1Template
*nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate
);
178 const SECAlgorithmID
*algid
;
180 /* Clear keaParams, since cleanup code checks the lengths */
181 (void) memset(&keaParams
, 0, sizeof(keaParams
));
183 SecCertificateGetAlgorithmID(cert
,&algid
);
184 certalgtag
= SECOID_GetAlgorithmTag(algid
);
185 PORT_Assert(certalgtag
== SEC_OID_MISSI_KEA_DSS_OLD
||
186 certalgtag
== SEC_OID_MISSI_KEA_DSS
||
187 certalgtag
== SEC_OID_MISSI_KEA
);
189 #define SMIME_FORTEZZA_RA_LENGTH 128
190 #define SMIME_FORTEZZA_IV_LENGTH 24
191 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
193 /* We really want to show our KEA tag as the key exchange algorithm tag. */
194 encalgtag
= SEC_OID_NETSCAPE_SMIME_KEA
;
196 /* Get the public key of the recipient. */
197 publickey
= CERT_ExtractPublicKey(cert
);
198 if (publickey
== NULL
) goto loser
;
200 /* Find our own cert, and extract its keys. */
201 ourCert
= PK11_FindBestKEAMatch(cert
, pwfn_arg
);
202 if (ourCert
== NULL
) goto loser
;
204 arena
= PORT_NewArena(1024);
208 ourPubKey
= CERT_ExtractPublicKey(ourCert
);
209 if (ourPubKey
== NULL
) {
210 CERT_DestroyCertificate(ourCert
);
214 /* While we're here, copy the public key into the outgoing
216 SECITEM_CopyItem(arena
, &(keaParams
.originatorKEAKey
), &(ourPubKey
->u
.fortezza
.KEAKey
));
217 SECKEY_DestroyPublicKey(ourPubKey
);
220 /* Extract our private key in order to derive the KEA key. */
221 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
, pwfn_arg
);
222 CERT_DestroyCertificate(ourCert
); /* we're done with this */
226 /* Prepare raItem with 128 bytes (filled with zeros). */
227 keaParams
.originatorRA
.Data
= (unsigned char *)PORT_ArenaAlloc(arena
,SMIME_FORTEZZA_RA_LENGTH
);
228 keaParams
.originatorRA
.Length
= SMIME_FORTEZZA_RA_LENGTH
;
230 /* Generate the TEK (token exchange key) which we use
231 * to wrap the bulk encryption key. (keaparams.originatorRA) will be
232 * filled with a random seed which we need to send to
233 * the recipient. (user keying material in RFC2630/DSA speak) */
234 tek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
235 &keaParams
.originatorRA
, NULL
,
236 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
237 CKA_WRAP
, 0, pwfn_arg
);
239 SECKEY_DestroyPublicKey(publickey
);
240 SECKEY_DestroyPrivateKey(ourPrivKey
);
247 /* allocate space for the wrapped key data */
248 encKey
->Data
= (unsigned char *)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
249 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
251 if (encKey
->Data
== NULL
) {
256 /* Wrap the bulk key. What we do with the resulting data
257 depends on whether we're using Skipjack to wrap the key. */
258 switch (PK11_AlgtagToMechanism(symalgtag
)) {
259 case CKM_SKIPJACK_CBC64
:
260 case CKM_SKIPJACK_ECB64
:
261 case CKM_SKIPJACK_OFB64
:
262 case CKM_SKIPJACK_CFB64
:
263 case CKM_SKIPJACK_CFB32
:
264 case CKM_SKIPJACK_CFB16
:
265 case CKM_SKIPJACK_CFB8
:
266 /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
267 err
= PK11_WrapSymKey(CKM_SKIPJACK_WRAP
, NULL
, tek
, bulkkey
, encKey
);
268 whichKEA
= SecCmsKEAUsesSkipjack
;
271 /* Not SKIPJACK, we encrypt the raw key data */
272 keaParams
.nonSkipjackIV
.Data
=
273 (unsigned char *)PORT_ArenaAlloc(arena
, SMIME_FORTEZZA_IV_LENGTH
);
274 keaParams
.nonSkipjackIV
.Length
= SMIME_FORTEZZA_IV_LENGTH
;
275 err
= PK11_WrapSymKey(CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
, tek
, bulkkey
, encKey
);
276 if (err
!= SECSuccess
)
279 if (encKey
->Length
!= PK11_GetKeyLength(bulkkey
)) {
280 /* The size of the encrypted key is not the same as
281 that of the original bulk key, presumably due to
282 padding. Encode and store the real size of the
284 if (SEC_ASN1EncodeInteger(arena
, &keaParams
.bulkKeySize
, PK11_GetKeyLength(bulkkey
)) == NULL
)
285 err
= (OSStatus
)PORT_GetError();
287 /* use full template for encoding */
288 whichKEA
= SecCmsKEAUsesNonSkipjackWithPaddedEncKey
;
291 /* enc key length == bulk key length */
292 whichKEA
= SecCmsKEAUsesNonSkipjack
;
298 if (err
!= SECSuccess
)
301 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
303 /* Encode the KEA parameters into the recipient info. */
304 params
= SEC_ASN1EncodeItem(poolp
, NULL
, &keaParams
, nss_cms_get_kea_template(whichKEA
));
308 /* pass back the algorithm params */
315 PORT_FreeArena(arena
, PR_FALSE
);
317 SECKEY_DestroyPublicKey(publickey
);
319 SECKEY_DestroyPrivateKey(ourPrivKey
);
324 SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
326 /* fortezza: do a key exchange */
328 CK_MECHANISM_TYPE bulkType
;
329 SecSymmetricKeyRef tek
;
330 SecPublicKeyRef originatorPubKey
;
331 SecCmsSMIMEKEAParameters keaParams
;
332 SecSymmetricKeyRef bulkkey
;
335 (void) memset(&keaParams
, 0, sizeof(keaParams
));
337 /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
338 All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
340 /* Decode the KEA algorithm parameters. */
341 err
= SEC_ASN1DecodeItem(NULL
, &keaParams
, NSS_SMIMEKEAParamTemplateAllParams
,
342 &(keyEncAlg
->parameters
));
343 if (err
!= SECSuccess
)
346 /* get originator's public key */
347 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
348 keaParams
.originatorKEAKey
.Length
);
349 if (originatorPubKey
== NULL
)
352 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
353 The Derive function generates a shared secret and combines it with the originatorRA
354 data to come up with an unique session key */
355 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
356 &keaParams
.originatorRA
, NULL
,
357 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
358 CKA_WRAP
, 0, pwfn_arg
);
359 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
363 /* Now that we have the TEK, unwrap the bulk key
364 with which to decrypt the message. We have to
365 do one of two different things depending on
366 whether Skipjack was used for *bulk* encryption
368 bulkType
= PK11_AlgtagToMechanism(bulkalgtag
);
370 case CKM_SKIPJACK_CBC64
:
371 case CKM_SKIPJACK_ECB64
:
372 case CKM_SKIPJACK_OFB64
:
373 case CKM_SKIPJACK_CFB64
:
374 case CKM_SKIPJACK_CFB32
:
375 case CKM_SKIPJACK_CFB16
:
376 case CKM_SKIPJACK_CFB8
:
377 /* Skipjack is being used as the bulk encryption algorithm.*/
378 /* Unwrap the bulk key. */
379 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
380 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
383 /* Skipjack was not used for bulk encryption of this
384 message. Use Skipjack CBC64, with the nonSkipjackIV
385 part of the KEA key parameters, to decrypt
386 the bulk key. If the optional parameter bulkKeySize is present,
387 bulk key size is different than the encrypted key size */
388 if (keaParams
.bulkKeySize
.Length
> 0) {
389 err
= SEC_ASN1DecodeItem(NULL
, &bulkLength
,
390 SEC_ASN1_GET(SEC_IntegerTemplate
),
391 &keaParams
.bulkKeySize
);
392 if (err
!= SECSuccess
)
396 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
,
397 encKey
, bulkType
, CKA_DECRYPT
, bulkLength
);
405 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
408 SecCmsUtilEncryptSymKeyESDH(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef key
,
409 CSSM_DATA_PTR encKey
, CSSM_DATA_PTR ukm
, SECAlgorithmID
*keyEncAlg
,
410 CSSM_DATA_PTR pubKey
)
412 #if 0 /* not yet done */
413 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
414 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
416 CSSM_DATA_PTR params
= NULL
;
419 SecSymmetricKeyRef tek
;
420 SecCertificateRef ourCert
;
421 SecPublicKeyRef ourPubKey
;
422 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
424 certalgtag
= SECOID_GetAlgorithmTag(&(cert
->subjectPublicKeyInfo
.algorithm
));
425 PORT_Assert(certalgtag
== SEC_OID_X942_DIFFIE_HELMAN_KEY
);
427 /* We really want to show our KEA tag as the key exchange algorithm tag. */
428 encalgtag
= SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
;
430 /* Get the public key of the recipient. */
431 publickey
= CERT_ExtractPublicKey(cert
);
432 if (publickey
== NULL
) goto loser
;
434 /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
435 /* XXXX */ourCert
= PK11_FindBestKEAMatch(cert
, wincx
);
436 if (ourCert
== NULL
) goto loser
;
438 arena
= PORT_NewArena(1024);
439 if (arena
== NULL
) goto loser
;
441 /* While we're here, extract the key pair's public key data and copy it into */
442 /* the outgoing parameters. */
443 /* XXXX */ourPubKey
= CERT_ExtractPublicKey(ourCert
);
444 if (ourPubKey
== NULL
)
448 SECITEM_CopyItem(arena
, pubKey
, /* XXX */&(ourPubKey
->u
.fortezza
.KEAKey
));
449 SECKEY_DestroyPublicKey(ourPubKey
); /* we only need the private key from now on */
452 /* Extract our private key in order to derive the KEA key. */
453 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
,wincx
);
454 CERT_DestroyCertificate(ourCert
); /* we're done with this */
455 if (!ourPrivKey
) goto loser
;
457 /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
459 ukm
->Data
= (unsigned char*)PORT_ArenaZAlloc(arena
,/* XXXX */);
460 ukm
->Length
= /* XXXX */;
463 /* Generate the KEK (key exchange key) according to RFC2631 which we use
464 * to wrap the bulk encryption key. */
465 kek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
467 /* XXXX */CKM_KEA_KEY_DERIVE
, /* XXXX */CKM_SKIPJACK_WRAP
,
470 SECKEY_DestroyPublicKey(publickey
);
471 SECKEY_DestroyPrivateKey(ourPrivKey
);
478 /* allocate space for the encrypted CEK (bulk key) */
479 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
480 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
482 if (encKey
->Data
== NULL
)
489 /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
490 /* bulk encryption algorithm */
491 switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo
->encalg
))
493 case /* XXXX */CKM_SKIPJACK_CFB8
:
494 err
= PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP
, NULL
, kek
, bulkkey
, encKey
);
495 whichKEA
= SecCmsKEAUsesSkipjack
;
497 case /* XXXX */CKM_SKIPJACK_CFB8
:
498 err
= PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP
, NULL
, kek
, bulkkey
, encKey
);
499 whichKEA
= SecCmsKEAUsesSkipjack
;
502 /* XXXX what do we do here? Neither RC2 nor 3DES... */
508 CFRelease(kek
); /* we do not need the KEK anymore */
509 if (err
!= SECSuccess
)
512 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
514 /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
515 /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
516 params
= SEC_ASN1EncodeItem(arena
, NULL
, &keaParams
, sec_pkcs7_get_kea_template(whichKEA
));
520 /* now set keyEncAlg */
521 rv
= SECOID_SetAlgorithmID(poolp
, keyEncAlg
, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
, params
);
522 if (rv
!= SECSuccess
)
525 /* XXXXXXX this is not right yet */
528 PORT_FreeArena(arena
, PR_FALSE
);
531 SECKEY_DestroyPublicKey(publickey
);
534 SECKEY_DestroyPrivateKey(ourPrivKey
);
541 SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
543 #if 0 /* not yet done */
545 CK_MECHANISM_TYPE bulkType
;
546 SecSymmetricKeyRef tek
;
547 SecPublicKeyRef originatorPubKey
;
548 SecCmsSMIMEKEAParameters keaParams
;
550 /* XXXX get originator's public key */
551 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
552 keaParams
.originatorKEAKey
.Length
);
553 if (originatorPubKey
== NULL
)
556 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
557 The Derive function generates a shared secret and combines it with the originatorRA
558 data to come up with an unique session key */
559 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
560 &keaParams
.originatorRA
, NULL
,
561 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
562 CKA_WRAP
, 0, pwfn_arg
);
563 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
567 /* Now that we have the TEK, unwrap the bulk key
568 with which to decrypt the message. */
569 /* Skipjack is being used as the bulk encryption algorithm.*/
570 /* Unwrap the bulk key. */
571 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
572 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
581 #endif /* Fortezza, DIffie-Hellman */
583 #define CFRELEASE(cf) if(cf != NULL) { CFRelease(cf); }
585 /* ====== ECDH (Ephemeral-Static Diffie-Hellman) ==================================== */
587 #pragma mark ---- ECDH support functions ----
590 #define CSSM_PERROR(f, r)
591 #define dprintf(args...)
593 #define CSSM_PERROR(f, r) cssmPerror(f, r)
594 #define dprintf(args...) fprintf(stderr, args)
597 /* Length of KeyAgreeRecipientInfo.ukm we create */
600 /* KEK algorithm info we generate */
601 #define ECDH_KEK_ALG_TAG SEC_OID_DES_EDE3_CBC
602 #define ECDH_KEK_KEY_CSSM_ALGID CSSM_ALGID_3DES_3KEY
603 #define ECDH_KEK_ENCR_CSSM_ALGID CSSM_ALGID_3DES_3KEY_EDE
604 #define ECDH_KEK_KEY_LEN_BYTES 24
605 #define ECDH_KEK_IV_LEN_BYTES 8
607 #define CMS_DUMP_BUFS 0
616 printf("%s:\n ", label
);
617 for(dex
=0; dex
<cd
->Length
; dex
++) {
618 printf("%02X ", cd
->Data
[dex
]);
619 if(((dex
% 16) == 15) && (dex
!= (cd
->Length
- 1))) {
627 #define dumpBuf(l, d)
628 #endif /* CMS_DUMP_BUFS */
631 * The ECC-CMS-SharedInfo struct, as defined in RFC 3278 8.2, and the
632 * template for DER encoding and decoding it.
635 SECAlgorithmID algId
; /* KEK alg, NULL params */
636 CSSM_DATA entityUInfo
; /* optional, ukm */
637 CSSM_DATA suppPubInfo
; /* length of KEK in bits as 4-byte integer */
638 } ECC_CMS_SharedInfo
;
640 static const SecAsn1Template ECC_CMS_SharedInfoTemplate
[] = {
641 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(ECC_CMS_SharedInfo
) },
642 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 0,
643 offsetof(ECC_CMS_SharedInfo
,entityUInfo
),
644 kSecAsn1OctetStringTemplate
},
645 { SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 2,
646 offsetof(ECC_CMS_SharedInfo
,suppPubInfo
),
647 kSecAsn1OctetStringTemplate
},
652 * Given a context specified via a CSSM_CC_HANDLE, add a new
653 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
654 * AttributeLength, and an untyped pointer.
656 /* specify either 32-bit integer or a pointer as an added attribute value */
662 /* convert uint32 to big-endian 4 bytes */
663 static void int32ToBytes(
668 for(dex
=3; dex
>=0; dex
--) {
675 * Given an OID tag, return key size and mode.
676 * NOTE: ciphers with variable key sizes, like RC2, RC4, and RC5 cannot
677 * be used here because the message does not contain a key size
680 static OSStatus
encrAlgInfo(
682 uint32
*keySizeBits
, /* RETURNED */
683 CCAlgorithm
*algorithm
, /* RETURNED */
684 CCOptions
*options
) /* RETURNED */
686 *keySizeBits
= 64; /* default */
687 *options
= kCCOptionPKCS7Padding
; /* default */
690 case SEC_OID_RC2_CBC
:
692 case SEC_OID_RC5_CBC_PAD
:
693 dprintf("encrAlgInfo: key size unknowable\n");
694 return errSecDataNotAvailable
;
695 case SEC_OID_DES_EDE
:
696 /* Not sure about this; SecCmsCipherContextStart() treats this
697 * like SEC_OID_DES_EDE3_CBC... */
698 *options
= kCCOptionECBMode
;
700 case SEC_OID_DES_EDE3_CBC
:
702 *algorithm
= kCCAlgorithm3DES
;
704 case SEC_OID_DES_ECB
:
705 *options
= kCCOptionECBMode
;
707 case SEC_OID_DES_CBC
:
708 *algorithm
= kCCAlgorithmDES
;
710 case SEC_OID_AES_128_CBC
:
712 *algorithm
= kCCAlgorithmAES
;
714 case SEC_OID_AES_192_CBC
:
716 *algorithm
= kCCAlgorithmAES
;
718 case SEC_OID_AES_256_CBC
:
720 *algorithm
= kCCAlgorithmAES
;
722 case SEC_OID_AES_128_ECB
:
724 *algorithm
= kCCAlgorithmAES
;
725 *options
= kCCOptionECBMode
;
727 case SEC_OID_AES_192_ECB
:
729 *algorithm
= kCCAlgorithmAES
;
730 *options
= kCCOptionECBMode
;
732 case SEC_OID_AES_256_ECB
:
734 *algorithm
= kCCAlgorithmAES
;
735 *options
= kCCOptionECBMode
;
738 dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag
);
739 return errSecDataNotAvailable
;
744 #pragma mark ---- ECDH CEK key wrap ----
747 * Encrypt bulk encryption key (a.k.a. content encryption key, CEK) using ECDH
750 SecCmsUtilEncryptSymKeyECDH(
752 SecCertificateRef cert
, /* recipient's cert */
753 SecSymmetricKeyRef key
, /* bulk key */
754 /* remaining fields RETURNED */
755 CSSM_DATA_PTR encKey
, /* encrypted key --> recipientEncryptedKeys[0].EncryptedKey */
756 CSSM_DATA_PTR ukm
, /* random UKM --> KeyAgreeRecipientInfo.ukm */
757 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
758 * params := another encoded AlgId, with the KEK alg and IV */
759 CSSM_DATA_PTR pubKey
) /* our pub key as ECPoint -->
760 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
763 SecKeyRef theirPubKey
= NULL
, ourPubKey
= NULL
, ourPrivKey
= NULL
;
764 CFDictionaryRef theirKeyAttrs
= NULL
, ourKeyParams
= NULL
, kekParams
= NULL
;
765 uint8_t iv
[ECDH_KEK_IV_LEN_BYTES
];
766 CSSM_DATA ivData
= { ECDH_KEK_IV_LEN_BYTES
, iv
};
767 SECAlgorithmID kekAlgId
;
769 ECC_CMS_SharedInfo sharedInfo
;
770 CSSM_DATA sharedInfoEnc
= {0, NULL
};
771 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
772 uint8 keyLenAsBytes
[4];
773 CFDataRef sharedInfoData
= NULL
, kekData
= NULL
, ourPubData
= NULL
;
774 CFNumberRef kekLen
= NULL
;
775 CFErrorRef error
= NULL
;
776 CCCryptorRef ciphercc
= NULL
;
781 /* Copy the recipient's static public ECDH key */
783 theirPubKey
= SecCertificateCopyPublicKey(cert
);
785 rv
= SecCertificateCopyPublicKey(cert
, &theirPubKey
);
787 if (rv
|| !theirPubKey
) {
788 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get public key from cert, %d\n", (int)rv
);
792 theirKeyAttrs
= SecKeyCopyAttributes(theirPubKey
);
793 if (!theirKeyAttrs
) {
794 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get key attributes\n");
798 CFStringRef keyType
= NULL
;
799 CFNumberRef keySizeNum
= NULL
;
800 keyType
= CFDictionaryGetValue(theirKeyAttrs
, kSecAttrKeyType
);
801 keySizeNum
= CFDictionaryGetValue(theirKeyAttrs
, kSecAttrKeySizeInBits
);
803 if (!CFEqual(kSecAttrKeyTypeECSECPrimeRandom
, keyType
)) {
804 dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported key type\n");
805 rv
= CSSMERR_CSP_INVALID_KEY
;
809 /* Generate ephemeral ECDH key */
810 const void *keys
[] = { kSecAttrKeyType
, kSecAttrKeySizeInBits
, kSecAttrNoLegacy
};
811 const void *values
[] = { keyType
, keySizeNum
, kCFBooleanTrue
};
812 ourKeyParams
= CFDictionaryCreate(NULL
, keys
, values
, 3,
813 &kCFTypeDictionaryKeyCallBacks
,
814 &kCFTypeDictionaryValueCallBacks
);
815 rv
= SecKeyGeneratePair(ourKeyParams
, &ourPubKey
, &ourPrivKey
);
816 if (rv
|| !ourPubKey
|| !ourPrivKey
) {
817 dprintf("SecKeyGeneratePair: unable to generate ECDH key pair, %d\n", (int)rv
);
822 ukm
->Data
= PORT_Alloc(UKM_LENGTH
);
823 ukm
->Length
= UKM_LENGTH
;
824 rv
= CCRandomCopyBytes(kCCRandomDefault
, ukm
->Data
, UKM_LENGTH
);
825 if (rv
|| !ukm
->Data
) {
826 dprintf("CCRandomGenerateBytes failed, %d", (int)rv
);
831 * OK, we have to set up a weird SECAlgorithmID.
832 * algorithm = dhSinglePass-stdDH-sha1kdf-scheme
833 * params = an encoded SECAlgorithmID representing the KEK algorithm, with
834 * algorithm = whatever we pick
835 * parameters = IV as octet string (though I haven't seen that specified
836 * anywhere; it's how the CEK IV is encoded)
839 /* Generate 8-byte IV */
840 rv
= CCRandomCopyBytes(kCCRandomDefault
, iv
, ECDH_KEK_IV_LEN_BYTES
);
842 dprintf("CCRandomGenerateBytes failed, %d", (int)rv
);
845 dumpBuf("sender IV", &ivData
);
847 memset(&kekAlgId
, 0, sizeof(kekAlgId
));
848 if (!SEC_ASN1EncodeItem(poolp
, &kekAlgId
.parameters
,
849 &ivData
, kSecAsn1OctetStringTemplate
)) {
850 rv
= internalComponentErr
;
854 /* Drop in the KEK OID and encode the whole thing */
855 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
857 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
858 rv
= internalComponentErr
;
861 kekAlgId
.algorithm
= kekOid
->oid
;
862 memset(keyEncAlg
, 0, sizeof(*keyEncAlg
));
863 if (!SEC_ASN1EncodeItem(poolp
, &keyEncAlg
->parameters
,
864 &kekAlgId
, SECOID_AlgorithmIDTemplate
)) {
865 rv
= internalComponentErr
;
868 kekOid
= SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF
);
870 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
871 rv
= internalComponentErr
;
874 keyEncAlg
->algorithm
= kekOid
->oid
;
877 * Now in order to derive the KEK proper, we have to create a
878 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
879 * encode that struct, the result of which is used as the
880 * SharedInfo value in the KEK key derive.
882 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
883 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
884 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
885 sharedInfo
.algId
.parameters
.Data
= nullData
;
886 sharedInfo
.algId
.parameters
.Length
= 2;
887 sharedInfo
.entityUInfo
= *ukm
;
888 int32ToBytes(ECDH_KEK_KEY_LEN_BYTES
<< 3, keyLenAsBytes
);
889 sharedInfo
.suppPubInfo
.Length
= 4;
890 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
891 if (!SEC_ASN1EncodeItem(poolp
, &sharedInfoEnc
,
892 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
893 rv
= internalComponentErr
;
896 dumpBuf("sender encoded SharedInfo", &sharedInfoEnc
);
899 sharedInfoData
= CFDataCreate(NULL
, sharedInfoEnc
.Data
, sharedInfoEnc
.Length
);
900 int32_t ecdh_key_key_len
= ECDH_KEK_KEY_LEN_BYTES
;
901 kekLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &ecdh_key_key_len
);
902 const void *kekKeys
[] = { kSecKeyKeyExchangeParameterRequestedSize
, kSecKeyKeyExchangeParameterSharedInfo
};
903 const void *kekValues
[] = { kekLen
, sharedInfoData
};
904 kekParams
= CFDictionaryCreate(NULL
, kekKeys
, kekValues
, 2,
905 &kCFTypeDictionaryKeyCallBacks
,
906 &kCFTypeDictionaryValueCallBacks
);
907 kekData
= SecKeyCopyKeyExchangeResult(ourPrivKey
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
,
908 theirPubKey
, kekParams
, &error
);
910 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
915 * Encrypt the raw CEK bits with the KEK we just derived
917 rv
= CCCryptorCreate(kCCEncrypt
, kCCAlgorithm3DES
, kCCOptionPKCS7Padding
,
918 CFDataGetBytePtr(kekData
), CFDataGetLength(kekData
), iv
, &ciphercc
);
920 dprintf("CCCryptorCreate failed: %d\n", (int)rv
);
924 rv
= cmsNullWrapKey(key
, &cek
);
926 dprintf("SecKeyGetCSSMKey failed: %d\n", (int)rv
);
929 size_t expectedEncKeyLength
= CCCryptorGetOutputLength(ciphercc
, cek
.KeyData
.Length
, true);
930 encKey
->Data
= PORT_ArenaAlloc(poolp
, expectedEncKeyLength
);
931 size_t bytes_output
= 0;
932 rv
= CCCryptorUpdate(ciphercc
, cek
.KeyData
.Data
, cek
.KeyData
.Length
, encKey
->Data
, expectedEncKeyLength
, &bytes_output
);
934 dprintf("CCCryptorUpdate failed: %d\n", (int)rv
);
937 size_t final_bytes_output
= 0;
938 rv
= CCCryptorFinal(ciphercc
, encKey
->Data
+bytes_output
, expectedEncKeyLength
- bytes_output
, &final_bytes_output
);
940 dprintf("CCCryptorFinal failed: %d\n", (int)rv
);
943 encKey
->Length
= bytes_output
+ final_bytes_output
;
945 /* Provide our ephemeral public key to the caller */
946 ourPubData
= SecKeyCopyExternalRepresentation(ourPubKey
, &error
);
948 dprintf("SecKeyCopyExternalRepresentation failed\n");
951 pubKey
->Length
= CFDataGetLength(ourPubData
);
952 pubKey
->Data
= malloc(pubKey
->Length
);
954 memcpy(pubKey
->Data
, CFDataGetBytePtr(ourPubData
), pubKey
->Length
);
958 /* pubKey is bit string, convert here */
959 pubKey
->Length
<<= 3;
962 if (theirPubKey
) { CFRelease(theirPubKey
); }
963 if (theirKeyAttrs
) { CFRelease(theirKeyAttrs
); }
964 if (ourKeyParams
) { CFRelease(ourKeyParams
); }
965 if (ourPubKey
) { CFRelease(ourPubKey
); }
966 if (ourPrivKey
) { CFRelease(ourPrivKey
); }
967 if (sharedInfoData
) { CFRelease(sharedInfoData
); }
968 if (kekLen
) { CFRelease(kekLen
); }
969 if (kekParams
) { CFRelease(kekParams
); }
970 if (kekData
) { CFRelease(kekData
); }
971 if (error
) { CFRelease(error
); }
972 if (ciphercc
) { CCCryptorRelease(ciphercc
); }
973 if (ourPubData
) { CFRelease(ourPubData
); }
974 if (rv
&& encKey
->Data
) {
975 PORT_Free(encKey
->Data
);
979 if (rv
&& ukm
->Data
) {
980 PORT_Free(ukm
->Data
);
988 #pragma mark ---- ECDH CEK key unwrap ----
991 SecCmsUtilDecryptSymKeyECDH(
992 SecPrivateKeyRef privkey
, /* our private key */
993 CSSM_DATA_PTR encKey
, /* encrypted CEK */
994 CSSM_DATA_PTR ukm
, /* random UKM from KeyAgreeRecipientInfo.ukm */
995 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
996 * params := another encoded AlgId, with the KEK alg and IV */
997 SECOidTag bulkalgtag
, /* algorithm of returned key */
998 CSSM_DATA_PTR pubKey
) /* sender's pub key as ECPoint from
999 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
1001 SecSymmetricKeyRef outKey
= NULL
;
1002 OSStatus rv
= noErr
;
1003 PLArenaPool
*pool
= NULL
;
1004 SECAlgorithmID keyAlgParam
;
1005 SECOidData
*kekOid
= NULL
;
1006 CSSM_DATA iv
= {0, NULL
};
1007 ECC_CMS_SharedInfo sharedInfo
;
1008 CSSM_DATA sharedInfoEnc
= {0, NULL
};
1009 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
1010 uint8 keyLenAsBytes
[4];
1012 SecKeyRef theirPubKey
= NULL
;
1013 CFStringRef keyType
= NULL
;
1014 CFDictionaryRef theirKeyAttrs
= NULL
, kekParams
= NULL
;
1015 CFMutableDictionaryRef cekParams
= NULL
;
1016 CFDataRef sharedInfoData
= NULL
, theirPubData
= NULL
, kekData
= NULL
, cekData
= NULL
;
1017 CFNumberRef kekLen
= NULL
, theirKeyLen
= NULL
;
1018 CFErrorRef error
= NULL
;
1020 CCOptions options
= 0;
1021 CCCryptorRef ciphercc
= NULL
;
1022 size_t theirKeySizeInBits
= 0;
1025 * Decode keyEncAlg.params to get KEK algorithm and IV
1027 pool
= PORT_NewArena(1024);
1031 memset(&keyAlgParam
, 0, sizeof(keyAlgParam
));
1032 if(SEC_ASN1DecodeItem(pool
, &keyAlgParam
, SECOID_AlgorithmIDTemplate
,
1033 &keyEncAlg
->parameters
)) {
1034 dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n");
1037 kekOid
= SECOID_FindOID(&keyAlgParam
.algorithm
);
1038 if(kekOid
== NULL
) {
1039 dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n");
1042 rv
= encrAlgInfo(kekOid
->offset
, &kekSizeBits
, &alg
, &options
);
1046 /* IV is OCTET STRING in the alg params */
1047 if(SEC_ASN1DecodeItem(pool
, &iv
, kSecAsn1OctetStringTemplate
,
1048 &keyAlgParam
.parameters
)) {
1050 * Not sure here - is it legal to have no IV? I haven't seen this
1051 * addressed in any spec. Maybe we should condition the behavior
1052 * here on the KEK algorithm.
1054 dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n");
1059 * Now in order to derive the KEK proper, we have to create a
1060 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
1061 * encode that struct, the result of which is used as the
1062 * SharedInfo value in the KEK key derive.
1064 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
1065 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
1066 sharedInfo
.algId
.parameters
.Data
= nullData
;
1067 sharedInfo
.algId
.parameters
.Length
= 2;
1068 sharedInfo
.entityUInfo
= *ukm
;
1069 int32ToBytes(kekSizeBits
, keyLenAsBytes
);
1070 sharedInfo
.suppPubInfo
.Length
= 4;
1071 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
1072 if (!SEC_ASN1EncodeItem(pool
, &sharedInfoEnc
,
1073 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
1074 rv
= internalComponentErr
;
1077 dumpBuf("receiver encoded SharedInfo", &sharedInfoEnc
);
1078 dumpBuf("receiver IV", &iv
);
1079 dumpBuf("receiver UKM", ukm
);
1080 dumpBuf("sender's public key", pubKey
);
1082 /* pubKey is bit string, convert here */
1083 theirKeySizeInBits
= pubKey
->Length
;
1084 pubKey
->Length
= (theirKeySizeInBits
+ 7) >> 3;
1085 theirPubData
= CFDataCreate(NULL
, pubKey
->Data
, pubKey
->Length
);
1086 theirKeyLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &theirKeySizeInBits
);
1087 const void *keys
[] = { kSecAttrKeyType
, kSecAttrKeyClass
, kSecAttrKeySizeInBits
};
1088 const void *values
[] = { kSecAttrKeyTypeECSECPrimeRandom
, kSecAttrKeyClassPublic
, theirKeyLen
};
1089 theirKeyAttrs
= CFDictionaryCreate(NULL
, keys
, values
, 3,
1090 &kCFTypeDictionaryKeyCallBacks
,
1091 &kCFTypeDictionaryValueCallBacks
);
1092 theirPubKey
= SecKeyCreateWithData(theirPubData
, theirKeyAttrs
, &error
);
1094 dprintf("SecKeyCreateWithData: failed\n");
1099 sharedInfoData
= CFDataCreate(NULL
, sharedInfoEnc
.Data
, sharedInfoEnc
.Length
);
1100 int32_t ecdh_key_key_len
= (kekSizeBits
+ 7) >> 3;
1101 kekLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &ecdh_key_key_len
);
1102 const void *kekKeys
[] = { kSecKeyKeyExchangeParameterRequestedSize
, kSecKeyKeyExchangeParameterSharedInfo
};
1103 const void *kekValues
[] = { kekLen
, sharedInfoData
};
1104 kekParams
= CFDictionaryCreate(NULL
, kekKeys
, kekValues
, 2,
1105 &kCFTypeDictionaryKeyCallBacks
,
1106 &kCFTypeDictionaryValueCallBacks
);
1107 kekData
= SecKeyCopyKeyExchangeResult(privkey
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
,
1108 theirPubKey
, kekParams
, &error
);
1110 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
1115 * Decrypt the raw CEK bits with the KEK we just derived
1117 CSSM_DATA cek
= { 0, NULL
};
1118 rv
= CCCryptorCreate(kCCDecrypt
, alg
, options
,
1119 CFDataGetBytePtr(kekData
), CFDataGetLength(kekData
), iv
.Data
, &ciphercc
);
1121 dprintf("CCCryptorCreate failed: %d\n", (int)rv
);
1124 size_t expectedKeyLength
= CCCryptorGetOutputLength(ciphercc
, encKey
->Length
, true);
1125 cek
.Data
= PORT_ArenaAlloc(pool
, expectedKeyLength
);
1126 size_t bytes_output
= 0;
1127 rv
= CCCryptorUpdate(ciphercc
, encKey
->Data
, encKey
->Length
, cek
.Data
, expectedKeyLength
, &bytes_output
);
1129 dprintf("CCCryptorUpdate failed: %d\n", (int)rv
);
1132 size_t final_bytes_output
= 0;
1133 rv
= CCCryptorFinal(ciphercc
, cek
.Data
+bytes_output
, expectedKeyLength
- bytes_output
, &final_bytes_output
);
1135 dprintf("CCCryptorFinal failed: %d\n", (int)rv
);
1138 cek
.Length
= bytes_output
+ final_bytes_output
;
1140 /* create the SecSymmetricKeyRef */
1141 cekData
= CFDataCreate(NULL
, cek
.Data
, cek
.Length
);
1142 keyType
= SECOID_CopyKeyTypeByTag(bulkalgtag
);
1146 cekParams
= CFDictionaryCreateMutable(NULL
, 1,
1147 &kCFTypeDictionaryKeyCallBacks
,
1148 &kCFTypeDictionaryValueCallBacks
);
1152 CFDictionaryAddValue(cekParams
, kSecAttrKeyType
, keyType
);
1153 outKey
= SecKeyCreateFromData(cekParams
, cekData
, NULL
);
1157 PORT_FreeArena(pool
, PR_FALSE
);
1159 if (theirPubData
) { CFRelease(theirPubData
); }
1160 if (theirKeyLen
) { CFRelease(theirKeyLen
); }
1161 if (theirPubKey
) { CFRelease(theirPubKey
); }
1162 if (theirKeyAttrs
) { CFRelease(theirKeyAttrs
); }
1163 if (sharedInfoData
) { CFRelease(sharedInfoData
); }
1164 if (kekLen
) { CFRelease(kekLen
); }
1165 if (kekParams
) { CFRelease(kekParams
); }
1166 if (kekData
) { CFRelease(kekData
); }
1167 if (error
) { CFRelease(error
); }
1168 if (ciphercc
) { CCCryptorRelease(ciphercc
); }
1169 if (cekData
) { CFRelease(cekData
); }
1170 if (keyType
) { CFRelease(keyType
); }
1171 if (cekParams
) { CFRelease(cekParams
); }
1172 if(outKey
== NULL
) {
1173 PORT_SetError(SEC_ERROR_NO_KEY
);