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
,
73 SecPublicKeyRef publickey
;
75 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
76 rv
= SecCertificateCopyPublicKey(cert
,&publickey
);
78 publickey
= SecCertificateCopyPublicKey(cert
);
80 if (publickey
== NULL
)
83 rv
= SecCmsUtilEncryptSymKeyRSAPubKey(poolp
, publickey
, bulkkey
, encKey
);
89 SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool
*poolp
,
90 SecPublicKeyRef publickey
,
91 SecSymmetricKeyRef bulkkey
, CSSM_DATA_PTR encKey
)
94 unsigned int data_len
;
98 mark
= PORT_ArenaMark(poolp
);
104 keyType
= SECKEY_GetPublicKeyType(publickey
);
105 PORT_Assert(keyType
== rsaKey
);
106 if (keyType
!= rsaKey
) {
110 /* allocate memory for the encrypted key */
111 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
112 rv
= SecKeyGetStrengthInBits(publickey
, NULL
, &data_len
);
115 // Convert length to bytes;
116 data_len
= data_len
/ 8;
118 data_len
= SecKeyGetSize(publickey
, kSecKeyEncryptedDataSize
);
121 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, data_len
);
122 encKey
->Length
= data_len
;
123 if (encKey
->Data
== NULL
)
126 /* encrypt the key now */
127 rv
= WRAP_PubWrapSymKey(publickey
, bulkkey
, encKey
);
128 if (rv
!= SECSuccess
)
131 PORT_ArenaUnmark(poolp
, mark
);
136 PORT_ArenaRelease(poolp
, mark
);
142 * SecCmsUtilDecryptSymKeyRSA - unwrap a RSA-wrapped symmetric key
144 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
145 * key handle. Please note that the actual unwrapped key data may not be allowed to leave
146 * a hardware token...
149 SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECOidTag bulkalgtag
)
152 return WRAP_PubUnwrapSymKey(privkey
, encKey
, bulkalgtag
);
156 // @@@ Implement Fortezza and Diffie hellman support
158 /* ====== MISSI (Fortezza) ========================================================== */
160 extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams
[];
163 SecCmsUtilEncryptSymKeyMISSI(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef bulkkey
,
164 SECOidTag symalgtag
, CSSM_DATA_PTR encKey
, CSSM_DATA_PTR
*pparams
, void *pwfn_arg
)
166 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
167 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
168 OSStatus rv
= SECFailure
;
169 CSSM_DATA_PTR params
= NULL
;
171 SecSymmetricKeyRef tek
;
172 SecCertificateRef ourCert
;
173 SecPublicKeyRef ourPubKey
, *publickey
= NULL
;
174 SecPrivateKeyRef ourPrivKey
= NULL
;
175 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
176 SecCmsSMIMEKEAParameters keaParams
;
177 PLArenaPool
*arena
= NULL
;
178 extern const SecAsn1Template
*nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate
);
179 const SECAlgorithmID
*algid
;
181 /* Clear keaParams, since cleanup code checks the lengths */
182 (void) memset(&keaParams
, 0, sizeof(keaParams
));
184 SecCertificateGetAlgorithmID(cert
,&algid
);
185 certalgtag
= SECOID_GetAlgorithmTag(algid
);
186 PORT_Assert(certalgtag
== SEC_OID_MISSI_KEA_DSS_OLD
||
187 certalgtag
== SEC_OID_MISSI_KEA_DSS
||
188 certalgtag
== SEC_OID_MISSI_KEA
);
190 #define SMIME_FORTEZZA_RA_LENGTH 128
191 #define SMIME_FORTEZZA_IV_LENGTH 24
192 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
194 /* We really want to show our KEA tag as the key exchange algorithm tag. */
195 encalgtag
= SEC_OID_NETSCAPE_SMIME_KEA
;
197 /* Get the public key of the recipient. */
198 publickey
= CERT_ExtractPublicKey(cert
);
199 if (publickey
== NULL
) goto loser
;
201 /* Find our own cert, and extract its keys. */
202 ourCert
= PK11_FindBestKEAMatch(cert
, pwfn_arg
);
203 if (ourCert
== NULL
) goto loser
;
205 arena
= PORT_NewArena(1024);
209 ourPubKey
= CERT_ExtractPublicKey(ourCert
);
210 if (ourPubKey
== NULL
) {
211 CERT_DestroyCertificate(ourCert
);
215 /* While we're here, copy the public key into the outgoing
217 SECITEM_CopyItem(arena
, &(keaParams
.originatorKEAKey
), &(ourPubKey
->u
.fortezza
.KEAKey
));
218 SECKEY_DestroyPublicKey(ourPubKey
);
221 /* Extract our private key in order to derive the KEA key. */
222 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
, pwfn_arg
);
223 CERT_DestroyCertificate(ourCert
); /* we're done with this */
227 /* Prepare raItem with 128 bytes (filled with zeros). */
228 keaParams
.originatorRA
.Data
= (unsigned char *)PORT_ArenaAlloc(arena
,SMIME_FORTEZZA_RA_LENGTH
);
229 keaParams
.originatorRA
.Length
= SMIME_FORTEZZA_RA_LENGTH
;
231 /* Generate the TEK (token exchange key) which we use
232 * to wrap the bulk encryption key. (keaparams.originatorRA) will be
233 * filled with a random seed which we need to send to
234 * the recipient. (user keying material in RFC2630/DSA speak) */
235 tek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
236 &keaParams
.originatorRA
, NULL
,
237 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
238 CKA_WRAP
, 0, pwfn_arg
);
240 SECKEY_DestroyPublicKey(publickey
);
241 SECKEY_DestroyPrivateKey(ourPrivKey
);
248 /* allocate space for the wrapped key data */
249 encKey
->Data
= (unsigned char *)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
250 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
252 if (encKey
->Data
== NULL
) {
257 /* Wrap the bulk key. What we do with the resulting data
258 depends on whether we're using Skipjack to wrap the key. */
259 switch (PK11_AlgtagToMechanism(symalgtag
)) {
260 case CKM_SKIPJACK_CBC64
:
261 case CKM_SKIPJACK_ECB64
:
262 case CKM_SKIPJACK_OFB64
:
263 case CKM_SKIPJACK_CFB64
:
264 case CKM_SKIPJACK_CFB32
:
265 case CKM_SKIPJACK_CFB16
:
266 case CKM_SKIPJACK_CFB8
:
267 /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */
268 err
= PK11_WrapSymKey(CKM_SKIPJACK_WRAP
, NULL
, tek
, bulkkey
, encKey
);
269 whichKEA
= SecCmsKEAUsesSkipjack
;
272 /* Not SKIPJACK, we encrypt the raw key data */
273 keaParams
.nonSkipjackIV
.Data
=
274 (unsigned char *)PORT_ArenaAlloc(arena
, SMIME_FORTEZZA_IV_LENGTH
);
275 keaParams
.nonSkipjackIV
.Length
= SMIME_FORTEZZA_IV_LENGTH
;
276 err
= PK11_WrapSymKey(CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
, tek
, bulkkey
, encKey
);
277 if (err
!= SECSuccess
)
280 if (encKey
->Length
!= PK11_GetKeyLength(bulkkey
)) {
281 /* The size of the encrypted key is not the same as
282 that of the original bulk key, presumably due to
283 padding. Encode and store the real size of the
285 if (SEC_ASN1EncodeInteger(arena
, &keaParams
.bulkKeySize
, PK11_GetKeyLength(bulkkey
)) == NULL
)
286 err
= (OSStatus
)PORT_GetError();
288 /* use full template for encoding */
289 whichKEA
= SecCmsKEAUsesNonSkipjackWithPaddedEncKey
;
292 /* enc key length == bulk key length */
293 whichKEA
= SecCmsKEAUsesNonSkipjack
;
299 if (err
!= SECSuccess
)
302 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
304 /* Encode the KEA parameters into the recipient info. */
305 params
= SEC_ASN1EncodeItem(poolp
, NULL
, &keaParams
, nss_cms_get_kea_template(whichKEA
));
309 /* pass back the algorithm params */
316 PORT_FreeArena(arena
, PR_FALSE
);
318 SECKEY_DestroyPublicKey(publickey
);
320 SECKEY_DestroyPrivateKey(ourPrivKey
);
325 SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
327 /* fortezza: do a key exchange */
329 CK_MECHANISM_TYPE bulkType
;
330 SecSymmetricKeyRef tek
;
331 SecPublicKeyRef originatorPubKey
;
332 SecCmsSMIMEKEAParameters keaParams
;
333 SecSymmetricKeyRef bulkkey
;
336 (void) memset(&keaParams
, 0, sizeof(keaParams
));
338 /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
339 All additional KEA parameters are DER-encoded in the encryption algorithm parameters */
341 /* Decode the KEA algorithm parameters. */
342 err
= SEC_ASN1DecodeItem(NULL
, &keaParams
, NSS_SMIMEKEAParamTemplateAllParams
,
343 &(keyEncAlg
->parameters
));
344 if (err
!= SECSuccess
)
347 /* get originator's public key */
348 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
349 keaParams
.originatorKEAKey
.Length
);
350 if (originatorPubKey
== NULL
)
353 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
354 The Derive function generates a shared secret and combines it with the originatorRA
355 data to come up with an unique session key */
356 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
357 &keaParams
.originatorRA
, NULL
,
358 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
359 CKA_WRAP
, 0, pwfn_arg
);
360 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
364 /* Now that we have the TEK, unwrap the bulk key
365 with which to decrypt the message. We have to
366 do one of two different things depending on
367 whether Skipjack was used for *bulk* encryption
369 bulkType
= PK11_AlgtagToMechanism(bulkalgtag
);
371 case CKM_SKIPJACK_CBC64
:
372 case CKM_SKIPJACK_ECB64
:
373 case CKM_SKIPJACK_OFB64
:
374 case CKM_SKIPJACK_CFB64
:
375 case CKM_SKIPJACK_CFB32
:
376 case CKM_SKIPJACK_CFB16
:
377 case CKM_SKIPJACK_CFB8
:
378 /* Skipjack is being used as the bulk encryption algorithm.*/
379 /* Unwrap the bulk key. */
380 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
381 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
384 /* Skipjack was not used for bulk encryption of this
385 message. Use Skipjack CBC64, with the nonSkipjackIV
386 part of the KEA key parameters, to decrypt
387 the bulk key. If the optional parameter bulkKeySize is present,
388 bulk key size is different than the encrypted key size */
389 if (keaParams
.bulkKeySize
.Length
> 0) {
390 err
= SEC_ASN1DecodeItem(NULL
, &bulkLength
,
391 SEC_ASN1_GET(SEC_IntegerTemplate
),
392 &keaParams
.bulkKeySize
);
393 if (err
!= SECSuccess
)
397 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_CBC64
, &keaParams
.nonSkipjackIV
,
398 encKey
, bulkType
, CKA_DECRYPT
, bulkLength
);
406 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
409 SecCmsUtilEncryptSymKeyESDH(PLArenaPool
*poolp
, SecCertificateRef cert
, SecSymmetricKeyRef key
,
410 CSSM_DATA_PTR encKey
, CSSM_DATA_PTR ukm
, SECAlgorithmID
*keyEncAlg
,
411 CSSM_DATA_PTR pubKey
)
413 #if 0 /* not yet done */
414 SECOidTag certalgtag
; /* the certificate's encryption algorithm */
415 SECOidTag encalgtag
; /* the algorithm used for key exchange/agreement */
417 CSSM_DATA_PTR params
= NULL
;
420 SecSymmetricKeyRef tek
;
421 SecCertificateRef ourCert
;
422 SecPublicKeyRef ourPubKey
;
423 SecCmsKEATemplateSelector whichKEA
= SecCmsKEAInvalid
;
425 certalgtag
= SECOID_GetAlgorithmTag(&(cert
->subjectPublicKeyInfo
.algorithm
));
426 PORT_Assert(certalgtag
== SEC_OID_X942_DIFFIE_HELMAN_KEY
);
428 /* We really want to show our KEA tag as the key exchange algorithm tag. */
429 encalgtag
= SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
;
431 /* Get the public key of the recipient. */
432 publickey
= CERT_ExtractPublicKey(cert
);
433 if (publickey
== NULL
) goto loser
;
435 /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
436 /* XXXX */ourCert
= PK11_FindBestKEAMatch(cert
, wincx
);
437 if (ourCert
== NULL
) goto loser
;
439 arena
= PORT_NewArena(1024);
440 if (arena
== NULL
) goto loser
;
442 /* While we're here, extract the key pair's public key data and copy it into */
443 /* the outgoing parameters. */
444 /* XXXX */ourPubKey
= CERT_ExtractPublicKey(ourCert
);
445 if (ourPubKey
== NULL
)
449 SECITEM_CopyItem(arena
, pubKey
, /* XXX */&(ourPubKey
->u
.fortezza
.KEAKey
));
450 SECKEY_DestroyPublicKey(ourPubKey
); /* we only need the private key from now on */
453 /* Extract our private key in order to derive the KEA key. */
454 ourPrivKey
= PK11_FindKeyByAnyCert(ourCert
,wincx
);
455 CERT_DestroyCertificate(ourCert
); /* we're done with this */
456 if (!ourPrivKey
) goto loser
;
458 /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
460 ukm
->Data
= (unsigned char*)PORT_ArenaZAlloc(arena
,/* XXXX */);
461 ukm
->Length
= /* XXXX */;
464 /* Generate the KEK (key exchange key) according to RFC2631 which we use
465 * to wrap the bulk encryption key. */
466 kek
= PK11_PubDerive(ourPrivKey
, publickey
, PR_TRUE
,
468 /* XXXX */CKM_KEA_KEY_DERIVE
, /* XXXX */CKM_SKIPJACK_WRAP
,
471 SECKEY_DestroyPublicKey(publickey
);
472 SECKEY_DestroyPrivateKey(ourPrivKey
);
479 /* allocate space for the encrypted CEK (bulk key) */
480 encKey
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, SMIME_FORTEZZA_MAX_KEY_SIZE
);
481 encKey
->Length
= SMIME_FORTEZZA_MAX_KEY_SIZE
;
483 if (encKey
->Data
== NULL
)
490 /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
491 /* bulk encryption algorithm */
492 switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo
->encalg
))
494 case /* XXXX */CKM_SKIPJACK_CFB8
:
495 err
= PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP
, NULL
, kek
, bulkkey
, encKey
);
496 whichKEA
= SecCmsKEAUsesSkipjack
;
498 case /* XXXX */CKM_SKIPJACK_CFB8
:
499 err
= PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP
, NULL
, kek
, bulkkey
, encKey
);
500 whichKEA
= SecCmsKEAUsesSkipjack
;
503 /* XXXX what do we do here? Neither RC2 nor 3DES... */
509 CFRelease(kek
); /* we do not need the KEK anymore */
510 if (err
!= SECSuccess
)
513 PORT_Assert(whichKEA
!= SecCmsKEAInvalid
);
515 /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
516 /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
517 params
= SEC_ASN1EncodeItem(arena
, NULL
, &keaParams
, sec_pkcs7_get_kea_template(whichKEA
));
521 /* now set keyEncAlg */
522 rv
= SECOID_SetAlgorithmID(poolp
, keyEncAlg
, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN
, params
);
523 if (rv
!= SECSuccess
)
526 /* XXXXXXX this is not right yet */
529 PORT_FreeArena(arena
, PR_FALSE
);
532 SECKEY_DestroyPublicKey(publickey
);
535 SECKEY_DestroyPrivateKey(ourPrivKey
);
542 SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey
, CSSM_DATA_PTR encKey
, SECAlgorithmID
*keyEncAlg
, SECOidTag bulkalgtag
, void *pwfn_arg
)
544 #if 0 /* not yet done */
546 CK_MECHANISM_TYPE bulkType
;
547 SecSymmetricKeyRef tek
;
548 SecPublicKeyRef originatorPubKey
;
549 SecCmsSMIMEKEAParameters keaParams
;
551 /* XXXX get originator's public key */
552 originatorPubKey
= PK11_MakeKEAPubKey(keaParams
.originatorKEAKey
.Data
,
553 keaParams
.originatorKEAKey
.Length
);
554 if (originatorPubKey
== NULL
)
557 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
558 The Derive function generates a shared secret and combines it with the originatorRA
559 data to come up with an unique session key */
560 tek
= PK11_PubDerive(privkey
, originatorPubKey
, PR_FALSE
,
561 &keaParams
.originatorRA
, NULL
,
562 CKM_KEA_KEY_DERIVE
, CKM_SKIPJACK_WRAP
,
563 CKA_WRAP
, 0, pwfn_arg
);
564 SECKEY_DestroyPublicKey(originatorPubKey
); /* not needed anymore */
568 /* Now that we have the TEK, unwrap the bulk key
569 with which to decrypt the message. */
570 /* Skipjack is being used as the bulk encryption algorithm.*/
571 /* Unwrap the bulk key. */
572 bulkkey
= PK11_UnwrapSymKey(tek
, CKM_SKIPJACK_WRAP
, NULL
,
573 encKey
, CKM_SKIPJACK_CBC64
, CKA_DECRYPT
, 0);
582 #endif /* Fortezza, DIffie-Hellman */
584 #define CFRELEASE(cf) if(cf != NULL) { CFRelease(cf); }
586 /* ====== ECDH (Ephemeral-Static Diffie-Hellman) ==================================== */
588 #pragma mark ---- ECDH support functions ----
591 #define CSSM_PERROR(f, r)
592 #define dprintf(args...)
594 #define CSSM_PERROR(f, r) cssmPerror(f, r)
595 #define dprintf(args...) fprintf(stderr, args)
598 /* Length of KeyAgreeRecipientInfo.ukm we create */
601 /* KEK algorithm info we generate */
602 #define ECDH_KEK_ALG_TAG SEC_OID_DES_EDE3_CBC
603 #define ECDH_KEK_KEY_CSSM_ALGID CSSM_ALGID_3DES_3KEY
604 #define ECDH_KEK_ENCR_CSSM_ALGID CSSM_ALGID_3DES_3KEY_EDE
605 #define ECDH_KEK_KEY_LEN_BYTES 24
606 #define ECDH_KEK_IV_LEN_BYTES 8
608 #define CMS_DUMP_BUFS 0
617 printf("%s:\n ", label
);
618 for(dex
=0; dex
<cd
->Length
; dex
++) {
619 printf("%02X ", cd
->Data
[dex
]);
620 if(((dex
% 16) == 15) && (dex
!= (cd
->Length
- 1))) {
628 #define dumpBuf(l, d)
629 #endif /* CMS_DUMP_BUFS */
632 * The ECC-CMS-SharedInfo struct, as defined in RFC 3278 8.2, and the
633 * template for DER encoding and decoding it.
636 SECAlgorithmID algId
; /* KEK alg, NULL params */
637 CSSM_DATA entityUInfo
; /* optional, ukm */
638 CSSM_DATA suppPubInfo
; /* length of KEK in bits as 4-byte integer */
639 } ECC_CMS_SharedInfo
;
641 static const SecAsn1Template ECC_CMS_SharedInfoTemplate
[] = {
642 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(ECC_CMS_SharedInfo
) },
643 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 0,
644 offsetof(ECC_CMS_SharedInfo
,entityUInfo
),
645 kSecAsn1OctetStringTemplate
},
646 { SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONTEXT_SPECIFIC
| 2,
647 offsetof(ECC_CMS_SharedInfo
,suppPubInfo
),
648 kSecAsn1OctetStringTemplate
},
653 * Given a context specified via a CSSM_CC_HANDLE, add a new
654 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
655 * AttributeLength, and an untyped pointer.
657 /* specify either 32-bit integer or a pointer as an added attribute value */
663 /* convert uint32 to big-endian 4 bytes */
664 static void int32ToBytes(
669 for(dex
=3; dex
>=0; dex
--) {
676 * Given an OID tag, return key size and mode.
677 * NOTE: ciphers with variable key sizes, like RC2, RC4, and RC5 cannot
678 * be used here because the message does not contain a key size
681 static OSStatus
encrAlgInfo(
683 uint32
*keySizeBits
, /* RETURNED */
684 CCAlgorithm
*algorithm
, /* RETURNED */
685 CCOptions
*options
) /* RETURNED */
687 *keySizeBits
= 64; /* default */
688 *options
= kCCOptionPKCS7Padding
; /* default */
691 case SEC_OID_RC2_CBC
:
693 case SEC_OID_RC5_CBC_PAD
:
694 dprintf("encrAlgInfo: key size unknowable\n");
695 return errSecDataNotAvailable
;
696 case SEC_OID_DES_EDE
:
697 /* Not sure about this; SecCmsCipherContextStart() treats this
698 * like SEC_OID_DES_EDE3_CBC... */
699 *options
= kCCOptionECBMode
;
701 case SEC_OID_DES_EDE3_CBC
:
703 *algorithm
= kCCAlgorithm3DES
;
705 case SEC_OID_DES_ECB
:
706 *options
= kCCOptionECBMode
;
708 case SEC_OID_DES_CBC
:
709 *algorithm
= kCCAlgorithmDES
;
711 case SEC_OID_AES_128_CBC
:
713 *algorithm
= kCCAlgorithmAES
;
715 case SEC_OID_AES_192_CBC
:
717 *algorithm
= kCCAlgorithmAES
;
719 case SEC_OID_AES_256_CBC
:
721 *algorithm
= kCCAlgorithmAES
;
723 case SEC_OID_AES_128_ECB
:
725 *algorithm
= kCCAlgorithmAES
;
726 *options
= kCCOptionECBMode
;
728 case SEC_OID_AES_192_ECB
:
730 *algorithm
= kCCAlgorithmAES
;
731 *options
= kCCOptionECBMode
;
733 case SEC_OID_AES_256_ECB
:
735 *algorithm
= kCCAlgorithmAES
;
736 *options
= kCCOptionECBMode
;
739 dprintf("encrAlgInfo: unknown alg tag (%d)\n", (int)oidTag
);
740 return errSecDataNotAvailable
;
745 #pragma mark ---- ECDH CEK key wrap ----
748 * Encrypt bulk encryption key (a.k.a. content encryption key, CEK) using ECDH
751 SecCmsUtilEncryptSymKeyECDH(
753 SecCertificateRef cert
, /* recipient's cert */
754 SecSymmetricKeyRef key
, /* bulk key */
755 /* remaining fields RETURNED */
756 CSSM_DATA_PTR encKey
, /* encrypted key --> recipientEncryptedKeys[0].EncryptedKey */
757 CSSM_DATA_PTR ukm
, /* random UKM --> KeyAgreeRecipientInfo.ukm */
758 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
759 * params := another encoded AlgId, with the KEK alg and IV */
760 CSSM_DATA_PTR pubKey
) /* our pub key as ECPoint -->
761 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
764 SecKeyRef theirPubKey
= NULL
, ourPubKey
= NULL
, ourPrivKey
= NULL
;
765 CFDictionaryRef theirKeyAttrs
= NULL
, ourKeyParams
= NULL
, kekParams
= NULL
;
766 uint8_t iv
[ECDH_KEK_IV_LEN_BYTES
];
767 CSSM_DATA ivData
= { ECDH_KEK_IV_LEN_BYTES
, iv
};
768 SECAlgorithmID kekAlgId
;
770 ECC_CMS_SharedInfo sharedInfo
;
771 CSSM_DATA sharedInfoEnc
= {0, NULL
};
772 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
773 uint8 keyLenAsBytes
[4];
774 CFDataRef sharedInfoData
= NULL
, kekData
= NULL
, ourPubData
= NULL
;
775 CFNumberRef kekLen
= NULL
;
776 CFErrorRef error
= NULL
;
777 CCCryptorRef ciphercc
= NULL
;
782 /* Copy the recipient's static public ECDH key */
784 theirPubKey
= SecCertificateCopyPublicKey(cert
);
786 rv
= SecCertificateCopyPublicKey(cert
, &theirPubKey
);
788 if (rv
|| !theirPubKey
) {
789 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get public key from cert, %d\n", (int)rv
);
793 theirKeyAttrs
= SecKeyCopyAttributes(theirPubKey
);
794 if (!theirKeyAttrs
) {
795 dprintf("SecCmsUtilEncryptSymKeyECDH: failed to get key attributes\n");
799 CFStringRef keyType
= NULL
;
800 CFNumberRef keySizeNum
= NULL
;
801 keyType
= CFDictionaryGetValue(theirKeyAttrs
, kSecAttrKeyType
);
802 keySizeNum
= CFDictionaryGetValue(theirKeyAttrs
, kSecAttrKeySizeInBits
);
804 if (!CFEqual(kSecAttrKeyTypeECSECPrimeRandom
, keyType
)) {
805 dprintf("SecCmsUtilEncryptSymKeyECDH: unsupported key type\n");
806 rv
= CSSMERR_CSP_INVALID_KEY
;
810 /* Generate ephemeral ECDH key */
811 const void *keys
[] = { kSecAttrKeyType
, kSecAttrKeySizeInBits
, kSecAttrNoLegacy
};
812 const void *values
[] = { keyType
, keySizeNum
, kCFBooleanTrue
};
813 ourKeyParams
= CFDictionaryCreate(NULL
, keys
, values
, 3,
814 &kCFTypeDictionaryKeyCallBacks
,
815 &kCFTypeDictionaryValueCallBacks
);
816 rv
= SecKeyGeneratePair(ourKeyParams
, &ourPubKey
, &ourPrivKey
);
817 if (rv
|| !ourPubKey
|| !ourPrivKey
) {
818 dprintf("SecKeyGeneratePair: unable to generate ECDH key pair, %d\n", (int)rv
);
823 ukm
->Data
= PORT_Alloc(UKM_LENGTH
);
824 ukm
->Length
= UKM_LENGTH
;
825 rv
= CCRandomCopyBytes(kCCRandomDefault
, ukm
->Data
, UKM_LENGTH
);
826 if (rv
|| !ukm
->Data
) {
827 dprintf("CCRandomGenerateBytes failed, %d", (int)rv
);
832 * OK, we have to set up a weird SECAlgorithmID.
833 * algorithm = dhSinglePass-stdDH-sha1kdf-scheme
834 * params = an encoded SECAlgorithmID representing the KEK algorithm, with
835 * algorithm = whatever we pick
836 * parameters = IV as octet string (though I haven't seen that specified
837 * anywhere; it's how the CEK IV is encoded)
840 /* Generate 8-byte IV */
841 rv
= CCRandomCopyBytes(kCCRandomDefault
, iv
, ECDH_KEK_IV_LEN_BYTES
);
843 dprintf("CCRandomGenerateBytes failed, %d", (int)rv
);
846 dumpBuf("sender IV", &ivData
);
848 memset(&kekAlgId
, 0, sizeof(kekAlgId
));
849 if (!SEC_ASN1EncodeItem(poolp
, &kekAlgId
.parameters
,
850 &ivData
, kSecAsn1OctetStringTemplate
)) {
851 rv
= internalComponentErr
;
855 /* Drop in the KEK OID and encode the whole thing */
856 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
858 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
859 rv
= internalComponentErr
;
862 kekAlgId
.algorithm
= kekOid
->oid
;
863 memset(keyEncAlg
, 0, sizeof(*keyEncAlg
));
864 if (!SEC_ASN1EncodeItem(poolp
, &keyEncAlg
->parameters
,
865 &kekAlgId
, SECOID_AlgorithmIDTemplate
)) {
866 rv
= internalComponentErr
;
869 kekOid
= SECOID_FindOIDByTag(SEC_OID_DH_SINGLE_STD_SHA1KDF
);
871 dprintf("SecCmsUtilEncryptSymKeyECDH: OID screwup\n");
872 rv
= internalComponentErr
;
875 keyEncAlg
->algorithm
= kekOid
->oid
;
878 * Now in order to derive the KEK proper, we have to create a
879 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
880 * encode that struct, the result of which is used as the
881 * SharedInfo value in the KEK key derive.
883 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
884 kekOid
= SECOID_FindOIDByTag(ECDH_KEK_ALG_TAG
);
885 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
886 sharedInfo
.algId
.parameters
.Data
= nullData
;
887 sharedInfo
.algId
.parameters
.Length
= 2;
888 sharedInfo
.entityUInfo
= *ukm
;
889 int32ToBytes(ECDH_KEK_KEY_LEN_BYTES
<< 3, keyLenAsBytes
);
890 sharedInfo
.suppPubInfo
.Length
= 4;
891 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
892 if (!SEC_ASN1EncodeItem(poolp
, &sharedInfoEnc
,
893 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
894 rv
= internalComponentErr
;
897 dumpBuf("sender encoded SharedInfo", &sharedInfoEnc
);
900 sharedInfoData
= CFDataCreate(NULL
, sharedInfoEnc
.Data
, sharedInfoEnc
.Length
);
901 int32_t ecdh_key_key_len
= ECDH_KEK_KEY_LEN_BYTES
;
902 kekLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &ecdh_key_key_len
);
903 const void *kekKeys
[] = { kSecKeyKeyExchangeParameterRequestedSize
, kSecKeyKeyExchangeParameterSharedInfo
};
904 const void *kekValues
[] = { kekLen
, sharedInfoData
};
905 kekParams
= CFDictionaryCreate(NULL
, kekKeys
, kekValues
, 2,
906 &kCFTypeDictionaryKeyCallBacks
,
907 &kCFTypeDictionaryValueCallBacks
);
908 kekData
= SecKeyCopyKeyExchangeResult(ourPrivKey
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
,
909 theirPubKey
, kekParams
, &error
);
911 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
916 * Encrypt the raw CEK bits with the KEK we just derived
918 rv
= CCCryptorCreate(kCCEncrypt
, kCCAlgorithm3DES
, kCCOptionPKCS7Padding
,
919 CFDataGetBytePtr(kekData
), CFDataGetLength(kekData
), iv
, &ciphercc
);
921 dprintf("CCCryptorCreate failed: %d\n", (int)rv
);
925 rv
= cmsNullWrapKey(key
, &cek
);
927 dprintf("SecKeyGetCSSMKey failed: %d\n", (int)rv
);
930 size_t expectedEncKeyLength
= CCCryptorGetOutputLength(ciphercc
, cek
.KeyData
.Length
, true);
931 encKey
->Data
= PORT_ArenaAlloc(poolp
, expectedEncKeyLength
);
932 size_t bytes_output
= 0;
933 rv
= CCCryptorUpdate(ciphercc
, cek
.KeyData
.Data
, cek
.KeyData
.Length
, encKey
->Data
, expectedEncKeyLength
, &bytes_output
);
935 dprintf("CCCryptorUpdate failed: %d\n", (int)rv
);
938 size_t final_bytes_output
= 0;
939 rv
= CCCryptorFinal(ciphercc
, encKey
->Data
+bytes_output
, expectedEncKeyLength
- bytes_output
, &final_bytes_output
);
941 dprintf("CCCryptorFinal failed: %d\n", (int)rv
);
944 encKey
->Length
= bytes_output
+ final_bytes_output
;
946 /* Provide our ephemeral public key to the caller */
947 ourPubData
= SecKeyCopyExternalRepresentation(ourPubKey
, &error
);
949 dprintf("SecKeyCopyExternalRepresentation failed\n");
952 pubKey
->Length
= CFDataGetLength(ourPubData
);
953 pubKey
->Data
= malloc(pubKey
->Length
);
955 memcpy(pubKey
->Data
, CFDataGetBytePtr(ourPubData
), pubKey
->Length
);
959 /* pubKey is bit string, convert here */
960 pubKey
->Length
<<= 3;
963 if (theirPubKey
) { CFRelease(theirPubKey
); }
964 if (theirKeyAttrs
) { CFRelease(theirKeyAttrs
); }
965 if (ourKeyParams
) { CFRelease(ourKeyParams
); }
966 if (ourPubKey
) { CFRelease(ourPubKey
); }
967 if (ourPrivKey
) { CFRelease(ourPrivKey
); }
968 if (sharedInfoData
) { CFRelease(sharedInfoData
); }
969 if (kekLen
) { CFRelease(kekLen
); }
970 if (kekParams
) { CFRelease(kekParams
); }
971 if (kekData
) { CFRelease(kekData
); }
972 if (error
) { CFRelease(error
); }
973 if (ciphercc
) { CCCryptorRelease(ciphercc
); }
974 if (ourPubData
) { CFRelease(ourPubData
); }
975 if (rv
&& encKey
->Data
) {
976 PORT_Free(encKey
->Data
);
980 if (rv
&& ukm
->Data
) {
981 PORT_Free(ukm
->Data
);
989 #pragma mark ---- ECDH CEK key unwrap ----
992 SecCmsUtilDecryptSymKeyECDH(
993 SecPrivateKeyRef privkey
, /* our private key */
994 CSSM_DATA_PTR encKey
, /* encrypted CEK */
995 CSSM_DATA_PTR ukm
, /* random UKM from KeyAgreeRecipientInfo.ukm */
996 SECAlgorithmID
*keyEncAlg
, /* alg := dhSinglePass-stdDH-sha1kdf-scheme
997 * params := another encoded AlgId, with the KEK alg and IV */
998 SECOidTag bulkalgtag
, /* algorithm of returned key */
999 CSSM_DATA_PTR pubKey
) /* sender's pub key as ECPoint from
1000 * KeyAgreeRecipientInfo.originator.OriginatorPublicKey */
1002 SecSymmetricKeyRef outKey
= NULL
;
1003 OSStatus rv
= noErr
;
1004 PLArenaPool
*pool
= NULL
;
1005 SECAlgorithmID keyAlgParam
;
1006 SECOidData
*kekOid
= NULL
;
1007 CSSM_DATA iv
= {0, NULL
};
1008 ECC_CMS_SharedInfo sharedInfo
;
1009 CSSM_DATA sharedInfoEnc
= {0, NULL
};
1010 uint8 nullData
[2] = {SEC_ASN1_NULL
, 0};
1011 uint8 keyLenAsBytes
[4];
1013 SecKeyRef theirPubKey
= NULL
;
1014 CFStringRef keyType
= NULL
;
1015 CFDictionaryRef theirKeyAttrs
= NULL
, kekParams
= NULL
;
1016 CFMutableDictionaryRef cekParams
= NULL
;
1017 CFDataRef sharedInfoData
= NULL
, theirPubData
= NULL
, kekData
= NULL
, cekData
= NULL
;
1018 CFNumberRef kekLen
= NULL
, theirKeyLen
= NULL
;
1019 CFErrorRef error
= NULL
;
1021 CCOptions options
= 0;
1022 CCCryptorRef ciphercc
= NULL
;
1023 size_t theirKeySizeInBits
= 0;
1026 * Decode keyEncAlg.params to get KEK algorithm and IV
1028 pool
= PORT_NewArena(1024);
1032 memset(&keyAlgParam
, 0, sizeof(keyAlgParam
));
1033 if(SEC_ASN1DecodeItem(pool
, &keyAlgParam
, SECOID_AlgorithmIDTemplate
,
1034 &keyEncAlg
->parameters
)) {
1035 dprintf("SecCmsUtilDecryptSymKeyECDH: error decoding keyAlgParams\n");
1038 kekOid
= SECOID_FindOID(&keyAlgParam
.algorithm
);
1039 if(kekOid
== NULL
) {
1040 dprintf("SecCmsUtilDecryptSymKeyECDH: unknown KEK enc OID\n");
1043 rv
= encrAlgInfo(kekOid
->offset
, &kekSizeBits
, &alg
, &options
);
1047 /* IV is OCTET STRING in the alg params */
1048 if(SEC_ASN1DecodeItem(pool
, &iv
, kSecAsn1OctetStringTemplate
,
1049 &keyAlgParam
.parameters
)) {
1051 * Not sure here - is it legal to have no IV? I haven't seen this
1052 * addressed in any spec. Maybe we should condition the behavior
1053 * here on the KEK algorithm.
1055 dprintf("SecCmsUtilDecryptSymKeyECDH: no KEK IV\n");
1060 * Now in order to derive the KEK proper, we have to create a
1061 * ECC-CMS-SharedInfo, which does not appear in the message, and DER
1062 * encode that struct, the result of which is used as the
1063 * SharedInfo value in the KEK key derive.
1065 memset(&sharedInfo
, 0, sizeof(sharedInfo
));
1066 sharedInfo
.algId
.algorithm
= kekOid
->oid
;
1067 sharedInfo
.algId
.parameters
.Data
= nullData
;
1068 sharedInfo
.algId
.parameters
.Length
= 2;
1069 sharedInfo
.entityUInfo
= *ukm
;
1070 int32ToBytes(kekSizeBits
, keyLenAsBytes
);
1071 sharedInfo
.suppPubInfo
.Length
= 4;
1072 sharedInfo
.suppPubInfo
.Data
= keyLenAsBytes
;
1073 if (!SEC_ASN1EncodeItem(pool
, &sharedInfoEnc
,
1074 &sharedInfo
, ECC_CMS_SharedInfoTemplate
)) {
1075 rv
= internalComponentErr
;
1078 dumpBuf("receiver encoded SharedInfo", &sharedInfoEnc
);
1079 dumpBuf("receiver IV", &iv
);
1080 dumpBuf("receiver UKM", ukm
);
1081 dumpBuf("sender's public key", pubKey
);
1083 /* pubKey is bit string, convert here */
1084 theirKeySizeInBits
= pubKey
->Length
;
1085 pubKey
->Length
= (theirKeySizeInBits
+ 7) >> 3;
1086 theirPubData
= CFDataCreate(NULL
, pubKey
->Data
, pubKey
->Length
);
1087 theirKeyLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &theirKeySizeInBits
);
1088 const void *keys
[] = { kSecAttrKeyType
, kSecAttrKeyClass
, kSecAttrKeySizeInBits
};
1089 const void *values
[] = { kSecAttrKeyTypeECSECPrimeRandom
, kSecAttrKeyClassPublic
, theirKeyLen
};
1090 theirKeyAttrs
= CFDictionaryCreate(NULL
, keys
, values
, 3,
1091 &kCFTypeDictionaryKeyCallBacks
,
1092 &kCFTypeDictionaryValueCallBacks
);
1093 theirPubKey
= SecKeyCreateWithData(theirPubData
, theirKeyAttrs
, &error
);
1095 dprintf("SecKeyCreateWithData: failed\n");
1100 sharedInfoData
= CFDataCreate(NULL
, sharedInfoEnc
.Data
, sharedInfoEnc
.Length
);
1101 int32_t ecdh_key_key_len
= (kekSizeBits
+ 7) >> 3;
1102 kekLen
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &ecdh_key_key_len
);
1103 const void *kekKeys
[] = { kSecKeyKeyExchangeParameterRequestedSize
, kSecKeyKeyExchangeParameterSharedInfo
};
1104 const void *kekValues
[] = { kekLen
, sharedInfoData
};
1105 kekParams
= CFDictionaryCreate(NULL
, kekKeys
, kekValues
, 2,
1106 &kCFTypeDictionaryKeyCallBacks
,
1107 &kCFTypeDictionaryValueCallBacks
);
1108 kekData
= SecKeyCopyKeyExchangeResult(privkey
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
,
1109 theirPubKey
, kekParams
, &error
);
1111 dprintf("SecKeyCopyKeyExchangeResult: failed\n");
1116 * Decrypt the raw CEK bits with the KEK we just derived
1118 CSSM_DATA cek
= { 0, NULL
};
1119 rv
= CCCryptorCreate(kCCDecrypt
, alg
, options
,
1120 CFDataGetBytePtr(kekData
), CFDataGetLength(kekData
), iv
.Data
, &ciphercc
);
1122 dprintf("CCCryptorCreate failed: %d\n", (int)rv
);
1125 size_t expectedKeyLength
= CCCryptorGetOutputLength(ciphercc
, encKey
->Length
, true);
1126 cek
.Data
= PORT_ArenaAlloc(pool
, expectedKeyLength
);
1127 size_t bytes_output
= 0;
1128 rv
= CCCryptorUpdate(ciphercc
, encKey
->Data
, encKey
->Length
, cek
.Data
, expectedKeyLength
, &bytes_output
);
1130 dprintf("CCCryptorUpdate failed: %d\n", (int)rv
);
1133 size_t final_bytes_output
= 0;
1134 rv
= CCCryptorFinal(ciphercc
, cek
.Data
+bytes_output
, expectedKeyLength
- bytes_output
, &final_bytes_output
);
1136 dprintf("CCCryptorFinal failed: %d\n", (int)rv
);
1139 cek
.Length
= bytes_output
+ final_bytes_output
;
1141 /* create the SecSymmetricKeyRef */
1142 cekData
= CFDataCreate(NULL
, cek
.Data
, cek
.Length
);
1143 keyType
= SECOID_CopyKeyTypeByTag(bulkalgtag
);
1147 cekParams
= CFDictionaryCreateMutable(NULL
, 1,
1148 &kCFTypeDictionaryKeyCallBacks
,
1149 &kCFTypeDictionaryValueCallBacks
);
1153 CFDictionaryAddValue(cekParams
, kSecAttrKeyType
, keyType
);
1154 outKey
= SecKeyCreateFromData(cekParams
, cekData
, NULL
);
1158 PORT_FreeArena(pool
, PR_FALSE
);
1160 if (theirPubData
) { CFRelease(theirPubData
); }
1161 if (theirKeyLen
) { CFRelease(theirKeyLen
); }
1162 if (theirPubKey
) { CFRelease(theirPubKey
); }
1163 if (theirKeyAttrs
) { CFRelease(theirKeyAttrs
); }
1164 if (sharedInfoData
) { CFRelease(sharedInfoData
); }
1165 if (kekLen
) { CFRelease(kekLen
); }
1166 if (kekParams
) { CFRelease(kekParams
); }
1167 if (kekData
) { CFRelease(kekData
); }
1168 if (error
) { CFRelease(error
); }
1169 if (ciphercc
) { CCCryptorRelease(ciphercc
); }
1170 if (cekData
) { CFRelease(cekData
); }
1171 if (keyType
) { CFRelease(keyType
); }
1172 if (cekParams
) { CFRelease(cekParams
); }
1173 if(outKey
== NULL
) {
1174 PORT_SetError(SEC_ERROR_NO_KEY
);