2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
22 Contains: interface between SSL and CDSA
24 Written by: Doug Mitchell
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
31 #include "sslContext.h"
32 #include "sslMemory.h"
33 #include "appleCdsa.h"
37 #include "ModuleAttacher.h"
39 #ifndef _SSL_KEYCHAIN_H_
40 #include "sslKeychain.h"
47 #include <Security/cssm.h>
48 #include <Security/cssmapple.h>
49 #include <Security/cssmerrno.h>
50 #include <Security/Security.h>
51 #include <Security/SecTrustPriv.h>
52 #include <Security/SecPolicyPriv.h>
53 #include <Security/SecKeyPriv.h>
55 /* X.509 includes, from cssmapi */
56 #include <Security/x509defs.h> /* x.509 function and type defs */
57 #include <Security/oidsalg.h>
58 #include <Security/oidscert.h>
60 #pragma mark *** Utilities ***
63 * Set up a Raw symmetric key with specified algorithm and key bits.
65 OSStatus
sslSetUpSymmKey(
68 CSSM_KEYUSE keyUse
, // CSSM_KEYUSE_ENCRYPT, etc.
69 CSSM_BOOL copyKey
, // true: copy keyData false: set by reference
71 uint32 keyDataLen
) // in bytes
76 memset(symKey
, 0, sizeof(CSSM_KEY
));
78 serr
= stSetUpCssmData(&symKey
->KeyData
, keyDataLen
);
82 memmove(symKey
->KeyData
.Data
, keyData
, keyDataLen
);
85 symKey
->KeyData
.Data
= keyData
;
86 symKey
->KeyData
.Length
= keyDataLen
;
89 /* set up the header */
90 hdr
= &symKey
->KeyHeader
;
91 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
92 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
93 hdr
->AlgorithmId
= alg
;
94 hdr
->KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
95 hdr
->LogicalKeySizeInBits
= keyDataLen
* 8;
96 hdr
->KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
97 hdr
->KeyUsage
= keyUse
;
98 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
103 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
106 CSSM_CSP_HANDLE cspHand
,
107 CSSM_KEY_PTR
*key
, /* so we can null it out */
108 #if ST_KC_KEYS_NEED_REF
109 SecKeychainRef
*kcItem
)
118 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
120 stAppFree(*key
, NULL
); // key mallocd by CL using our callback
123 #if ST_KC_KEYS_NEED_REF
124 if((kcItem
!= NULL
) && (*kcItem
!= NULL
)) {
125 KCReleaseItem(kcItem
); /* does this NULL the referent? */
133 * Standard app-level memory functions required by CDSA.
135 void * stAppMalloc (uint32 size
, void *allocRef
) {
136 return( malloc(size
) );
138 void stAppFree (void *mem_ptr
, void *allocRef
) {
142 void * stAppRealloc (void *ptr
, uint32 size
, void *allocRef
) {
143 return( realloc( ptr
, size
) );
145 void * stAppCalloc (uint32 num
, uint32 size
, void *allocRef
) {
146 return( calloc( num
, size
) );
150 * Ensure there's a connection to ctx->cspHand. If there
151 * already is one, fine.
152 * Note that as of 12/18/00, we assume we're connected to
153 * all modules all the time (since we do an attachToAll() in
156 OSStatus
attachToCsp(SSLContext
*ctx
)
159 if(ctx
->cspHand
!= 0) {
163 return errSSLModuleAttach
;
168 * Connect to TP, CL; reusable.
170 OSStatus
attachToCl(SSLContext
*ctx
)
173 if(ctx
->clHand
!= 0) {
177 return errSSLModuleAttach
;
181 OSStatus
attachToTp(SSLContext
*ctx
)
184 if(ctx
->tpHand
!= 0) {
188 return errSSLModuleAttach
;
193 * Convenience function - attach to CSP, CL, TP. Reusable.
195 OSStatus
attachToAll(SSLContext
*ctx
)
200 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
, &ctx
->tpHand
);
202 return errSSLModuleAttach
;
209 OSStatus
detachFromAll(SSLContext
*ctx
)
212 /* No more, attachments are kept on a global basis */
214 if(ctx
->cspHand
!= 0) {
215 CSSM_ModuleDetach(ctx
->cspHand
);
218 if(ctx
->tpHand
!= 0) {
219 CSSM_ModuleDetach(ctx
->tpHand
);
222 if(ctx
->clHand
!= 0) {
223 CSSM_ModuleDetach(ctx
->clHand
);
231 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
232 * specified crypto context.
234 static CSSM_RETURN
sslAddBlindingAttr(
235 CSSM_CC_HANDLE ccHand
)
237 CSSM_CONTEXT_ATTRIBUTE newAttr
;
240 newAttr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
241 newAttr
.AttributeLength
= sizeof(uint32
);
242 newAttr
.Attribute
.Uint32
= 1;
243 crtn
= CSSM_UpdateContextAttributes(ccHand
, 1, &newAttr
);
245 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
250 /* Get CSP, key in CSSM format from a SecKeyRef */
251 static OSStatus
sslGetKeyParts(
253 const CSSM_KEY
**cssmKey
,
254 CSSM_CSP_HANDLE
*cspHand
)
256 OSStatus ortn
= SecKeyGetCSSMKey(keyRef
, cssmKey
);
258 sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n",
262 ortn
= SecKeyGetCSPHandle(keyRef
, cspHand
);
264 sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n",
271 #pragma mark *** CSSM_DATA routines ***
273 CSSM_DATA_PTR
stMallocCssmData(
276 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
286 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
293 CSSM_BOOL freeStruct
)
298 if(data
->Data
!= NULL
) {
299 stAppFree(data
->Data
, NULL
);
304 stAppFree(data
, NULL
);
309 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
310 * Malloc the Data ptr if necessary.
312 OSStatus
stSetUpCssmData(
316 assert(data
!= NULL
);
317 if(data
->Length
== 0) {
318 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
319 if(data
->Data
== NULL
) {
323 else if(data
->Length
< length
) {
324 sslErrorLog("stSetUpCssmData: length too small\n");
327 data
->Length
= length
;
331 static OSStatus
sslKeyToSigAlg(
332 const CSSM_KEY
*cssmKey
,
333 CSSM_ALGORITHMS
&sigAlg
) /* RETURNED */
336 OSStatus ortn
= noErr
;
337 switch(cssmKey
->KeyHeader
.AlgorithmId
) {
339 sigAlg
= CSSM_ALGID_RSA
;
342 sigAlg
= CSSM_ALGID_DSA
;
345 ortn
= errSSLBadConfiguration
;
352 #pragma mark *** Public CSP Functions ***
355 * Raw RSA/DSA sign/verify.
359 SecKeyRef privKeyRef
,
360 const UInt8
*plainText
,
362 UInt8
*sig
, // mallocd by caller; RETURNED
363 UInt32 sigLen
, // available
364 UInt32
*actualBytes
) // RETURNED
366 CSSM_CC_HANDLE sigHand
= 0;
371 CSSM_CSP_HANDLE cspHand
;
372 const CSSM_KEY
*privKey
;
373 const CSSM_ACCESS_CREDENTIALS
*creds
;
376 if((privKeyRef
== NULL
) ||
377 (plainText
== NULL
) ||
379 (actualBytes
== NULL
)) {
380 sslErrorLog("sslRsaRawSign: bad arguments\n");
381 return errSSLInternal
;
385 /* Get CSP, signing key in CSSM format */
386 serr
= sslGetKeyParts(privKeyRef
, &privKey
, &cspHand
);
390 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
392 CSSM_ALGORITHMS sigAlg
;
393 serr
= sslKeyToSigAlg(privKey
, sigAlg
);
400 * FIXME: per 3420180, this needs to allow app-specified creds via
403 serr
= SecKeyGetCredentials(privKeyRef
,
404 CSSM_ACL_AUTHORIZATION_SIGN
,
405 kSecCredentialTypeDefault
,
408 sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", serr
);
412 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
418 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
422 if((ctx
->rsaBlindingEnable
) &&
423 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
425 * Turn on RSA blinding to defeat timing attacks
427 crtn
= sslAddBlindingAttr(sigHand
);
433 ptextData
.Data
= (uint8
*)plainText
;
434 ptextData
.Length
= plainTextLen
;
436 /* caller better get this right, or the SignData will fail */
438 sigData
.Length
= sigLen
;
440 crtn
= CSSM_SignData(sigHand
,
443 CSSM_ALGID_NONE
, // digestAlg for raw sign
446 stPrintCdsaError("CSSM_SignData", crtn
);
450 *actualBytes
= sigData
.Length
;
454 CSSM_DeleteContext(sigHand
);
459 OSStatus
sslRawVerify(
461 const CSSM_KEY
*pubKey
,
462 CSSM_CSP_HANDLE cspHand
,
463 const UInt8
*plainText
,
468 CSSM_CC_HANDLE sigHand
= 0;
475 if((pubKey
== NULL
) ||
477 (plainText
== NULL
) ||
479 sslErrorLog("sslRawVerify: bad arguments\n");
480 return errSSLInternal
;
483 CSSM_ALGORITHMS sigAlg
;
484 serr
= sslKeyToSigAlg(pubKey
, sigAlg
);
488 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
494 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
498 ptextData
.Data
= (uint8
*)plainText
;
499 ptextData
.Length
= plainTextLen
;
500 sigData
.Data
= (uint8
*)sig
;
501 sigData
.Length
= sigLen
;
503 crtn
= CSSM_VerifyData(sigHand
,
506 CSSM_ALGID_NONE
, // digestAlg
509 stPrintCdsaError("CSSM_VerifyData", crtn
);
516 CSSM_DeleteContext(sigHand
);
524 OSStatus
sslRsaEncrypt(
526 const CSSM_KEY
*pubKey
,
527 CSSM_CSP_HANDLE cspHand
,
528 const UInt8
*plainText
,
530 UInt8
*cipherText
, // mallocd by caller; RETURNED
531 UInt32 cipherTextLen
, // available
532 UInt32
*actualBytes
) // RETURNED
534 CSSM_DATA ctextData
= {0, NULL
};
536 CSSM_DATA remData
= {0, NULL
};
537 CSSM_CC_HANDLE cryptHand
= 0;
538 OSStatus serr
= errSSLInternal
;
540 uint32 bytesMoved
= 0;
541 CSSM_ACCESS_CREDENTIALS creds
;
544 assert(actualBytes
!= NULL
);
547 if((pubKey
== NULL
) || (cspHand
== 0)) {
548 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
549 return errSSLInternal
;
551 assert(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
);
553 #if RSA_PUB_KEY_USAGE_HACK
554 ((CSSM_KEY_PTR
)pubKey
)->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
556 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
558 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
565 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
568 ptextData
.Data
= (uint8
*)plainText
;
569 ptextData
.Length
= plainTextLen
;
572 * Have CSP malloc ciphertext
574 crtn
= CSSM_EncryptData(cryptHand
,
581 if(crtn
== CSSM_OK
) {
583 * ciphertext in both ctextData and remData; ensure it'll fit
584 * in caller's buf & copy
586 if(bytesMoved
> cipherTextLen
) {
587 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
588 cipherTextLen
, bytesMoved
);
595 *actualBytes
= bytesMoved
;
597 * Snag valid data from ctextData - its length or bytesMoved,
600 if(ctextData
.Length
> bytesMoved
) {
601 /* everything's in ctext */
602 toMoveCtext
= bytesMoved
;
606 /* must be some in remData too */
607 toMoveCtext
= ctextData
.Length
;
608 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
611 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
614 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
621 stPrintCdsaError("CSSM_EncryptData", crtn
);
625 CSSM_DeleteContext(cryptHand
);
628 /* free data mallocd by CSP */
629 stFreeCssmData(&ctextData
, CSSM_FALSE
);
630 stFreeCssmData(&remData
, CSSM_FALSE
);
634 OSStatus
sslRsaDecrypt(
636 SecKeyRef privKeyRef
,
637 const UInt8
*cipherText
,
638 UInt32 cipherTextLen
,
639 UInt8
*plainText
, // mallocd by caller; RETURNED
640 UInt32 plainTextLen
, // available
641 UInt32
*actualBytes
) // RETURNED
643 CSSM_DATA ptextData
= {0, NULL
};
645 CSSM_DATA remData
= {0, NULL
};
646 CSSM_CC_HANDLE cryptHand
= 0;
647 OSStatus serr
= errSSLInternal
;
649 uint32 bytesMoved
= 0;
650 CSSM_CSP_HANDLE cspHand
;
651 const CSSM_KEY
*privKey
;
652 const CSSM_ACCESS_CREDENTIALS
*creds
;
655 assert(actualBytes
!= NULL
);
658 if(privKeyRef
== NULL
) {
659 sslErrorLog("sslRsaDecrypt: bad privKey\n");
660 return errSSLInternal
;
663 /* Get CSP, signing key in CSSM format */
664 serr
= sslGetKeyParts(privKeyRef
, &privKey
, &cspHand
);
668 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
672 * FIXME: per 3420180, this needs to allow app-specified creds via
675 serr
= SecKeyGetCredentials(privKeyRef
,
676 CSSM_ACL_AUTHORIZATION_DECRYPT
,
677 kSecCredentialTypeDefault
,
680 sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", serr
);
683 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
690 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
693 ctextData
.Data
= (uint8
*)cipherText
;
694 ctextData
.Length
= cipherTextLen
;
696 if((ctx
->rsaBlindingEnable
) &&
697 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
699 * Turn on RSA blinding to defeat timing attacks
701 crtn
= sslAddBlindingAttr(cryptHand
);
708 * Have CSP malloc plaintext
710 crtn
= CSSM_DecryptData(cryptHand
,
717 if(crtn
== CSSM_OK
) {
719 * plaintext in both ptextData and remData; ensure it'll fit
720 * in caller's buf & copy
722 if(bytesMoved
> plainTextLen
) {
723 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
724 plainTextLen
, bytesMoved
);
731 *actualBytes
= bytesMoved
;
733 * Snag valid data from ptextData - its length or bytesMoved,
736 if(ptextData
.Length
> bytesMoved
) {
737 /* everything's in ptext */
738 toMovePtext
= bytesMoved
;
742 /* must be some in remData too */
743 toMovePtext
= ptextData
.Length
;
744 toMoveRem
= bytesMoved
- toMovePtext
; // remainder
747 memmove(plainText
, ptextData
.Data
, toMovePtext
);
750 memmove(plainText
+ toMovePtext
, remData
.Data
,
757 stPrintCdsaError("CSSM_DecryptData", crtn
);
761 CSSM_DeleteContext(cryptHand
);
764 /* free data mallocd by CSP */
765 stFreeCssmData(&ptextData
, CSSM_FALSE
);
766 stFreeCssmData(&remData
, CSSM_FALSE
);
771 * Obtain size of key in bytes.
773 UInt32
sslKeyLengthInBytes(const CSSM_KEY
*key
)
776 return (((key
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
780 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
781 * ask the CSP to do this but that would be kind of expensive.
783 OSStatus
sslGetMaxSigSize(
784 const CSSM_KEY
*privKey
,
787 OSStatus ortn
= noErr
;
788 assert(privKey
!= NULL
);
789 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
790 switch(privKey
->KeyHeader
.AlgorithmId
) {
792 maxSigSize
= sslKeyLengthInBytes(privKey
);
796 /* DSA sig is DER sequence of two 160-bit integers */
798 sizeOfOneInt
= (160 / 8) + // the raw contents
799 1 + // possible leading zero
800 2; // tag + length (assume DER, not BER)
801 maxSigSize
= (2 * sizeOfOneInt
) + 5;
805 ortn
= errSSLBadConfiguration
;
811 * Get raw key bits from an RSA public key.
813 OSStatus
sslGetPubKeyBits(
815 const CSSM_KEY
*pubKey
,
816 CSSM_CSP_HANDLE cspHand
,
817 SSLBuffer
*modulus
, // data mallocd and RETURNED
818 SSLBuffer
*exponent
) // data mallocd and RETURNED
821 CSSM_BOOL didWrap
= CSSM_FALSE
;
822 const CSSM_KEYHEADER
*hdr
;
823 SSLBuffer pubKeyBlob
;
827 assert(modulus
!= NULL
);
828 assert(exponent
!= NULL
);
829 assert(pubKey
!= NULL
);
831 hdr
= &pubKey
->KeyHeader
;
832 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
833 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr
->KeyClass
);
834 return errSSLInternal
;
836 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
837 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr
->AlgorithmId
);
838 return errSSLInternal
;
841 /* Note currently ALL public keys are raw, obtained from the CL... */
842 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
845 * Handle possible reference format - I think it should be in
846 * blob form since it came from the DL, but conversion is
849 switch(hdr
->BlobType
) {
850 case CSSM_KEYBLOB_RAW
:
852 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
855 case CSSM_KEYBLOB_REFERENCE
:
857 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
859 return errSSLInternal
;
863 * Convert to a blob via "NULL wrap"; no wrapping key,
866 srtn
= attachToCsp(ctx
);
870 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
871 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
881 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
884 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
885 crtn
= CSSM_WrapKey(ccHand
,
888 NULL
, // descriptiveData
890 CSSM_DeleteContext(ccHand
);
892 stPrintCdsaError("CSSM_WrapKey", crtn
);
895 hdr
= &wrappedKey
.KeyHeader
;
896 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
897 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
902 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
907 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
909 return errSSLInternal
;
911 } /* switch BlobType */
913 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
914 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
916 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
922 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
923 * Server-initiated key exchange.
925 OSStatus
sslGetPubKeyFromBits(
927 const SSLBuffer
*modulus
,
928 const SSLBuffer
*exponent
,
929 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
930 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
932 CSSM_KEY_PTR key
= NULL
;
935 CSSM_KEYHEADER_PTR hdr
;
936 CSSM_KEY_SIZE keySize
;
939 assert((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
940 assert((pubKey
!= NULL
) && (cspHand
!= NULL
));
945 serr
= attachToCsp(ctx
);
949 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
954 /* the rest is boilerplate, cook up a good-looking public key */
955 key
= (CSSM_KEY_PTR
)sslMalloc(sizeof(CSSM_KEY
));
959 memset(key
, 0, sizeof(CSSM_KEY
));
960 hdr
= &key
->KeyHeader
;
962 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
963 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
964 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
965 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
966 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
967 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
968 /* comply with ASA requirements */
969 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
970 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
971 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
972 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
973 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
974 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
976 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
978 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
981 * Get keySizeInBits. This also serves to validate the key blob
984 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
986 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
992 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
994 *cspHand
= ctx
->cspHand
;
998 /* note this frees the blob */
999 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
1004 #pragma mark *** Public Certificate Functions ***
1007 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
1008 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
1010 * For now, the returned cspHand is a copy of ctx->cspHand, so it
1011 * doesn't have to be detached later - this may change.
1013 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
1014 * us to tell the CL what CSP to use, we really have no way of knowing
1015 * what is going on here...we return the process-wide (bare) cspHand,
1016 * which is currently always able to deal with this raw public key.
1018 OSStatus
sslPubKeyFromCert(
1020 const SSLBuffer
&derCert
,
1021 CSSM_KEY_PTR
*pubKey
, // RETURNED
1022 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
1028 assert(ctx
!= NULL
);
1029 assert(pubKey
!= NULL
);
1030 assert(cspHand
!= NULL
);
1035 serr
= attachToCl(ctx
);
1039 serr
= attachToCsp(ctx
);
1043 SSLBUF_TO_CSSM(&derCert
, &certData
);
1044 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, pubKey
);
1046 return errSSLBadCert
;
1049 *cspHand
= ctx
->cspHand
;
1055 * Release each element in a CFArray.
1057 static void sslReleaseArray(
1060 CFIndex num
= CFArrayGetCount(a
);
1061 for(CFIndex dex
=0; dex
<num
; dex
++) {
1062 CFTypeRef elmt
= (CFTypeRef
)CFArrayGetValueAtIndex(a
, dex
);
1063 secdebug("sslcert", "Freeing cert %p", elmt
);
1069 * Verify a chain of DER-encoded certs.
1070 * First cert in a chain is root; this must also be present
1071 * in ctx->trustedCerts.
1073 * If arePeerCerts is true, host name verification is enabled and we
1074 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
1075 * we're just validating our own certs; no host name checking and
1076 * peerSecTrust is transient.
1078 OSStatus
sslVerifyCertChain(
1080 const SSLCertificate
&certChain
,
1081 bool arePeerCerts
/* = true */)
1086 SSLCertificate
*c
= (SSLCertificate
*)&certChain
;
1088 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
1089 CSSM_APPLE_TP_ACTION_DATA tpActionData
;
1090 SecPolicyRef policy
= NULL
;
1091 SecPolicySearchRef policySearch
= NULL
;
1092 CFDataRef actionData
= NULL
;
1093 CSSM_DATA sslOptsData
;
1094 CFMutableArrayRef anchors
= NULL
;
1095 SecCertificateRef cert
; // only lives in CFArrayRefs
1096 SecTrustResultType secTrustResult
;
1097 CFMutableArrayRef kcList
= NULL
;
1098 SecTrustRef theTrust
= NULL
;
1100 if(ctx
->peerSecTrust
&& arePeerCerts
) {
1101 /* renegotiate - start with a new SecTrustRef */
1102 CFRelease(ctx
->peerSecTrust
);
1103 ctx
->peerSecTrust
= NULL
;
1106 numCerts
= SSLGetCertificateChainLength(&certChain
);
1109 return errSSLBadCert
;
1113 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
1114 * TP Cert group has root at the end, opposite of
1115 * SSLCertificate chain.
1117 CFMutableArrayRef certGroup
= CFArrayCreateMutable(NULL
, numCerts
,
1118 &kCFTypeArrayCallBacks
);
1119 if(certGroup
== NULL
) {
1122 /* subsequent errors to errOut: */
1124 for(i
=numCerts
-1; i
>=0; i
--) {
1126 SSLBUF_TO_CSSM(&c
->derCert
, &cdata
);
1127 serr
= SecCertificateCreateFromData(&cdata
, CSSM_CERT_X_509v3
,
1128 CSSM_CERT_ENCODING_DER
, &cert
);
1133 * Can't set a value at index i when there is an empty element
1136 secdebug("sslcert", "Adding cert %p", cert
);
1137 CFArrayInsertValueAtIndex(certGroup
, 0, cert
);
1142 * Cook up an SSL-specific SecPolicyRef. This will persists as part
1143 * of the SecTrustRef object we'll be creating.
1145 serr
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
1146 &CSSMOID_APPLE_TP_SSL
,
1150 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
1154 serr
= SecPolicySearchCopyNext(policySearch
, &policy
);
1156 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
1160 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
1162 sslOpts
.ServerNameLen
= ctx
->peerDomainNameLen
;
1163 sslOpts
.ServerName
= ctx
->peerDomainName
;
1166 sslOpts
.ServerNameLen
= 0;
1167 sslOpts
.ServerName
= NULL
;
1169 sslOptsData
.Data
= (uint8
*)&sslOpts
;
1170 sslOptsData
.Length
= sizeof(sslOpts
);
1171 serr
= SecPolicySetValue(policy
, &sslOptsData
);
1173 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
1178 /* now a SecTrustRef */
1179 serr
= SecTrustCreateWithCertificates(certGroup
, policy
, &theTrust
);
1181 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
1182 "rtn %d\n", (int)serr
);
1186 /* anchors - default, or ours? */
1187 if(ctx
->numTrustedCerts
!= 0) {
1188 anchors
= CFArrayCreateMutable(NULL
, ctx
->numTrustedCerts
,
1189 &kCFTypeArrayCallBacks
);
1190 if(anchors
== NULL
) {
1194 for(i
=0; i
<(int)ctx
->numTrustedCerts
; i
++) {
1195 serr
= SecCertificateCreateFromData(&ctx
->trustedCerts
[i
],
1196 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
1200 secdebug("sslcert", "Adding cert %p", cert
);
1201 CFArraySetValueAtIndex(anchors
, i
, cert
);
1203 serr
= SecTrustSetAnchorCertificates(theTrust
, anchors
);
1205 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
1206 "rtn %d\n", (int)serr
);
1210 tpActionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
1211 tpActionData
.ActionFlags
= 0;
1212 if(ctx
->allowExpiredCerts
) {
1213 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED
;
1215 if(ctx
->allowExpiredRoots
) {
1216 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
;
1218 actionData
= CFDataCreate(NULL
, (UInt8
*)&tpActionData
, sizeof(tpActionData
));
1220 serr
= SecTrustSetParameters(theTrust
, CSSM_TP_ACTION_DEFAULT
,
1223 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
1229 /* Disabled for Radar 3421314 */
1231 * Avoid searching user keychains for intermediate certs by specifying
1232 * an empty array of keychains
1234 kcList
= CFArrayCreateMutable(NULL
, 0, NULL
);
1235 if(kcList
== NULL
) {
1236 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
1240 serr
= SecTrustSetKeychains(theTrust
, kcList
);
1242 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
1249 * Save this no matter what if we're evaluating peer certs.
1250 * We do a retain here so we can unconditionally release theTrust
1251 * at the end of this routine in case of previous error or
1255 ctx
->peerSecTrust
= theTrust
;
1259 if(!ctx
->enableCertVerify
) {
1260 /* trivial case, this is caller's responsibility */
1266 * Here we go; hand it over to SecTrust/TP.
1268 serr
= SecTrustEvaluate(theTrust
, &secTrustResult
);
1270 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
1274 switch(secTrustResult
) {
1275 case kSecTrustResultUnspecified
:
1276 /* cert chain valid, no special UserTrust assignments */
1277 case kSecTrustResultProceed
:
1278 /* cert chain valid AND user explicitly trusts this */
1281 case kSecTrustResultDeny
:
1282 case kSecTrustResultConfirm
:
1284 * Cert chain may well have verified OK, but user has flagged
1285 * one of these certs as untrustable.
1287 crtn
= CSSMERR_TP_NOT_TRUSTED
;
1292 serr
= SecTrustGetCssmResultCode(theTrust
, &osCrtn
);
1294 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
1295 " rtn %d\n", (int)serr
);
1302 /* get some detailed error info */
1304 case CSSMERR_TP_INVALID_ANCHOR_CERT
:
1305 /* root found but we don't trust it */
1306 if(ctx
->allowAnyRoot
) {
1308 sslErrorLog("***Warning: accepting unknown root cert\n");
1311 serr
= errSSLUnknownRootCert
;
1314 case CSSMERR_TP_NOT_TRUSTED
:
1315 /* no root, not even in implicit SSL roots */
1316 if(ctx
->allowAnyRoot
) {
1317 sslErrorLog("***Warning: accepting unverified cert chain\n");
1321 serr
= errSSLNoRootCert
;
1324 case CSSMERR_TP_CERT_EXPIRED
:
1325 assert(!ctx
->allowExpiredCerts
);
1326 serr
= errSSLCertExpired
;
1328 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1329 serr
= errSSLCertNotYetValid
;
1332 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1334 serr
= errSSLXCertChainInvalid
;
1337 } /* SecTrustEvaluate error */
1341 * Free up resources - certGroup, policy, etc. Note that most of these
1342 * will actually persist as long as the current SSLContext does since
1343 * peerSecTrust holds references to these.
1349 CFRelease(policySearch
);
1352 CFRelease(actionData
);
1355 sslReleaseArray(anchors
);
1359 sslReleaseArray(certGroup
);
1360 CFRelease(certGroup
);
1363 /* empty, no contents to release */
1367 CFRelease(theTrust
);
1373 void stPrintCdsaError(const char *op
, CSSM_RETURN crtn
)
1375 cssmPerror(op
, crtn
);
1378 char *stCssmErrToStr(CSSM_RETURN err
)
1380 string errStr
= cssmErrorString(err
);
1381 return const_cast<char *>(errStr
.c_str());
1386 #pragma mark *** Diffie-Hellman support ***
1389 * Generate a Diffie-Hellman key pair. Algorithm parameters always
1390 * come from the server, so on client side we have the parameters
1391 * as two SSLBuffers. On server side we have the pre-encoded block
1392 * which comes from ServerDhParams.
1394 OSStatus
sslDhGenKeyPairClient(
1396 const SSLBuffer
&prime
,
1397 const SSLBuffer
&generator
,
1398 CSSM_KEY_PTR publicKey
, // RETURNED
1399 CSSM_KEY_PTR privateKey
) // RETURNED
1401 assert((prime
.data
!= NULL
) && (generator
.data
!= NULL
));
1402 if(prime
.data
&& !generator
.data
) {
1403 return errSSLProtocol
;
1405 if(!prime
.data
&& generator
.data
) {
1406 return errSSLProtocol
;
1410 OSStatus ortn
= sslEncodeDhParams(&prime
, &generator
, &sParam
);
1412 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
1415 ortn
= sslDhGenerateKeyPair(ctx
, sParam
, prime
.length
* 8, publicKey
, privateKey
);
1416 SSLFreeBuffer(sParam
, ctx
);
1420 OSStatus
sslDhGenerateKeyPair(
1422 const SSLBuffer
¶mBlob
,
1423 UInt32 keySizeInBits
,
1424 CSSM_KEY_PTR publicKey
, // RETURNED
1425 CSSM_KEY_PTR privateKey
) // RETURNED
1428 CSSM_CC_HANDLE ccHandle
;
1429 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1430 OSStatus ortn
= noErr
;
1431 CSSM_DATA cParamBlob
;
1433 assert(ctx
!= NULL
);
1434 assert(ctx
->cspHand
!= 0);
1436 memset(publicKey
, 0, sizeof(CSSM_KEY
));
1437 memset(privateKey
, 0, sizeof(CSSM_KEY
));
1438 SSLBUF_TO_CSSM(¶mBlob
, &cParamBlob
);
1440 crtn
= CSSM_CSP_CreateKeyGenContext(ctx
->cspHand
,
1450 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn
);
1451 return errSSLCrypto
;
1454 crtn
= CSSM_GenerateKeyPair(ccHandle
,
1455 CSSM_KEYUSE_DERIVE
, // only legal use of a Diffie-Hellman key
1456 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1459 /* private key specification */
1461 CSSM_KEYATTR_RETURN_REF
,
1462 &labelData
, // same labels
1463 NULL
, // CredAndAclEntry
1466 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn
);
1467 ortn
= errSSLCrypto
;
1469 CSSM_DeleteContext(ccHandle
);
1474 * Perform Diffie-Hellman key exchange.
1479 * This generates deriveSizeInBits of key-exchanged data.
1482 /* the alg isn't important; we just want to be able to cook up lots of bits */
1483 #define DERIVE_KEY_ALG CSSM_ALGID_RC5
1484 #define DERIVE_KEY_MAX_BYTES 255
1486 OSStatus
sslDhKeyExchange(
1488 uint32 deriveSizeInBits
,
1489 SSLBuffer
*exchanged
)
1492 CSSM_ACCESS_CREDENTIALS creds
;
1493 CSSM_CC_HANDLE ccHandle
;
1494 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1495 CSSM_KEY derivedKey
;
1496 OSStatus ortn
= noErr
;
1498 assert(ctx
!= NULL
);
1499 assert(ctx
->cspHand
!= 0);
1500 assert(ctx
->dhPrivate
!= NULL
);
1501 if(ctx
->dhPeerPublic
.length
== 0) {
1502 /* comes from peer, don't panic */
1503 sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
1504 return errSSLProtocol
;
1506 if(deriveSizeInBits
> (DERIVE_KEY_MAX_BYTES
* 8)) {
1507 sslErrorLog("cdsaDhKeyExchange: deriveSizeInBits %u bits\n",
1508 (unsigned)deriveSizeInBits
);
1509 return errSSLProtocol
;
1512 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1513 memset(&derivedKey
, 0, sizeof(CSSM_KEY
));
1515 crtn
= CSSM_CSP_CreateDeriveKeyContext(ctx
->cspHand
,
1520 ctx
->dhPrivate
, // BaseKey
1521 0, // IterationCount
1526 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn
);
1527 return errSSLCrypto
;
1530 /* public key passed in as CSSM_DATA *Param */
1531 CSSM_DATA theirPubKeyData
;
1532 SSLBUF_TO_CSSM(&ctx
->dhPeerPublic
, &theirPubKeyData
);
1534 crtn
= CSSM_DeriveKey(ccHandle
,
1537 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1542 stPrintCdsaError("DH CSSM_DeriveKey", crtn
);
1543 ortn
= errSSLCrypto
;
1546 CSSM_TO_SSLBUF(&derivedKey
.KeyData
, exchanged
);
1548 CSSM_DeleteContext(ccHandle
);
1553 * After ciphersuite negotiation is complete, verify that we have
1554 * the capability of actually performing the negotiated cipher.
1555 * Currently we just verify that we have a cert and private signing
1556 * key, if needed, and that the signing key's algorithm matches the
1557 * expected key exchange method.
1558 * This is currnetly only called from FindCipherSpec(), after
1559 * it sets ctx->selectedCipherSpec to a (supposedly) valid value.
1561 OSStatus
sslVerifyNegotiatedCipher(
1564 if(ctx
->protocolSide
== SSL_ClientSide
) {
1567 CSSM_ALGORITHMS requireAlg
= CSSM_ALGID_NONE
;
1569 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1571 case SSL_RSA_EXPORT
:
1573 case SSL_DH_RSA_EXPORT
:
1575 case SSL_DHE_RSA_EXPORT
:
1576 requireAlg
= CSSM_ALGID_RSA
;
1579 case SSL_DHE_DSS_EXPORT
:
1581 case SSL_DH_DSS_EXPORT
:
1582 requireAlg
= CSSM_ALGID_DSA
;
1585 case SSL_DH_anon_EXPORT
:
1586 /* CSSM_ALGID_NONE, no signing key */
1589 /* needs update per cipherSpecs.cpp */
1591 return errSSLInternal
;
1593 if(requireAlg
== CSSM_ALGID_NONE
) {
1597 /* private signing key required */
1598 if(ctx
->signingPrivKeyRef
== NULL
) {
1599 sslErrorLog("sslVerifyNegotiatedCipher: no signing key\n");
1600 return errSSLBadConfiguration
;
1603 const CSSM_KEY
*cssmKey
;
1604 OSStatus ortn
= SecKeyGetCSSMKey(ctx
->signingPrivKeyRef
, &cssmKey
);
1606 sslErrorLog("sslVerifyNegotiatedCipher: SecKeyGetCSSMKey err %d\n",
1610 if(cssmKey
->KeyHeader
.AlgorithmId
!= requireAlg
) {
1611 sslErrorLog("sslVerifyNegotiatedCipher: signing key alg mismatch\n");
1612 return errSSLBadConfiguration
;