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>
54 /* X.509 includes, from cssmapi */
55 #include <Security/x509defs.h> /* x.509 function and type defs */
56 #include <Security/oidsalg.h>
57 #include <Security/oidscert.h>
59 #pragma mark *** Utilities ***
62 * Set up a Raw symmetric key with specified algorithm and key bits.
64 OSStatus
sslSetUpSymmKey(
67 CSSM_KEYUSE keyUse
, // CSSM_KEYUSE_ENCRYPT, etc.
68 CSSM_BOOL copyKey
, // true: copy keyData false: set by reference
70 uint32 keyDataLen
) // in bytes
75 memset(symKey
, 0, sizeof(CSSM_KEY
));
77 serr
= stSetUpCssmData(&symKey
->KeyData
, keyDataLen
);
81 memmove(symKey
->KeyData
.Data
, keyData
, keyDataLen
);
84 symKey
->KeyData
.Data
= keyData
;
85 symKey
->KeyData
.Length
= keyDataLen
;
88 /* set up the header */
89 hdr
= &symKey
->KeyHeader
;
90 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
91 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
92 hdr
->AlgorithmId
= alg
;
93 hdr
->KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
94 hdr
->LogicalKeySizeInBits
= keyDataLen
* 8;
95 hdr
->KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
96 hdr
->KeyUsage
= keyUse
;
97 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
102 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
105 CSSM_CSP_HANDLE cspHand
,
106 CSSM_KEY_PTR
*key
, /* so we can null it out */
107 #if ST_KC_KEYS_NEED_REF
108 SecKeychainRef
*kcItem
)
117 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
119 stAppFree(*key
, NULL
); // key mallocd by CL using our callback
122 #if ST_KC_KEYS_NEED_REF
123 if((kcItem
!= NULL
) && (*kcItem
!= NULL
)) {
124 KCReleaseItem(kcItem
); /* does this NULL the referent? */
132 * Standard app-level memory functions required by CDSA.
134 void * stAppMalloc (uint32 size
, void *allocRef
) {
135 return( malloc(size
) );
137 void stAppFree (void *mem_ptr
, void *allocRef
) {
141 void * stAppRealloc (void *ptr
, uint32 size
, void *allocRef
) {
142 return( realloc( ptr
, size
) );
144 void * stAppCalloc (uint32 num
, uint32 size
, void *allocRef
) {
145 return( calloc( num
, size
) );
149 * Ensure there's a connection to ctx->cspHand. If there
150 * already is one, fine.
151 * Note that as of 12/18/00, we assume we're connected to
152 * all modules all the time (since we do an attachToAll() in
155 OSStatus
attachToCsp(SSLContext
*ctx
)
158 if(ctx
->cspHand
!= 0) {
162 return errSSLModuleAttach
;
167 * Connect to TP, CL; reusable.
169 OSStatus
attachToCl(SSLContext
*ctx
)
172 if(ctx
->clHand
!= 0) {
176 return errSSLModuleAttach
;
180 OSStatus
attachToTp(SSLContext
*ctx
)
183 if(ctx
->tpHand
!= 0) {
187 return errSSLModuleAttach
;
192 * Convenience function - attach to CSP, CL, TP. Reusable.
194 OSStatus
attachToAll(SSLContext
*ctx
)
199 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
, &ctx
->tpHand
);
201 return errSSLModuleAttach
;
208 OSStatus
detachFromAll(SSLContext
*ctx
)
211 /* No more, attachments are kept on a global basis */
213 if(ctx
->cspHand
!= 0) {
214 CSSM_ModuleDetach(ctx
->cspHand
);
217 if(ctx
->tpHand
!= 0) {
218 CSSM_ModuleDetach(ctx
->tpHand
);
221 if(ctx
->clHand
!= 0) {
222 CSSM_ModuleDetach(ctx
->clHand
);
230 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
231 * specified crypto context.
233 static CSSM_RETURN
sslAddBlindingAttr(
234 CSSM_CC_HANDLE ccHand
)
236 CSSM_CONTEXT_ATTRIBUTE newAttr
;
239 newAttr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
240 newAttr
.AttributeLength
= sizeof(uint32
);
241 newAttr
.Attribute
.Uint32
= 1;
242 crtn
= CSSM_UpdateContextAttributes(ccHand
, 1, &newAttr
);
244 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
250 #pragma mark *** CSSM_DATA routines ***
252 CSSM_DATA_PTR
stMallocCssmData(
255 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
265 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
272 CSSM_BOOL freeStruct
)
277 if(data
->Data
!= NULL
) {
278 stAppFree(data
->Data
, NULL
);
283 stAppFree(data
, NULL
);
288 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
289 * Malloc the Data ptr if necessary.
291 OSStatus
stSetUpCssmData(
295 assert(data
!= NULL
);
296 if(data
->Length
== 0) {
297 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
298 if(data
->Data
== NULL
) {
302 else if(data
->Length
< length
) {
303 sslErrorLog("stSetUpCssmData: length too small\n");
306 data
->Length
= length
;
310 static OSStatus
sslKeyToSigAlg(
311 const CSSM_KEY
*cssmKey
,
312 CSSM_ALGORITHMS
&sigAlg
) /* RETURNED */
315 OSStatus ortn
= noErr
;
316 switch(cssmKey
->KeyHeader
.AlgorithmId
) {
318 sigAlg
= CSSM_ALGID_RSA
;
321 sigAlg
= CSSM_ALGID_DSA
;
324 ortn
= errSSLBadConfiguration
;
331 #pragma mark *** Public CSP Functions ***
334 * Raw RSA/DSA sign/verify.
338 const CSSM_KEY
*privKey
,
339 CSSM_CSP_HANDLE cspHand
,
340 const UInt8
*plainText
,
342 UInt8
*sig
, // mallocd by caller; RETURNED
343 UInt32 sigLen
, // available
344 UInt32
*actualBytes
) // RETURNED
346 CSSM_CC_HANDLE sigHand
= 0;
353 if((privKey
== NULL
) ||
355 (plainText
== NULL
) ||
357 (actualBytes
== NULL
)) {
358 sslErrorLog("sslRsaRawSign: bad arguments\n");
359 return errSSLInternal
;
363 CSSM_ALGORITHMS sigAlg
;
364 serr
= sslKeyToSigAlg(privKey
, sigAlg
);
368 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
374 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
378 if((ctx
->rsaBlindingEnable
) &&
379 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
381 * Turn on RSA blinding to defeat timing attacks
383 crtn
= sslAddBlindingAttr(sigHand
);
389 ptextData
.Data
= (uint8
*)plainText
;
390 ptextData
.Length
= plainTextLen
;
392 /* caller better get this right, or the SignData will fail */
394 sigData
.Length
= sigLen
;
396 crtn
= CSSM_SignData(sigHand
,
399 CSSM_ALGID_NONE
, // digestAlg for raw sign
402 stPrintCdsaError("CSSM_SignData", crtn
);
406 *actualBytes
= sigData
.Length
;
410 CSSM_DeleteContext(sigHand
);
415 OSStatus
sslRawVerify(
417 const CSSM_KEY
*pubKey
,
418 CSSM_CSP_HANDLE cspHand
,
419 const UInt8
*plainText
,
424 CSSM_CC_HANDLE sigHand
= 0;
431 if((pubKey
== NULL
) ||
433 (plainText
== NULL
) ||
435 sslErrorLog("sslRawVerify: bad arguments\n");
436 return errSSLInternal
;
439 CSSM_ALGORITHMS sigAlg
;
440 serr
= sslKeyToSigAlg(pubKey
, sigAlg
);
444 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
450 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
454 ptextData
.Data
= (uint8
*)plainText
;
455 ptextData
.Length
= plainTextLen
;
456 sigData
.Data
= (uint8
*)sig
;
457 sigData
.Length
= sigLen
;
459 crtn
= CSSM_VerifyData(sigHand
,
462 CSSM_ALGID_NONE
, // digestAlg
465 stPrintCdsaError("CSSM_VerifyData", crtn
);
472 CSSM_DeleteContext(sigHand
);
480 OSStatus
sslRsaEncrypt(
482 const CSSM_KEY
*pubKey
,
483 CSSM_CSP_HANDLE cspHand
,
484 const UInt8
*plainText
,
486 UInt8
*cipherText
, // mallocd by caller; RETURNED
487 UInt32 cipherTextLen
, // available
488 UInt32
*actualBytes
) // RETURNED
490 CSSM_DATA ctextData
= {0, NULL
};
492 CSSM_DATA remData
= {0, NULL
};
493 CSSM_CC_HANDLE cryptHand
= 0;
494 OSStatus serr
= errSSLInternal
;
496 uint32 bytesMoved
= 0;
497 CSSM_ACCESS_CREDENTIALS creds
;
500 assert(actualBytes
!= NULL
);
503 if((pubKey
== NULL
) || (cspHand
== 0)) {
504 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
505 return errSSLInternal
;
507 assert(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
);
509 #if RSA_PUB_KEY_USAGE_HACK
510 ((CSSM_KEY_PTR
)pubKey
)->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
512 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
514 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
521 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
524 ptextData
.Data
= (uint8
*)plainText
;
525 ptextData
.Length
= plainTextLen
;
528 * Have CSP malloc ciphertext
530 crtn
= CSSM_EncryptData(cryptHand
,
537 if(crtn
== CSSM_OK
) {
539 * ciphertext in both ctextData and remData; ensure it'll fit
540 * in caller's buf & copy
542 if(bytesMoved
> cipherTextLen
) {
543 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
544 cipherTextLen
, bytesMoved
);
551 *actualBytes
= bytesMoved
;
553 * Snag valid data from ctextData - its length or bytesMoved,
556 if(ctextData
.Length
> bytesMoved
) {
557 /* everything's in ctext */
558 toMoveCtext
= bytesMoved
;
562 /* must be some in remData too */
563 toMoveCtext
= ctextData
.Length
;
564 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
567 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
570 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
577 stPrintCdsaError("CSSM_EncryptData", crtn
);
581 CSSM_DeleteContext(cryptHand
);
584 /* free data mallocd by CSP */
585 stFreeCssmData(&ctextData
, CSSM_FALSE
);
586 stFreeCssmData(&remData
, CSSM_FALSE
);
590 OSStatus
sslRsaDecrypt(
592 const CSSM_KEY
*privKey
,
593 CSSM_CSP_HANDLE cspHand
,
594 const UInt8
*cipherText
,
595 UInt32 cipherTextLen
,
596 UInt8
*plainText
, // mallocd by caller; RETURNED
597 UInt32 plainTextLen
, // available
598 UInt32
*actualBytes
) // RETURNED
600 CSSM_DATA ptextData
= {0, NULL
};
602 CSSM_DATA remData
= {0, NULL
};
603 CSSM_CC_HANDLE cryptHand
= 0;
604 OSStatus serr
= errSSLInternal
;
606 uint32 bytesMoved
= 0;
607 CSSM_ACCESS_CREDENTIALS creds
;
610 assert(actualBytes
!= NULL
);
613 if((privKey
== NULL
) || (cspHand
== 0)) {
614 sslErrorLog("sslRsaDecrypt: bad privKey/cspHand\n");
615 return errSSLInternal
;
617 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
618 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
619 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
626 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
629 ctextData
.Data
= (uint8
*)cipherText
;
630 ctextData
.Length
= cipherTextLen
;
632 if((ctx
->rsaBlindingEnable
) &&
633 (privKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
)) {
635 * Turn on RSA blinding to defeat timing attacks
637 crtn
= sslAddBlindingAttr(cryptHand
);
644 * Have CSP malloc plaintext
646 crtn
= CSSM_DecryptData(cryptHand
,
653 if(crtn
== CSSM_OK
) {
655 * plaintext in both ptextData and remData; ensure it'll fit
656 * in caller's buf & copy
658 if(bytesMoved
> plainTextLen
) {
659 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
660 plainTextLen
, bytesMoved
);
667 *actualBytes
= bytesMoved
;
669 * Snag valid data from ptextData - its length or bytesMoved,
672 if(ptextData
.Length
> bytesMoved
) {
673 /* everything's in ptext */
674 toMovePtext
= bytesMoved
;
678 /* must be some in remData too */
679 toMovePtext
= ptextData
.Length
;
680 toMoveRem
= bytesMoved
- toMovePtext
; // remainder
683 memmove(plainText
, ptextData
.Data
, toMovePtext
);
686 memmove(plainText
+ toMovePtext
, remData
.Data
,
693 stPrintCdsaError("CSSM_DecryptData", crtn
);
697 CSSM_DeleteContext(cryptHand
);
700 /* free data mallocd by CSP */
701 stFreeCssmData(&ptextData
, CSSM_FALSE
);
702 stFreeCssmData(&remData
, CSSM_FALSE
);
707 * Obtain size of key in bytes.
709 UInt32
sslKeyLengthInBytes(const CSSM_KEY
*key
)
712 return (((key
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
716 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
717 * ask the CSP to do this but that would be kind of expensive.
719 OSStatus
sslGetMaxSigSize(
720 const CSSM_KEY
*privKey
,
723 OSStatus ortn
= noErr
;
724 assert(privKey
!= NULL
);
725 assert(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
726 switch(privKey
->KeyHeader
.AlgorithmId
) {
728 maxSigSize
= sslKeyLengthInBytes(privKey
);
732 /* DSA sig is DER sequence of two 160-bit integers */
734 sizeOfOneInt
= (160 / 8) + // the raw contents
735 1 + // possible leading zero
736 2; // tag + length (assume DER, not BER)
737 maxSigSize
= (2 * sizeOfOneInt
) + 5;
741 ortn
= errSSLBadConfiguration
;
747 * Get raw key bits from an RSA public key.
749 OSStatus
sslGetPubKeyBits(
751 const CSSM_KEY
*pubKey
,
752 CSSM_CSP_HANDLE cspHand
,
753 SSLBuffer
*modulus
, // data mallocd and RETURNED
754 SSLBuffer
*exponent
) // data mallocd and RETURNED
757 CSSM_BOOL didWrap
= CSSM_FALSE
;
758 const CSSM_KEYHEADER
*hdr
;
759 CSSM_CC_HANDLE ccHand
;
761 SSLBuffer pubKeyBlob
;
763 CSSM_ACCESS_CREDENTIALS creds
;
766 assert(modulus
!= NULL
);
767 assert(exponent
!= NULL
);
768 assert(pubKey
!= NULL
);
770 hdr
= &pubKey
->KeyHeader
;
771 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
772 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr
->KeyClass
);
773 return errSSLInternal
;
775 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
776 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr
->AlgorithmId
);
777 return errSSLInternal
;
781 * Handle possible reference format - I think it should be in
782 * blob form since it came from the DL, but conversion is
785 switch(hdr
->BlobType
) {
786 case CSSM_KEYBLOB_RAW
:
788 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
791 case CSSM_KEYBLOB_REFERENCE
:
793 * Convert to a blob via "NULL wrap"; no wrapping key,
796 srtn
= attachToCsp(ctx
);
800 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
801 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
811 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
814 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
815 crtn
= CSSM_WrapKey(ccHand
,
818 NULL
, // descriptiveData
820 CSSM_DeleteContext(ccHand
);
822 stPrintCdsaError("CSSM_WrapKey", crtn
);
825 hdr
= &wrappedKey
.KeyHeader
;
826 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
827 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
832 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
836 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
838 return errSSLInternal
;
840 } /* switch BlobType */
842 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
843 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
845 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
851 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
852 * Server-initiated key exchange.
854 OSStatus
sslGetPubKeyFromBits(
856 const SSLBuffer
*modulus
,
857 const SSLBuffer
*exponent
,
858 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
859 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
861 CSSM_KEY_PTR key
= NULL
;
864 CSSM_KEYHEADER_PTR hdr
;
865 CSSM_KEY_SIZE keySize
;
868 assert((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
869 assert((pubKey
!= NULL
) && (cspHand
!= NULL
));
874 serr
= attachToCsp(ctx
);
878 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
883 /* the rest is boilerplate, cook up a good-looking public key */
884 key
= (CSSM_KEY_PTR
)sslMalloc(sizeof(CSSM_KEY
));
888 memset(key
, 0, sizeof(CSSM_KEY
));
889 hdr
= &key
->KeyHeader
;
891 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
892 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
893 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
894 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
895 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
896 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
897 /* comply with ASA requirements */
898 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
899 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
900 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
901 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
902 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
903 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
905 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
907 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
910 * Get keySizeInBits. This also serves to validate the key blob
913 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
915 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
921 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
923 *cspHand
= ctx
->cspHand
;
927 /* note this frees the blob */
928 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
933 #pragma mark *** Public Certificate Functions ***
936 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
937 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
939 * For now, the returned cspHand is a copy of ctx->cspHand, so it
940 * doesn't have to be detached later - this may change.
942 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
943 * us to tell the CL what CSP to use, we really have no way of knowing
944 * what is going on here...we return the process-wide (bare) cspHand,
945 * which is currently always able to deal with this raw public key.
947 OSStatus
sslPubKeyFromCert(
949 const SSLBuffer
&derCert
,
950 CSSM_KEY_PTR
*pubKey
, // RETURNED
951 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
958 assert(pubKey
!= NULL
);
959 assert(cspHand
!= NULL
);
964 serr
= attachToCl(ctx
);
968 serr
= attachToCsp(ctx
);
972 SSLBUF_TO_CSSM(&derCert
, &certData
);
973 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, pubKey
);
975 return errSSLBadCert
;
978 *cspHand
= ctx
->cspHand
;
984 * Release each element in a CFArray.
986 static void sslReleaseArray(
989 CFIndex num
= CFArrayGetCount(a
);
990 for(CFIndex dex
=0; dex
<num
; dex
++) {
991 CFTypeRef elmt
= (CFTypeRef
)CFArrayGetValueAtIndex(a
, dex
);
992 secdebug("sslcert", "Freeing cert %p", elmt
);
998 * Verify a chain of DER-encoded certs.
999 * First cert in a chain is root; this must also be present
1000 * in ctx->trustedCerts.
1002 * If arePeerCerts is true, host name verification is enabled and we
1003 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
1004 * we're just validating our own certs; no host name checking and
1005 * peerSecTrust is transient.
1007 OSStatus
sslVerifyCertChain(
1009 const SSLCertificate
&certChain
,
1010 bool arePeerCerts
/* = true */)
1015 SSLCertificate
*c
= (SSLCertificate
*)&certChain
;
1017 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
1018 CSSM_APPLE_TP_ACTION_DATA tpActionData
;
1019 SecPolicyRef policy
= NULL
;
1020 SecPolicySearchRef policySearch
= NULL
;
1021 CFDataRef actionData
= NULL
;
1022 CSSM_DATA sslOptsData
;
1023 CFMutableArrayRef anchors
= NULL
;
1024 SecCertificateRef cert
; // only lives in CFArrayRefs
1025 SecTrustResultType secTrustResult
;
1026 CFMutableArrayRef kcList
= NULL
;
1027 SecTrustRef theTrust
= NULL
;
1029 if(ctx
->peerSecTrust
&& arePeerCerts
) {
1030 /* renegotiate - start with a new SecTrustRef */
1031 CFRelease(ctx
->peerSecTrust
);
1032 ctx
->peerSecTrust
= NULL
;
1035 numCerts
= SSLGetCertificateChainLength(&certChain
);
1038 return errSSLBadCert
;
1042 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
1043 * TP Cert group has root at the end, opposite of
1044 * SSLCertificate chain.
1046 CFMutableArrayRef certGroup
= CFArrayCreateMutable(NULL
, numCerts
,
1047 &kCFTypeArrayCallBacks
);
1048 if(certGroup
== NULL
) {
1051 /* subsequent errors to errOut: */
1053 for(i
=numCerts
-1; i
>=0; i
--) {
1055 SSLBUF_TO_CSSM(&c
->derCert
, &cdata
);
1056 serr
= SecCertificateCreateFromData(&cdata
, CSSM_CERT_X_509v3
,
1057 CSSM_CERT_ENCODING_DER
, &cert
);
1062 * Can't set a value at index i when there is an empty element
1065 secdebug("sslcert", "Adding cert %p", cert
);
1066 CFArrayInsertValueAtIndex(certGroup
, 0, cert
);
1071 * Cook up an SSL-specific SecPolicyRef. This will persists as part
1072 * of the SecTrustRef object we'll be creating.
1074 serr
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
1075 &CSSMOID_APPLE_TP_SSL
,
1079 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
1083 serr
= SecPolicySearchCopyNext(policySearch
, &policy
);
1085 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
1089 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
1091 sslOpts
.ServerNameLen
= ctx
->peerDomainNameLen
;
1092 sslOpts
.ServerName
= ctx
->peerDomainName
;
1095 sslOpts
.ServerNameLen
= 0;
1096 sslOpts
.ServerName
= NULL
;
1098 sslOptsData
.Data
= (uint8
*)&sslOpts
;
1099 sslOptsData
.Length
= sizeof(sslOpts
);
1100 serr
= SecPolicySetValue(policy
, &sslOptsData
);
1102 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
1107 /* now a SecTrustRef */
1108 serr
= SecTrustCreateWithCertificates(certGroup
, policy
, &theTrust
);
1110 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
1111 "rtn %d\n", (int)serr
);
1115 /* anchors - default, or ours? */
1116 if(ctx
->numTrustedCerts
!= 0) {
1117 anchors
= CFArrayCreateMutable(NULL
, ctx
->numTrustedCerts
,
1118 &kCFTypeArrayCallBacks
);
1119 if(anchors
== NULL
) {
1123 for(i
=0; i
<(int)ctx
->numTrustedCerts
; i
++) {
1124 serr
= SecCertificateCreateFromData(&ctx
->trustedCerts
[i
],
1125 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
1129 secdebug("sslcert", "Adding cert %p", cert
);
1130 CFArraySetValueAtIndex(anchors
, i
, cert
);
1132 serr
= SecTrustSetAnchorCertificates(theTrust
, anchors
);
1134 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
1135 "rtn %d\n", (int)serr
);
1139 tpActionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
1140 tpActionData
.ActionFlags
= 0;
1141 if(ctx
->allowExpiredCerts
) {
1142 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED
;
1144 if(ctx
->allowExpiredRoots
) {
1145 tpActionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
;
1147 actionData
= CFDataCreate(NULL
, (UInt8
*)&tpActionData
, sizeof(tpActionData
));
1149 serr
= SecTrustSetParameters(theTrust
, CSSM_TP_ACTION_DEFAULT
,
1152 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
1158 /* Disabled for Radar 3421314 */
1160 * Avoid searching user keychains for intermediate certs by specifying
1161 * an empty array of keychains
1163 kcList
= CFArrayCreateMutable(NULL
, 0, NULL
);
1164 if(kcList
== NULL
) {
1165 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
1169 serr
= SecTrustSetKeychains(theTrust
, kcList
);
1171 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
1178 * Save this no matter what if we're evaluating peer certs.
1179 * We do a retain here so we can unconditionally release theTrust
1180 * at the end of this routine in case of previous error or
1184 ctx
->peerSecTrust
= theTrust
;
1188 if(!ctx
->enableCertVerify
) {
1189 /* trivial case, this is caller's responsibility */
1195 * Here we go; hand it over to SecTrust/TP.
1197 serr
= SecTrustEvaluate(theTrust
, &secTrustResult
);
1199 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
1203 switch(secTrustResult
) {
1204 case kSecTrustResultUnspecified
:
1205 /* cert chain valid, no special UserTrust assignments */
1206 case kSecTrustResultProceed
:
1207 /* cert chain valid AND user explicitly trusts this */
1210 case kSecTrustResultDeny
:
1211 case kSecTrustResultConfirm
:
1213 * Cert chain may well have verified OK, but user has flagged
1214 * one of these certs as untrustable.
1216 crtn
= CSSMERR_TP_NOT_TRUSTED
;
1221 serr
= SecTrustGetCssmResultCode(theTrust
, &osCrtn
);
1223 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
1224 " rtn %d\n", (int)serr
);
1231 /* get some detailed error info */
1233 case CSSMERR_TP_INVALID_ANCHOR_CERT
:
1234 /* root found but we don't trust it */
1235 if(ctx
->allowAnyRoot
) {
1237 sslErrorLog("***Warning: accepting unknown root cert\n");
1240 serr
= errSSLUnknownRootCert
;
1243 case CSSMERR_TP_NOT_TRUSTED
:
1244 /* no root, not even in implicit SSL roots */
1245 if(ctx
->allowAnyRoot
) {
1246 sslErrorLog("***Warning: accepting unverified cert chain\n");
1250 serr
= errSSLNoRootCert
;
1253 case CSSMERR_TP_CERT_EXPIRED
:
1254 assert(!ctx
->allowExpiredCerts
);
1255 serr
= errSSLCertExpired
;
1257 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1258 serr
= errSSLCertNotYetValid
;
1261 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1263 serr
= errSSLXCertChainInvalid
;
1266 } /* SecTrustEvaluate error */
1270 * Free up resources - certGroup, policy, etc. Note that most of these
1271 * will actually persist as long as the current SSLContext does since
1272 * peerSecTrust holds references to these.
1278 CFRelease(policySearch
);
1281 CFRelease(actionData
);
1284 sslReleaseArray(anchors
);
1288 sslReleaseArray(certGroup
);
1289 CFRelease(certGroup
);
1292 /* empty, no contents to release */
1296 CFRelease(theTrust
);
1302 void stPrintCdsaError(const char *op
, CSSM_RETURN crtn
)
1304 cssmPerror(op
, crtn
);
1307 char *stCssmErrToStr(CSSM_RETURN err
)
1309 string errStr
= cssmErrorString(err
);
1310 return const_cast<char *>(errStr
.c_str());
1315 #pragma mark *** Diffie-Hellman support ***
1318 * Generate a Diffie-Hellman key pair. Algorithm parameters always
1319 * come from the server, so on client side we have the parameters
1320 * as two SSLBuffers. On server side we have the pre-encoded block
1321 * which comes from ServerDhParams.
1323 OSStatus
sslDhGenKeyPairClient(
1325 const SSLBuffer
&prime
,
1326 const SSLBuffer
&generator
,
1327 CSSM_KEY_PTR publicKey
, // RETURNED
1328 CSSM_KEY_PTR privateKey
) // RETURNED
1330 assert((prime
.data
!= NULL
) && (generator
.data
!= NULL
));
1331 if(prime
.data
&& !generator
.data
) {
1332 return errSSLProtocol
;
1334 if(!prime
.data
&& generator
.data
) {
1335 return errSSLProtocol
;
1339 OSStatus ortn
= sslEncodeDhParams(&prime
, &generator
, &sParam
);
1341 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
1344 ortn
= sslDhGenerateKeyPair(ctx
, sParam
, prime
.length
* 8, publicKey
, privateKey
);
1345 SSLFreeBuffer(sParam
, ctx
);
1349 OSStatus
sslDhGenerateKeyPair(
1351 const SSLBuffer
¶mBlob
,
1352 UInt32 keySizeInBits
,
1353 CSSM_KEY_PTR publicKey
, // RETURNED
1354 CSSM_KEY_PTR privateKey
) // RETURNED
1357 CSSM_CC_HANDLE ccHandle
;
1358 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1359 OSStatus ortn
= noErr
;
1360 CSSM_DATA cParamBlob
;
1362 assert(ctx
!= NULL
);
1363 assert(ctx
->cspHand
!= 0);
1365 memset(publicKey
, 0, sizeof(CSSM_KEY
));
1366 memset(privateKey
, 0, sizeof(CSSM_KEY
));
1367 SSLBUF_TO_CSSM(¶mBlob
, &cParamBlob
);
1369 crtn
= CSSM_CSP_CreateKeyGenContext(ctx
->cspHand
,
1379 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn
);
1380 return errSSLCrypto
;
1383 crtn
= CSSM_GenerateKeyPair(ccHandle
,
1384 CSSM_KEYUSE_DERIVE
, // only legal use of a Diffie-Hellman key
1385 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1388 /* private key specification */
1390 CSSM_KEYATTR_RETURN_REF
,
1391 &labelData
, // same labels
1392 NULL
, // CredAndAclEntry
1395 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn
);
1396 ortn
= errSSLCrypto
;
1398 CSSM_DeleteContext(ccHandle
);
1403 * Perform Diffie-Hellman key exchange.
1408 * This generates deriveSizeInBits of key-exchanged data.
1411 /* the alg isn't important; we just want to be able to cook up lots of bits */
1412 #define DERIVE_KEY_ALG CSSM_ALGID_RC5
1413 #define DERIVE_KEY_MAX_BYTES 255
1415 OSStatus
sslDhKeyExchange(
1417 uint32 deriveSizeInBits
,
1418 SSLBuffer
*exchanged
)
1421 CSSM_ACCESS_CREDENTIALS creds
;
1422 CSSM_CC_HANDLE ccHandle
;
1423 CSSM_DATA labelData
= {8, (uint8
*)"tempKey"};
1424 CSSM_KEY derivedKey
;
1425 OSStatus ortn
= noErr
;
1427 assert(ctx
!= NULL
);
1428 assert(ctx
->cspHand
!= 0);
1429 assert(ctx
->dhPrivate
!= NULL
);
1430 if(ctx
->dhPeerPublic
.length
== 0) {
1431 /* comes from peer, don't panic */
1432 sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
1433 return errSSLProtocol
;
1435 if(deriveSizeInBits
> (DERIVE_KEY_MAX_BYTES
* 8)) {
1436 sslErrorLog("cdsaDhKeyExchange: deriveSizeInBits %u bits\n",
1437 (unsigned)deriveSizeInBits
);
1438 return errSSLProtocol
;
1441 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
1442 memset(&derivedKey
, 0, sizeof(CSSM_KEY
));
1444 crtn
= CSSM_CSP_CreateDeriveKeyContext(ctx
->cspHand
,
1449 ctx
->dhPrivate
, // BaseKey
1450 0, // IterationCount
1455 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn
);
1456 return errSSLCrypto
;
1459 /* public key passed in as CSSM_DATA *Param */
1460 CSSM_DATA theirPubKeyData
;
1461 SSLBUF_TO_CSSM(&ctx
->dhPeerPublic
, &theirPubKeyData
);
1463 crtn
= CSSM_DeriveKey(ccHandle
,
1466 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
1471 stPrintCdsaError("DH CSSM_DeriveKey", crtn
);
1472 ortn
= errSSLCrypto
;
1475 CSSM_TO_SSLBUF(&derivedKey
.KeyData
, exchanged
);
1477 CSSM_DeleteContext(ccHandle
);
1482 * After ciphersuite negotiation is complete, verify that we have
1483 * the capability of actually performing the negotiated cipher.
1484 * Currently we just verify that we have a cert and private signing
1485 * key, if needed, and that the signing key's algorithm matches the
1486 * expected key exchange method.
1487 * This is currnetly only called from FindCipherSpec(), after
1488 * it sets ctx->selectedCipherSpec to a (supposedly) valid value.
1490 OSStatus
sslVerifyNegotiatedCipher(
1493 if(ctx
->protocolSide
== SSL_ClientSide
) {
1496 CSSM_ALGORITHMS requireAlg
= CSSM_ALGID_NONE
;
1498 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1500 case SSL_RSA_EXPORT
:
1502 case SSL_DH_RSA_EXPORT
:
1504 case SSL_DHE_RSA_EXPORT
:
1505 requireAlg
= CSSM_ALGID_RSA
;
1508 case SSL_DHE_DSS_EXPORT
:
1510 case SSL_DH_DSS_EXPORT
:
1511 requireAlg
= CSSM_ALGID_DSA
;
1514 case SSL_DH_anon_EXPORT
:
1515 /* CSSM_ALGID_NONE, no signing key */
1518 /* needs update per cipherSpecs.cpp */
1520 return errSSLInternal
;
1522 if(requireAlg
== CSSM_ALGID_NONE
) {
1526 /* private signing key required */
1527 if(ctx
->signingPrivKey
== NULL
) {
1528 sslErrorLog("sslVerifyNegotiatedCipher: no signing key\n");
1529 return errSSLBadConfiguration
;
1531 if(ctx
->signingPrivKey
->KeyHeader
.AlgorithmId
!= requireAlg
) {
1532 sslErrorLog("sslVerifyNegotiatedCipher: signing key alg mismatch\n");
1533 return errSSLBadConfiguration
;