2 * Copyright (c) 2000-2001,2005-2008,2010-2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * appleCdsa.c - CDSA based implementation of sslCrypto.h interfaces.
31 #include "appleCdsa.h"
32 #include "sslCrypto.h"
34 #include "CipherSuite.h"
35 #include "sslContext.h"
36 #include "sslMemory.h"
40 #include "ModuleAttacher.h"
42 #ifndef _SSL_KEYCHAIN_H_
43 #include "sslKeychain.h"
50 #include <Security/cssm.h>
51 #include <Security/cssmapple.h>
52 #include <Security/Security.h>
53 #include <Security/SecTrustPriv.h>
54 #include <Security/SecPolicyPriv.h>
55 #include <Security/SecKeyPriv.h>
57 /* X.509 includes, from cssmapi */
58 #include <Security/x509defs.h> /* x.509 function and type defs */
59 #include <Security/oidsalg.h>
60 #include <Security/oidscert.h>
63 #pragma mark Utilities
66 * Set up a Raw symmetric key with specified algorithm and key bits.
68 OSStatus
sslSetUpSymmKey(
71 CSSM_KEYUSE keyUse
, // CSSM_KEYUSE_ENCRYPT, etc.
72 CSSM_BOOL copyKey
, // true: copy keyData false: set by reference
74 size_t keyDataLen
) // in bytes
79 memset(symKey
, 0, sizeof(CSSM_KEY
));
81 serr
= stSetUpCssmData(&symKey
->KeyData
, keyDataLen
);
85 memmove(symKey
->KeyData
.Data
, keyData
, keyDataLen
);
88 symKey
->KeyData
.Data
= keyData
;
89 symKey
->KeyData
.Length
= keyDataLen
;
92 /* set up the header */
93 hdr
= &symKey
->KeyHeader
;
94 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
95 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
96 hdr
->AlgorithmId
= alg
;
97 hdr
->KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
98 hdr
->LogicalKeySizeInBits
= keyDataLen
* 8;
99 hdr
->KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
100 hdr
->KeyUsage
= keyUse
;
101 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
106 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
109 CSSM_CSP_HANDLE cspHand
,
110 CSSM_KEY_PTR
*key
, /* so we can null it out */
111 #if ST_KC_KEYS_NEED_REF
112 SecKeychainRef
*kcItem
)
121 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
123 stAppFree(*key
, NULL
); // key mallocd by CL using our callback
126 #if ST_KC_KEYS_NEED_REF
127 if((kcItem
!= NULL
) && (*kcItem
!= NULL
)) {
128 KCReleaseItem(kcItem
); /* does this NULL the referent? */
136 * Standard app-level memory functions required by CDSA.
138 void * stAppMalloc (size_t size
, void *allocRef
) {
139 return( malloc(size
) );
141 void stAppFree (void *mem_ptr
, void *allocRef
) {
145 void * stAppRealloc (void *ptr
, size_t size
, void *allocRef
) {
146 return( realloc( ptr
, size
) );
148 void * stAppCalloc (uint32_t num
, size_t size
, void *allocRef
) {
149 return( calloc( num
, size
) );
153 * Ensure there's a connection to ctx->cspHand. If there
154 * already is one, fine.
155 * Note that as of 12/18/00, we assume we're connected to
156 * all modules all the time (since we do an attachToAll() in
159 OSStatus
attachToCsp(SSLContext
*ctx
)
162 if(ctx
->cspHand
!= 0) {
166 return errSSLModuleAttach
;
171 * Connect to TP, CL; reusable.
173 OSStatus
attachToCl(SSLContext
*ctx
)
176 if(ctx
->clHand
!= 0) {
180 return errSSLModuleAttach
;
184 OSStatus
attachToTp(SSLContext
*ctx
)
187 if(ctx
->tpHand
!= 0) {
191 return errSSLModuleAttach
;
196 * Convenience function - attach to CSP, CL, TP. Reusable.
198 OSStatus
attachToAll(SSLContext
*ctx
)
203 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
, &ctx
->tpHand
);
205 return errSSLModuleAttach
;
212 OSStatus
detachFromAll(SSLContext
*ctx
)
215 /* No more, attachments are kept on a global basis */
217 if(ctx
->cspHand
!= 0) {
218 CSSM_ModuleDetach(ctx
->cspHand
);
221 if(ctx
->tpHand
!= 0) {
222 CSSM_ModuleDetach(ctx
->tpHand
);
225 if(ctx
->clHand
!= 0) {
226 CSSM_ModuleDetach(ctx
->clHand
);
234 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
235 * specified crypto context.
237 static CSSM_RETURN
sslAddBlindingAttr(
238 CSSM_CC_HANDLE ccHand
)
240 CSSM_CONTEXT_ATTRIBUTE newAttr
;
243 newAttr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
244 newAttr
.AttributeLength
= sizeof(uint32_t);
245 newAttr
.Attribute
.Uint32
= 1;
246 crtn
= CSSM_UpdateContextAttributes(ccHand
, 1, &newAttr
);
248 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
253 /* Get CSP, key in CSSM format from a SecKeyRef */
254 static OSStatus
sslGetKeyParts(
256 const CSSM_KEY
**cssmKey
,
257 CSSM_CSP_HANDLE
*cspHand
)
259 OSStatus ortn
= SecKeyGetCSSMKey(keyRef
, cssmKey
);
261 sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n",
265 ortn
= SecKeyGetCSPHandle(keyRef
, cspHand
);
267 sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n",
273 /* Return the first certificate reference from the supplied array
274 * whose data matches the given certificate, or NULL if none match.
276 static SecCertificateRef
sslGetMatchingCertInArray(
277 SecCertificateRef certRef
,
278 CFArrayRef certArray
)
284 if(certRef
== NULL
|| certArray
== NULL
) {
287 ortn
= SecCertificateGetData(certRef
, &certData
);
289 count
= CFArrayGetCount(certArray
);
290 for(idx
=0; idx
<count
; idx
++) {
291 CSSM_DATA aData
= { 0, NULL
};
292 SecCertificateRef aCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(certArray
, idx
);
293 ortn
= SecCertificateGetData(aCert
, &aData
);
294 if (!ortn
&& aData
.Length
== certData
.Length
&&
295 !memcmp(aData
.Data
, certData
.Data
, certData
.Length
)) {
304 #pragma mark CSSM_DATA routines
306 CSSM_DATA_PTR
stMallocCssmData(
309 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
319 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
326 CSSM_BOOL freeStruct
)
331 if(data
->Data
!= NULL
) {
332 stAppFree(data
->Data
, NULL
);
337 stAppFree(data
, NULL
);
342 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
343 * Malloc the Data ptr if necessary.
345 OSStatus
stSetUpCssmData(
349 assert(data
!= NULL
);
350 if(data
->Length
== 0) {
351 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
352 if(data
->Data
== NULL
) {
356 else if(data
->Length
< length
) {
357 sslErrorLog("stSetUpCssmData: length too small\n");
360 data
->Length
= length
;
364 /* All signature ops are "raw", with digest step done by us */
365 static OSStatus
sslKeyToSigAlg(
366 const CSSM_KEY
*cssmKey
,
367 CSSM_ALGORITHMS
*sigAlg
) /* RETURNED */
370 OSStatus ortn
= noErr
;
371 switch(cssmKey
->KeyHeader
.AlgorithmId
) {
373 *sigAlg
= CSSM_ALGID_RSA
;
376 *sigAlg
= CSSM_ALGID_DSA
;
378 case CSSM_ALGID_ECDSA
:
379 *sigAlg
= CSSM_ALGID_ECDSA
;
382 ortn
= errSSLBadConfiguration
;
389 #pragma mark Public CSP Functions
392 * Raw RSA/DSA sign/verify.
396 SecKeyRef privKeyRef
,
397 const UInt8
*plainText
,
399 UInt8
*sig
, // mallocd by caller; RETURNED
400 size_t sigLen
, // available
401 size_t *actualBytes
) // RETURNED
403 CSSM_CC_HANDLE sigHand
= 0;
408 CSSM_CSP_HANDLE cspHand
;
409 const CSSM_KEY
*privKey
;
410 const CSSM_ACCESS_CREDENTIALS
*creds
;
413 if((privKeyRef
== NULL
) ||
414 (plainText
== NULL
) ||
416 (actualBytes
== NULL
)) {
417 sslErrorLog("sslRsaRawSign: bad arguments\n");
418 return errSSLInternal
;
422 /* Get CSP, signing key in CSSM format */
423 serr
= sslGetKeyParts(privKeyRef
, &privKey
, &cspHand
);
427 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
429 CSSM_ALGORITHMS sigAlg
;
430 serr
= sslKeyToSigAlg(privKey
, &sigAlg
);
437 * FIXME: per 3420180, this needs to allow app-specified creds via
440 serr
= SecKeyGetCredentials(privKeyRef
,
441 CSSM_ACL_AUTHORIZATION_SIGN
,
442 kSecCredentialTypeDefault
,
445 sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", (unsigned long)serr
);
449 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
455 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
459 if((ctx
->rsaBlindingEnable
) &&
460 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
462 * Turn on RSA blinding to defeat timing attacks
464 crtn
= sslAddBlindingAttr(sigHand
);
470 ptextData
.Data
= (uint8
*)plainText
;
471 ptextData
.Length
= plainTextLen
;
473 /* caller better get this right, or the SignData will fail */
475 sigData
.Length
= sigLen
;
477 crtn
= CSSM_SignData(sigHand
,
480 CSSM_ALGID_NONE
, // digestAlg for raw sign
483 stPrintCdsaError("CSSM_SignData", crtn
);
487 *actualBytes
= sigData
.Length
;
491 CSSM_DeleteContext(sigHand
);
496 OSStatus
sslRawVerify(
498 const SSLPubKey
*sslPubKey
,
499 const UInt8
*plainText
,
504 CSSM_CC_HANDLE sigHand
= 0;
509 const CSSM_KEY
*pubKey
;
510 CSSM_CSP_HANDLE cspHand
;
513 if((sslPubKey
== NULL
) ||
514 (sslPubKey
->key
== NULL
) ||
515 (sslPubKey
->csp
== 0) ||
516 (plainText
== NULL
) ||
518 sslErrorLog("sslRawVerify: bad arguments\n");
519 return errSSLInternal
;
522 pubKey
= &sslPubKey
->key
;
523 cspHand
= sslPubKey
->csp
;
525 CSSM_ALGORITHMS sigAlg
;
526 serr
= sslKeyToSigAlg(pubKey
, &sigAlg
);
530 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
536 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
540 ptextData
.Data
= (uint8
*)plainText
;
541 ptextData
.Length
= plainTextLen
;
542 sigData
.Data
= (uint8
*)sig
;
543 sigData
.Length
= sigLen
;
545 crtn
= CSSM_VerifyData(sigHand
,
548 CSSM_ALGID_NONE
, // digestAlg
551 stPrintCdsaError("CSSM_VerifyData", crtn
);
558 CSSM_DeleteContext(sigHand
);
566 OSStatus
sslRsaEncrypt(
568 const CSSM_KEY
*pubKey
,
569 CSSM_CSP_HANDLE cspHand
,
570 CSSM_PADDING padding
, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2
571 const UInt8
*plainText
,
573 UInt8
*cipherText
, // mallocd by caller; RETURNED
574 size_t cipherTextLen
, // available
575 size_t *actualBytes
) // RETURNED
577 CSSM_DATA ctextData
= {0, NULL
};
579 CSSM_DATA remData
= {0, NULL
};
580 CSSM_CC_HANDLE cryptHand
= 0;
581 OSStatus serr
= errSSLInternal
;
583 size_t bytesMoved
= 0;
584 CSSM_ACCESS_CREDENTIALS creds
;
587 assert(actualBytes
!= NULL
);
590 if((pubKey
== NULL
) || (cspHand
== 0)) {
591 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
592 return errSSLInternal
;
594 assert(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
);
596 #if RSA_PUB_KEY_USAGE_HACK
597 ((CSSM_KEY_PTR
)pubKey
)->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
599 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
601 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
608 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
611 ptextData
.Data
= (uint8
*)plainText
;
612 ptextData
.Length
= plainTextLen
;
615 * Have CSP malloc ciphertext
617 crtn
= CSSM_EncryptData(cryptHand
,
624 if(crtn
== CSSM_OK
) {
626 * ciphertext in both ctextData and remData; ensure it'll fit
627 * in caller's buf & copy
629 if(bytesMoved
> cipherTextLen
) {
630 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %lu bytesMoved %lu\n",
631 cipherTextLen
, bytesMoved
);
638 *actualBytes
= bytesMoved
;
640 * Snag valid data from ctextData - its length or bytesMoved,
643 if(ctextData
.Length
> bytesMoved
) {
644 /* everything's in ctext */
645 toMoveCtext
= bytesMoved
;
649 /* must be some in remData too */
650 toMoveCtext
= ctextData
.Length
;
651 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
654 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
657 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
664 stPrintCdsaError("CSSM_EncryptData", crtn
);
668 CSSM_DeleteContext(cryptHand
);
671 /* free data mallocd by CSP */
672 stFreeCssmData(&ctextData
, CSSM_FALSE
);
673 stFreeCssmData(&remData
, CSSM_FALSE
);
677 OSStatus
sslRsaDecrypt(
679 SecKeyRef privKeyRef
,
680 CSSM_PADDING padding
, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2
681 const UInt8
*cipherText
,
682 size_t cipherTextLen
,
683 UInt8
*plainText
, // mallocd by caller; RETURNED
684 size_t plainTextLen
, // available
685 size_t *actualBytes
) // RETURNED
687 CSSM_DATA ptextData
= {0, NULL
};
689 CSSM_DATA remData
= {0, NULL
};
690 CSSM_CC_HANDLE cryptHand
= 0;
691 OSStatus serr
= errSSLInternal
;
693 size_t bytesMoved
= 0;
694 CSSM_CSP_HANDLE cspHand
;
695 const CSSM_KEY
*privKey
;
696 const CSSM_ACCESS_CREDENTIALS
*creds
;
699 assert(actualBytes
!= NULL
);
702 if(privKeyRef
== NULL
) {
703 sslErrorLog("sslRsaDecrypt: bad privKey\n");
704 return errSSLInternal
;
707 /* Get CSP, signing key in CSSM format */
708 serr
= sslGetKeyParts(privKeyRef
, &privKey
, &cspHand
);
712 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
716 * FIXME: per 3420180, this needs to allow app-specified creds via
719 serr
= SecKeyGetCredentials(privKeyRef
,
720 CSSM_ACL_AUTHORIZATION_DECRYPT
,
721 kSecCredentialTypeDefault
,
724 sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", (unsigned long)serr
);
727 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
734 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
737 ctextData
.Data
= (uint8
*)cipherText
;
738 ctextData
.Length
= cipherTextLen
;
740 if((ctx
->rsaBlindingEnable
) &&
741 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
743 * Turn on RSA blinding to defeat timing attacks
745 crtn
= sslAddBlindingAttr(cryptHand
);
752 * Have CSP malloc plaintext
754 crtn
= CSSM_DecryptData(cryptHand
,
761 if(crtn
== CSSM_OK
) {
763 * plaintext in both ptextData and remData; ensure it'll fit
764 * in caller's buf & copy
766 if(bytesMoved
> plainTextLen
) {
767 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %lu bytesMoved %lu\n",
768 plainTextLen
, bytesMoved
);
775 *actualBytes
= bytesMoved
;
777 * Snag valid data from ptextData - its length or bytesMoved,
780 if(ptextData
.Length
> bytesMoved
) {
781 /* everything's in ptext */
782 toMovePtext
= bytesMoved
;
786 /* must be some in remData too */
787 toMovePtext
= ptextData
.Length
;
788 toMoveRem
= bytesMoved
- toMovePtext
; // remainder
791 memmove(plainText
, ptextData
.Data
, toMovePtext
);
794 memmove(plainText
+ toMovePtext
, remData
.Data
,
801 stPrintCdsaError("CSSM_DecryptData", crtn
);
805 CSSM_DeleteContext(cryptHand
);
808 /* free data mallocd by CSP */
809 stFreeCssmData(&ptextData
, CSSM_FALSE
);
810 stFreeCssmData(&remData
, CSSM_FALSE
);
815 * Obtain size of key in bytes.
817 uint32_t sslPrivKeyLengthInBytes(const SSLPrivKey
*sslKey
)
819 const CSSM_KEY
*cssmKey
;
821 assert(sslKey
!= NULL
);
822 assert(sslKey
->key
!= NULL
);
823 err
= SecKeyGetCSSMKey(sslKey
->key
, &cssmKey
);
825 sslErrorLog("sslKeyLengthInBytes: SecKeyGetCSSMKey err %d\n", (int)err
);
829 return (((cssmKey
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
833 * Obtain size of key in bytes.
835 uint32_t sslPubKeyLengthInBytes(const SSLPubKey
*sslKey
)
837 const CSSM_KEY
*cssmKey
;
839 assert(sslKey
!= NULL
);
840 assert(sslKey
->key
!= NULL
);
842 return (((sslKey
->key
.KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
847 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
848 * ask the CSP to do this but that would be kind of expensive.
850 OSStatus
sslGetMaxSigSize(
851 const CSSM_KEY
*privKey
,
852 uint32_t *maxSigSize
)
854 OSStatus ortn
= noErr
;
855 assert(privKey
!= NULL
);
856 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
857 switch(privKey
->KeyHeader
.AlgorithmId
) {
859 *maxSigSize
= sslPrivKeyLengthInBytes(privKey
);
863 /* DSA sig is DER sequence of two 160-bit integers */
864 uint32_t sizeOfOneInt
;
865 sizeOfOneInt
= (160 / 8) + // the raw contents
866 1 + // possible leading zero
867 2; // tag + length (assume DER, not BER)
868 *maxSigSize
= (2 * sizeOfOneInt
) + 5;
872 ortn
= errSSLBadConfiguration
;
878 * Get raw key bits from an RSA public key.
880 OSStatus
sslGetPubKeyBits(
882 const CSSM_KEY
*pubKey
,
883 CSSM_CSP_HANDLE cspHand
,
884 SSLBuffer
*modulus
, // data mallocd and RETURNED
885 SSLBuffer
*exponent
) // data mallocd and RETURNED
888 CSSM_BOOL didWrap
= CSSM_FALSE
;
889 const CSSM_KEYHEADER
*hdr
;
890 SSLBuffer pubKeyBlob
;
894 assert(modulus
!= NULL
);
895 assert(exponent
!= NULL
);
896 assert(pubKey
!= NULL
);
898 hdr
= &pubKey
->KeyHeader
;
899 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
900 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", (long)hdr
->KeyClass
);
901 return errSSLInternal
;
903 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
904 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", (long)hdr
->AlgorithmId
);
905 return errSSLInternal
;
908 /* Note currently ALL public keys are raw, obtained from the CL... */
909 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
912 * Handle possible reference format - I think it should be in
913 * blob form since it came from the DL, but conversion is
916 switch(hdr
->BlobType
) {
917 case CSSM_KEYBLOB_RAW
:
919 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
922 case CSSM_KEYBLOB_REFERENCE
:
924 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
925 (long)hdr
->BlobType
);
926 return errSSLInternal
;
930 * Convert to a blob via "NULL wrap"; no wrapping key,
933 srtn
= attachToCsp(ctx
);
937 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
938 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
948 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
951 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
952 crtn
= CSSM_WrapKey(ccHand
,
955 NULL
, // descriptiveData
957 CSSM_DeleteContext(ccHand
);
959 stPrintCdsaError("CSSM_WrapKey", crtn
);
962 hdr
= &wrappedKey
.KeyHeader
;
963 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
964 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
969 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
974 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
975 (long)hdr
->BlobType
);
976 return errSSLInternal
;
978 } /* switch BlobType */
980 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
981 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
983 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
989 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
990 * Server-initiated key exchange.
992 OSStatus
sslGetPubKeyFromBits(
994 const SSLBuffer
*modulus
,
995 const SSLBuffer
*exponent
,
996 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
997 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
999 CSSM_KEY_PTR key
= NULL
;
1002 CSSM_KEYHEADER_PTR hdr
;
1003 CSSM_KEY_SIZE keySize
;
1006 assert((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
1007 assert((pubKey
!= NULL
) && (cspHand
!= NULL
));
1012 serr
= attachToCsp(ctx
);
1016 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
1021 /* the rest is boilerplate, cook up a good-looking public key */
1022 key
= (CSSM_KEY_PTR
)sslMalloc(sizeof(CSSM_KEY
));
1026 memset(key
, 0, sizeof(CSSM_KEY
));
1027 hdr
= &key
->KeyHeader
;
1029 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
1030 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
1031 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
1032 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
1033 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
1034 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1035 /* comply with ASA requirements */
1036 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
1037 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
1038 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
1039 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
1040 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
1041 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
1043 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
1045 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
1048 * Get keySizeInBits. This also serves to validate the key blob
1049 * we just cooked up.
1051 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
1053 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
1054 serr
= errSSLCrypto
;
1059 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
1061 *cspHand
= ctx
->cspHand
;
1065 /* note this frees the blob */
1066 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
1070 #ifdef UNUSED_FUNCTIONS
1072 * NULL-unwrap a raw key to a ref key. Caller must free the returned key.
1074 static OSStatus
sslNullUnwrapKey(
1075 CSSM_CSP_HANDLE cspHand
,
1076 CSSM_KEY_PTR rawKey
,
1077 CSSM_KEY_PTR refKey
)
1079 CSSM_DATA descData
= {0, 0};
1081 CSSM_CC_HANDLE ccHand
;
1082 CSSM_ACCESS_CREDENTIALS creds
;
1083 CSSM_DATA labelData
= {4, (uint8
*)"none"};
1085 OSStatus ortn
= noErr
;
1087 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1088 memset(refKey
, 0, sizeof(CSSM_KEY
));
1090 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
1094 NULL
, // unwrappingKey
1100 stPrintCdsaError("sslNullUnwrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn
);
1101 return errSSLCrypto
;
1104 keyAttr
= rawKey
->KeyHeader
.KeyAttr
;
1105 keyAttr
&= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
|
1106 CSSM_KEYATTR_MODIFIABLE
);
1107 keyAttr
|= CSSM_KEYATTR_RETURN_REF
;
1108 if(rawKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1110 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1112 crtn
= CSSM_UnwrapKey(ccHand
,
1115 rawKey
->KeyHeader
.KeyUsage
,
1118 NULL
, // CredAndAclEntry
1120 &descData
); // required
1121 if(crtn
!= CSSM_OK
) {
1122 stPrintCdsaError("sslNullUnwrapKey: CSSM_UnwrapKey\n", crtn
);
1123 ortn
= errSSLCrypto
;
1125 if(CSSM_DeleteContext(ccHand
)) {
1126 printf("CSSM_DeleteContext failure\n");
1133 * NULL-wrap a ref key to a raw key. Caller must free the returned key.
1135 static OSStatus
sslNullWrapKey(
1136 CSSM_CSP_HANDLE cspHand
,
1137 CSSM_KEY_PTR refKey
,
1138 CSSM_KEY_PTR rawKey
)
1140 CSSM_DATA descData
= {0, 0};
1142 CSSM_CC_HANDLE ccHand
;
1143 CSSM_ACCESS_CREDENTIALS creds
;
1145 OSStatus ortn
= noErr
;
1147 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1148 memset(rawKey
, 0, sizeof(CSSM_KEY
));
1150 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
1154 NULL
, // unwrappingKey
1160 stPrintCdsaError("sslNullWrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn
);
1161 return errSSLCrypto
;
1164 keyAttr
= rawKey
->KeyHeader
.KeyAttr
;
1165 keyAttr
&= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
|
1166 CSSM_KEYATTR_MODIFIABLE
);
1167 keyAttr
|= CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
1168 crtn
= CSSM_WrapKey(ccHand
,
1173 if(crtn
!= CSSM_OK
) {
1174 stPrintCdsaError("sslNullWrapKey: CSSM_WrapKey\n", crtn
);
1175 ortn
= errSSLCrypto
;
1177 if(CSSM_DeleteContext(ccHand
)) {
1178 printf("CSSM_DeleteContext failure\n");
1184 #pragma mark Public Certificate Functions
1187 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
1188 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
1190 * For now, the returned cspHand is a copy of ctx->cspHand, so it
1191 * doesn't have to be detached later - this may change.
1193 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
1194 * us to tell the CL what CSP to use, we really have no way of knowing
1195 * what is going on here...we return the process-wide (bare) cspHand,
1196 * which is currently always able to deal with this raw public key.
1198 OSStatus
sslPubKeyFromCert(
1200 const SSLBuffer
*derCert
,
1201 SSLPubKey
*pubKey
) // RETURNED
1207 assert(ctx
!= NULL
);
1208 assert(pubKey
!= NULL
);
1211 pubKey
->cspHand
= 0;
1213 serr
= attachToCl(ctx
);
1217 serr
= attachToCsp(ctx
);
1221 SSLBUF_TO_CSSM(derCert
, &certData
);
1222 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, &pubKey
->key
);
1224 return errSSLBadCert
;
1227 pubKey
->cspHand
= ctx
->cspHand
;
1233 * Release each element in a CFArray.
1235 static void sslReleaseArray(
1238 CFIndex num
= CFArrayGetCount(a
);
1240 for(dex
=0; dex
<num
; dex
++) {
1241 CFTypeRef elmt
= (CFTypeRef
)CFArrayGetValueAtIndex(a
, dex
);
1242 secdebug("sslcert", "Freeing cert %p", elmt
);
1248 * Verify a chain of DER-encoded certs.
1249 * Last cert in the chain is leaf.
1251 * If arePeerCerts is true, host name verification is enabled and we
1252 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
1253 * we're just validating our own certs; no host name checking and
1254 * peerSecTrust is transient.
1256 OSStatus
sslVerifyCertChain(
1258 const SSLCertificate
*certChain
,
1264 SSLCertificate
*c
= (SSLCertificate
*)certChain
;
1266 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
1267 CSSM_APPLE_TP_ACTION_DATA tpActionData
;
1268 SecPolicyRef policy
= NULL
;
1269 SecPolicySearchRef policySearch
= NULL
;
1270 CFDataRef actionData
= NULL
;
1271 CSSM_DATA sslOptsData
;
1272 CFMutableArrayRef anchors
= NULL
;
1273 SecCertificateRef cert
; // only lives in CFArrayRefs
1274 SecTrustResultType secTrustResult
;
1275 CFMutableArrayRef kcList
= NULL
;
1276 SecTrustRef theTrust
= NULL
;
1278 if(ctx
->peerSecTrust
&& arePeerCerts
) {
1279 /* renegotiate - start with a new SecTrustRef */
1280 CFRelease(ctx
->peerSecTrust
);
1281 ctx
->peerSecTrust
= NULL
;
1284 numCerts
= SSLGetCertificateChainLength(certChain
);
1287 return errSSLBadCert
;
1291 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
1292 * TP Cert group has root at the end, opposite of
1293 * SSLCertificate chain.
1295 CFMutableArrayRef certGroup
= CFArrayCreateMutable(NULL
, numCerts
,
1296 &kCFTypeArrayCallBacks
);
1297 if(certGroup
== NULL
) {
1300 /* subsequent errors to errOut: */
1302 for(i
=numCerts
-1; i
>=0; i
--) {
1304 SSLBUF_TO_CSSM(&c
->derCert
, &cdata
);
1305 serr
= SecCertificateCreateFromData(&cdata
, CSSM_CERT_X_509v3
,
1306 CSSM_CERT_ENCODING_DER
, &cert
);
1311 * Can't set a value at index i when there is an empty element
1314 secdebug("sslcert", "Adding cert %p", cert
);
1315 CFArrayInsertValueAtIndex(certGroup
, 0, cert
);
1320 * Cook up an SSL-specific SecPolicyRef. This will persists as part
1321 * of the SecTrustRef object we'll be creating.
1323 serr
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
1324 &CSSMOID_APPLE_TP_SSL
,
1328 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
1332 serr
= SecPolicySearchCopyNext(policySearch
, &policy
);
1334 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
1338 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
1340 sslOpts
.ServerNameLen
= ctx
->peerDomainNameLen
;
1341 sslOpts
.ServerName
= ctx
->peerDomainName
;
1344 sslOpts
.ServerNameLen
= 0;
1345 sslOpts
.ServerName
= NULL
;
1348 if(ctx
->protocolSide
== kSSLServerSide
) {
1349 /* we're evaluating a client cert */
1350 sslOpts
.Flags
|= CSSM_APPLE_TP_SSL_CLIENT
;
1352 sslOptsData
.Data
= (uint8
*)&sslOpts
;
1353 sslOptsData
.Length
= sizeof(sslOpts
);
1354 serr
= SecPolicySetValue(policy
, &sslOptsData
);
1356 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
1361 /* now a SecTrustRef */
1362 serr
= SecTrustCreateWithCertificates(certGroup
, policy
, &theTrust
);
1364 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
1365 "rtn %d\n", (int)serr
);
1369 /* anchors - default, or ours? */
1370 if(ctx
->trustedCerts
!= NULL
) {
1371 serr
= SecTrustSetAnchorCertificates(theTrust
, ctx
->trustedCerts
);
1373 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
1374 "rtn %d\n", (int)serr
);
1378 tpActionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
1379 tpActionData
.ActionFlags
= 0;
1380 if(ctx
->allowExpiredCerts
) {
1381 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED
;
1383 if(ctx
->allowExpiredRoots
) {
1384 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
;
1386 actionData
= CFDataCreate(NULL
, (UInt8
*)&tpActionData
, sizeof(tpActionData
));
1388 serr
= SecTrustSetParameters(theTrust
, CSSM_TP_ACTION_DEFAULT
,
1391 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
1397 /* Disabled for Radar 3421314 */
1399 * Avoid searching user keychains for intermediate certs by specifying
1400 * an empty array of keychains
1402 kcList
= CFArrayCreateMutable(NULL
, 0, NULL
);
1403 if(kcList
== NULL
) {
1404 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
1408 serr
= SecTrustSetKeychains(theTrust
, kcList
);
1410 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
1417 * Save this no matter what if we're evaluating peer certs.
1418 * We do a retain here so we can unconditionally release theTrust
1419 * at the end of this routine in case of previous error or
1423 ctx
->peerSecTrust
= theTrust
;
1427 if(!ctx
->enableCertVerify
) {
1428 /* trivial case, this is caller's responsibility */
1434 * If the caller provided a list of trusted leaf certs, check them here
1436 if(ctx
->trustedLeafCerts
) {
1437 if (sslGetMatchingCertInArray((SecCertificateRef
)CFArrayGetValueAtIndex(certGroup
, 0),
1438 ctx
->trustedLeafCerts
)) {
1445 * Here we go; hand it over to SecTrust/TP.
1447 serr
= SecTrustEvaluate(theTrust
, &secTrustResult
);
1449 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
1453 switch(secTrustResult
) {
1454 case kSecTrustResultUnspecified
:
1455 /* cert chain valid, no special UserTrust assignments */
1456 case kSecTrustResultProceed
:
1457 /* cert chain valid AND user explicitly trusts this */
1460 case kSecTrustResultDeny
:
1461 case kSecTrustResultConfirm
:
1463 * Cert chain may well have verified OK, but user has flagged
1464 * one of these certs as untrustable.
1466 crtn
= CSSMERR_TP_NOT_TRUSTED
;
1471 serr
= SecTrustGetCssmResultCode(theTrust
, &osCrtn
);
1473 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
1474 " rtn %d\n", (int)serr
);
1481 /* get some detailed error info */
1483 case CSSMERR_TP_INVALID_ANCHOR_CERT
:
1484 /* root found but we don't trust it */
1485 if(ctx
->allowAnyRoot
) {
1487 sslErrorLog("***Warning: accepting unknown root cert\n");
1490 serr
= errSSLUnknownRootCert
;
1493 case CSSMERR_TP_NOT_TRUSTED
:
1494 /* no root, not even in implicit SSL roots */
1495 if(ctx
->allowAnyRoot
) {
1496 sslErrorLog("***Warning: accepting unverified cert chain\n");
1500 serr
= errSSLNoRootCert
;
1503 case CSSMERR_TP_CERT_EXPIRED
:
1504 assert(!ctx
->allowExpiredCerts
);
1505 serr
= errSSLCertExpired
;
1507 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1508 serr
= errSSLCertNotYetValid
;
1510 case CSSMERR_APPLETP_HOSTNAME_MISMATCH
:
1511 serr
= errSSLHostNameMismatch
;
1513 case errSecInvalidTrustSettings
:
1514 /* these get passed along unmodified */
1518 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1520 serr
= errSSLXCertChainInvalid
;
1523 } /* SecTrustEvaluate error */
1527 * Free up resources - certGroup, policy, etc. Note that most of these
1528 * will actually persist as long as the current SSLContext does since
1529 * peerSecTrust holds references to these.
1535 CFRelease(policySearch
);
1538 CFRelease(actionData
);
1541 sslReleaseArray(anchors
);
1545 sslReleaseArray(certGroup
);
1546 CFRelease(certGroup
);
1549 /* empty, no contents to release */
1553 CFRelease(theTrust
);
1559 void stPrintCdsaError(const char *op
, CSSM_RETURN crtn
)
1561 cssmPerror(op
, crtn
);
1566 #pragma mark Diffie-Hellman Support
1569 * Generate a Diffie-Hellman key pair. Algorithm parameters always
1570 * come from the server, so on client side we have the parameters
1571 * as two SSLBuffers. On server side we have the pre-encoded block
1572 * which comes from ServerDhParams.
1574 OSStatus
sslDhGenKeyPairClient(
1576 const SSLBuffer
*prime
,
1577 const SSLBuffer
*generator
,
1578 CSSM_KEY_PTR publicKey
, // RETURNED
1579 CSSM_KEY_PTR privateKey
) // RETURNED
1581 assert((prime
->data
!= NULL
) && (generator
->data
!= NULL
));
1582 if(prime
->data
&& !generator
->data
) {
1583 return errSSLProtocol
;
1585 if(!prime
->data
&& generator
->data
) {
1586 return errSSLProtocol
;
1590 OSStatus ortn
= sslEncodeDhParams(prime
, generator
, &sParam
);
1592 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
1595 ortn
= sslDhGenerateKeyPair(ctx
, &sParam
, prime
->length
* 8, publicKey
, privateKey
);
1596 SSLFreeBuffer(&sParam
, ctx
);
1600 OSStatus
sslDhGenerateKeyPair(
1602 const SSLBuffer
*paramBlob
,
1603 uint32_t keySizeInBits
,
1604 CSSM_KEY_PTR publicKey
, // RETURNED
1605 CSSM_KEY_PTR privateKey
) // RETURNED
1608 CSSM_CC_HANDLE ccHandle
;
1609 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1610 OSStatus ortn
= noErr
;
1611 CSSM_DATA cParamBlob
;
1613 assert(ctx
!= NULL
);
1614 assert(ctx
->cspHand
!= 0);
1616 memset(publicKey
, 0, sizeof(CSSM_KEY
));
1617 memset(privateKey
, 0, sizeof(CSSM_KEY
));
1618 SSLBUF_TO_CSSM(paramBlob
, &cParamBlob
);
1620 crtn
= CSSM_CSP_CreateKeyGenContext(ctx
->cspHand
,
1630 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn
);
1631 return errSSLCrypto
;
1634 crtn
= CSSM_GenerateKeyPair(ccHandle
,
1635 CSSM_KEYUSE_DERIVE
, // only legal use of a Diffie-Hellman key
1636 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1639 /* private key specification */
1641 CSSM_KEYATTR_RETURN_REF
,
1642 &labelData
, // same labels
1643 NULL
, // CredAndAclEntry
1646 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn
);
1647 ortn
= errSSLCrypto
;
1649 CSSM_DeleteContext(ccHandle
);
1654 * Perform Diffie-Hellman key exchange.
1659 * This generates deriveSizeInBits of key-exchanged data.
1662 /* the alg isn't important; we just want to be able to cook up lots of bits */
1663 #define DERIVE_KEY_ALG CSSM_ALGID_RC5
1665 OSStatus
sslDhKeyExchange(
1667 uint32_t deriveSizeInBits
,
1668 SSLBuffer
*exchanged
)
1671 CSSM_ACCESS_CREDENTIALS creds
;
1672 CSSM_CC_HANDLE ccHandle
;
1673 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1674 CSSM_KEY derivedKey
;
1675 OSStatus ortn
= noErr
;
1677 assert(ctx
!= NULL
);
1678 assert(ctx
->cspHand
!= 0);
1679 assert(ctx
->dhPrivate
!= NULL
);
1680 if(ctx
->dhPeerPublic
.length
== 0) {
1681 /* comes from peer, don't panic */
1682 sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
1683 return errSSLProtocol
;
1686 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1687 memset(&derivedKey
, 0, sizeof(CSSM_KEY
));
1689 crtn
= CSSM_CSP_CreateDeriveKeyContext(ctx
->cspHand
,
1694 ctx
->dhPrivate
, // BaseKey
1695 0, // IterationCount
1700 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn
);
1701 return errSSLCrypto
;
1704 /* public key passed in as CSSM_DATA *Param */
1705 CSSM_DATA theirPubKeyData
;
1706 SSLBUF_TO_CSSM(&ctx
->dhPeerPublic
, &theirPubKeyData
);
1708 crtn
= CSSM_DeriveKey(ccHandle
,
1711 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1716 stPrintCdsaError("DH CSSM_DeriveKey", crtn
);
1717 ortn
= errSSLCrypto
;
1720 CSSM_TO_SSLBUF(&derivedKey
.KeyData
, exchanged
);
1722 CSSM_DeleteContext(ccHandle
);
1727 #pragma mark *** ECDSA support ***
1729 /* specify either 32-bit integer or a pointer as an added attribute value */
1736 * Given a context specified via a CSSM_CC_HANDLE, add a new
1737 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
1738 * AttributeLength, and an untyped pointer.
1740 static CSSM_RETURN
sslAddContextAttribute(CSSM_CC_HANDLE CCHandle
,
1741 uint32 AttributeType
,
1742 uint32 AttributeLength
,
1743 ContextAttrType attrType
,
1744 /* specify exactly one of these */
1745 const void *AttributePtr
,
1746 uint32 attributeInt
)
1748 CSSM_CONTEXT_ATTRIBUTE newAttr
;
1751 newAttr
.AttributeType
= AttributeType
;
1752 newAttr
.AttributeLength
= AttributeLength
;
1753 if(attrType
== CAT_Uint32
) {
1754 newAttr
.Attribute
.Uint32
= attributeInt
;
1757 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
1759 crtn
= CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
1761 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
1767 * Generate ECDH key pair with the given SSL_ECDSA_NamedCurve.
1768 * Private key, in ref form, is placed in ctx->ecdhPrivate.
1769 * Public key, in ECPoint form - which can NOT be used as
1770 * a key in any CSP ops - is placed in ecdhExchangePublic.
1772 OSStatus
sslEcdhGenerateKeyPair(
1774 SSL_ECDSA_NamedCurve namedCurve
)
1777 CSSM_CC_HANDLE ccHandle
= 0;
1778 CSSM_DATA labelData
= {8, (uint8
*)"ecdsaKey"};
1779 OSStatus ortn
= noErr
;
1781 uint32 keySizeInBits
;
1783 assert(ctx
!= NULL
);
1784 assert(ctx
->cspHand
!= 0);
1785 sslFreeKey(ctx
->ecdhPrivCspHand
, &ctx
->ecdhPrivate
, NULL
);
1786 SSLFreeBuffer(&ctx
->ecdhExchangePublic
, ctx
);
1788 switch(namedCurve
) {
1789 case SSL_Curve_secp256r1
:
1790 keySizeInBits
= 256;
1792 case SSL_Curve_secp384r1
:
1793 keySizeInBits
= 384;
1795 case SSL_Curve_secp521r1
:
1796 keySizeInBits
= 521;
1799 /* should not have gotten this far */
1800 sslErrorLog("sslEcdhGenerateKeyPair: bad namedCurve (%u)\n",
1801 (unsigned)namedCurve
);
1802 return errSSLInternal
;
1805 ctx
->ecdhPrivate
= (CSSM_KEY
*)sslMalloc(sizeof(CSSM_KEY
));
1807 memset(ctx
->ecdhPrivate
, 0, sizeof(CSSM_KEY
));
1808 memset(&pubKey
, 0, sizeof(CSSM_KEY
));
1810 crtn
= CSSM_CSP_CreateKeyGenContext(ctx
->cspHand
,
1820 stPrintCdsaError("ECDH CSSM_CSP_CreateKeyGenContext", crtn
);
1821 return errSSLCrypto
;
1823 /* subsequent errors to errOut: */
1826 * Here's how we get the raw ECPoint form of a public key
1828 crtn
= sslAddContextAttribute(ccHandle
,
1829 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT
,
1833 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
);
1835 ortn
= errSSLCrypto
;
1839 crtn
= CSSM_GenerateKeyPair(ccHandle
,
1840 /* public key specification */
1841 CSSM_KEYUSE_DERIVE
, // only legal use - right?
1842 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1845 /* private key specification */
1847 CSSM_KEYATTR_RETURN_REF
,
1848 &labelData
, // same labels
1849 NULL
, // CredAndAclEntry
1852 stPrintCdsaError("ECDH CSSM_GenerateKeyPair", crtn
);
1853 ortn
= errSSLCrypto
;
1856 ctx
->ecdhPrivCspHand
= ctx
->cspHand
;
1859 * Take that public key data, drop it into ecdhExchangePublic,
1862 ortn
= SSLCopyBufferFromData(pubKey
.KeyData
.Data
, pubKey
.KeyData
.Length
,
1863 &ctx
->ecdhExchangePublic
);
1864 CSSM_FreeKey(ctx
->cspHand
, NULL
, &pubKey
, CSSM_FALSE
);
1868 CSSM_DeleteContext(ccHandle
);
1875 * Perform ECDH key exchange. Obtained key material is the same
1876 * size as our private key.
1878 * On entry, ecdhPrivate is our private key. The peer's public key
1879 * is either ctx->ecdhPeerPublic for ECDHE exchange, or
1880 * ctx->peerPubKey for ECDH exchange.
1882 OSStatus
sslEcdhKeyExchange(
1884 SSLBuffer
*exchanged
)
1887 CSSM_ACCESS_CREDENTIALS creds
;
1888 const CSSM_ACCESS_CREDENTIALS
*secCreds
;
1889 const CSSM_ACCESS_CREDENTIALS
*useCreds
= &creds
;
1890 CSSM_CC_HANDLE ccHandle
;
1891 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1892 CSSM_KEY derivedKey
;
1893 OSStatus ortn
= noErr
;
1895 bool useRefKeys
= false;
1897 SSLBuffer pubKeyBits
= {0, NULL
};
1899 assert(ctx
!= NULL
);
1900 assert(ctx
->ecdhPrivCspHand
!= 0);
1901 assert(ctx
->ecdhPrivate
!= NULL
);
1903 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1904 memset(&derivedKey
, 0, sizeof(CSSM_KEY
));
1905 memset(&rawKey
, 0, sizeof(CSSM_KEY
));
1908 * If we're using an actual CSSM_KEY for the peer public key, and its
1909 * cspHand differs from our private key, we do things a bit different -
1910 * our key is in the CSPDL space, and it has a Sec-style ACL for which
1911 * we need creds. Also, the peer public key and the derived key have
1912 * to be in reference form.
1914 switch(ctx
->selectedCipherSpec
.keyExchangeMethod
) {
1915 case SSL_ECDH_ECDSA
:
1917 if(ctx
->cspHand
!= ctx
->ecdhPrivCspHand
) {
1925 assert(ctx
->signingPrivKeyRef
!= NULL
);
1926 ortn
= SecKeyGetCredentials(ctx
->signingPrivKeyRef
,
1927 CSSM_ACL_AUTHORIZATION_DERIVE
,
1928 kSecCredentialTypeDefault
,
1931 stPrintCdsaError("ECDH SecKeyGetCredentials", ortn
);
1934 useCreds
= secCreds
;
1936 crtn
= CSSM_CSP_CreateDeriveKeyContext(ctx
->ecdhPrivCspHand
,
1939 ctx
->ecdhPrivate
->KeyHeader
.LogicalKeySizeInBits
,
1941 ctx
->ecdhPrivate
, // BaseKey
1942 0, // IterationCount
1947 stPrintCdsaError("ECDH CSSM_CSP_CreateDeriveKeyContext", crtn
);
1948 return errSSLCrypto
;
1950 /* subsequent errors to errOut: */
1952 CSSM_DATA theirPubKeyData
= {0, NULL
};
1954 switch(ctx
->selectedCipherSpec
.keyExchangeMethod
) {
1955 case SSL_ECDHE_ECDSA
:
1957 /* public key passed in as CSSM_DATA *Param */
1958 if(ctx
->ecdhPeerPublic
.length
== 0) {
1959 /* comes from peer, don't panic */
1960 sslErrorLog("sslEcdhKeyExchange: null peer public key\n");
1961 ortn
= errSSLProtocol
;
1964 SSLBUF_TO_CSSM(&ctx
->ecdhPeerPublic
, &theirPubKeyData
);
1966 case SSL_ECDH_ECDSA
:
1968 /* add pub key as a context attr */
1969 if(ctx
->peerPubKey
== NULL
) {
1970 sslErrorLog("sslEcdhKeyExchange: no peer key\n");
1971 ortn
= errSSLInternal
;
1976 * If we're using CSPDL, extract the raw public key bits in ECPoint
1977 * form and transmit as CSSM_DATA *Param.
1978 * The securityd can't transmit a public key in a DeriveKey context
1982 ortn
= sslEcdsaPubKeyBits(ctx
->peerPubKey
, &pubKeyBits
);
1986 SSLBUF_TO_CSSM(&pubKeyBits
, &theirPubKeyData
);
1989 crtn
= sslAddContextAttribute(ccHandle
,
1990 CSSM_ATTRIBUTE_PUBLIC_KEY
,
1993 (void *)ctx
->peerPubKey
,
1996 stPrintCdsaError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
1998 ortn
= errSSLInternal
;
2004 /* shouldn't be here */
2006 ortn
= errSSLInternal
;
2011 keyAttr
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
;
2014 keyAttr
= CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
;
2016 crtn
= CSSM_DeriveKey(ccHandle
,
2024 stPrintCdsaError("ECDH CSSM_DeriveKey", crtn
);
2025 ortn
= errSSLCrypto
;
2031 * one more step: NULL-wrap the generated ref key to something we
2034 ortn
= sslNullWrapKey(ctx
->ecdhPrivCspHand
, &derivedKey
, &rawKey
);
2038 ortn
= SSLCopyBufferFromData(rawKey
.KeyData
.Data
, rawKey
.KeyData
.Length
,
2042 ortn
= SSLCopyBufferFromData(derivedKey
.KeyData
.Data
,
2043 derivedKey
.KeyData
.Length
, exchanged
);
2046 CSSM_DeleteContext(ccHandle
);
2048 if(pubKeyBits
.length
) {
2049 SSLFreeBuffer(&pubKeyBits
, ctx
);
2051 if(rawKey
.KeyData
.Length
) {
2052 CSSM_FreeKey(ctx
->ecdhPrivCspHand
, NULL
, &rawKey
, CSSM_FALSE
);
2060 * After ciphersuite negotiation is complete, verify that we have
2061 * the capability of actually performing the selected cipher.
2062 * Currently we just verify that we have a cert and private signing
2063 * key, if needed, and that the signing key's algorithm matches the
2064 * expected key exchange method.
2066 * This is currently called from FindCipherSpec(), after it sets
2067 * ctx->selectedCipherSuite to a (supposedly) valid value, and from
2068 * sslBuildCipherSuiteArray(), in server mode (pre-negotiation) only.
2070 OSStatus
sslVerifySelectedCipher(
2072 const SSLCipherSpec
*selectedCipherSpec
)
2074 if(ctx
->protocolSide
== kSSLClientSide
) {
2077 #if SSL_PAC_SERVER_ENABLE
2078 if((ctx
->masterSecretCallback
!= NULL
) &&
2079 (ctx
->sessionTicket
.data
!= NULL
)) {
2080 /* EAP via PAC resumption; we can do it */
2083 #endif /* SSL_PAC_SERVER_ENABLE */
2085 CSSM_ALGORITHMS requireAlg
= CSSM_ALGID_NONE
;
2086 if(selectedCipherSpec
== NULL
) {
2087 return errSSLInternal
;
2089 switch (selectedCipherSpec
->keyExchangeMethod
) {
2091 case SSL_RSA_EXPORT
:
2093 case SSL_DH_RSA_EXPORT
:
2095 case SSL_DHE_RSA_EXPORT
:
2096 requireAlg
= CSSM_ALGID_RSA
;
2099 case SSL_DHE_DSS_EXPORT
:
2101 case SSL_DH_DSS_EXPORT
:
2102 requireAlg
= CSSM_ALGID_DSA
;
2105 case SSL_DH_anon_EXPORT
:
2106 /* CSSM_ALGID_NONE, no signing key */
2109 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
2110 * we'll need to add some logic here...
2112 #if SSL_ECDSA_SERVER
2113 #error Work needed in sslVerifySelectedCipher
2117 /* needs update per cipherSpecs.c */
2119 return errSSLInternal
;
2121 if(requireAlg
== CSSM_ALGID_NONE
) {
2125 /* private signing key required */
2126 if(ctx
->signingPrivKeyRef
== NULL
) {
2127 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
2128 return errSSLBadConfiguration
;
2131 const CSSM_KEY
*cssmKey
;
2132 OSStatus ortn
= SecKeyGetCSSMKey(ctx
->signingPrivKeyRef
, &cssmKey
);
2134 sslErrorLog("sslVerifySelectedCipher: SecKeyGetCSSMKey err %d\n",
2138 if(cssmKey
->KeyHeader
.AlgorithmId
!= requireAlg
) {
2139 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
2140 return errSSLBadConfiguration
;
2146 #endif /* USE_CDSA_CRYPTO */