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.
33 #include "appleCdsa.h"
38 #include "ModuleAttacher.h"
40 #ifndef _SSL_KEYCHAIN_H_
41 #include "sslKeychain.h"
47 #include <Security/cssm.h>
48 #include <Security/cssmapple.h>
50 /* X.509 includes, from cssmapi */
51 #include <Security/x509defs.h> /* x.509 function and type defs */
52 #include <Security/oidsalg.h>
53 #include <Security/oidscert.h>
55 #pragma mark *** Utilities ***
58 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
61 CSSM_CSP_HANDLE cspHand
,
62 CSSM_KEY_PTR
*key
, /* so we can null it out */
63 #if ST_KEYCHAIN_ENABLE
64 KCItemRef
*kcItem
) /* optional; ditto */
73 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
78 #if ST_KEYCHAIN_ENABLE
79 if((kcItem
!= NULL
) && (*kcItem
!= NULL
)) {
80 KCReleaseItem(kcItem
); /* does this NULL the referent? */
88 * Standard app-level memory functions required by CDSA.
90 void * stAppMalloc (uint32 size
, void *allocRef
) {
91 return( malloc(size
) );
93 void stAppFree (void *mem_ptr
, void *allocRef
) {
97 void * stAppRealloc (void *ptr
, uint32 size
, void *allocRef
) {
98 return( realloc( ptr
, size
) );
100 void * stAppCalloc (uint32 num
, uint32 size
, void *allocRef
) {
101 return( calloc( num
, size
) );
105 * Ensure there's a connection to ctx->cspHand. If there
106 * already is one, fine.
107 * Note that as of 12/18/00, we assume we're connected to
108 * all modules all the time (since we do an attachToAll() in
111 SSLErr
attachToCsp(SSLContext
*ctx
)
113 CASSERT(ctx
!= NULL
);
114 if(ctx
->cspHand
!= 0) {
118 return SSLAttachFailure
;
123 * Connect to TP, CL; reusable.
125 SSLErr
attachToCl(SSLContext
*ctx
)
127 CASSERT(ctx
!= NULL
);
128 if(ctx
->clHand
!= 0) {
132 return SSLAttachFailure
;
136 SSLErr
attachToTp(SSLContext
*ctx
)
138 CASSERT(ctx
!= NULL
);
139 if(ctx
->tpHand
!= 0) {
143 return SSLAttachFailure
;
148 * Convenience function - attach to CSP, CL, TP. Reusable.
150 SSLErr
attachToAll(SSLContext
*ctx
)
154 CASSERT(ctx
!= NULL
);
155 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
,
158 return SSLAttachFailure
;
165 SSLErr
detachFromAll(SSLContext
*ctx
)
168 /* No more, attachments are kept on a global basis */
169 CASSERT(ctx
!= NULL
);
170 if(ctx
->cspHand
!= 0) {
171 CSSM_ModuleDetach(ctx
->cspHand
);
174 if(ctx
->tpHand
!= 0) {
175 CSSM_ModuleDetach(ctx
->tpHand
);
178 if(ctx
->clHand
!= 0) {
179 CSSM_ModuleDetach(ctx
->clHand
);
187 #pragma mark *** CSSM_DATA routines ***
189 CSSM_DATA_PTR
stMallocCssmData(
192 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
202 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
209 CSSM_BOOL freeStruct
)
214 if(data
->Data
!= NULL
) {
215 stAppFree(data
->Data
, NULL
);
220 stAppFree(data
, NULL
);
225 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
226 * Malloc the Data ptr if necessary.
228 SSLErr
stSetUpCssmData(
232 CASSERT(data
!= NULL
);
233 if(data
->Length
== 0) {
234 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
235 if(data
->Data
== NULL
) {
239 else if(data
->Length
< length
) {
240 errorLog0("stSetUpCssmData: length too small\n");
243 data
->Length
= length
;
248 #pragma mark *** Public CSP Functions ***
251 * Common RNG function; replaces SSLRef's SSLRandomFunc.
253 SSLErr
sslRand(SSLContext
*ctx
, SSLBuffer
*buf
)
256 CSSM_CC_HANDLE rngHand
;
260 CASSERT(ctx
!= NULL
);
261 CASSERT(buf
!= NULL
);
262 CASSERT(buf
->data
!= NULL
);
264 serr
= attachToCsp(ctx
);
268 if(buf
->length
== 0) {
269 dprintf0("sslRand: zero buf->length\n");
274 * We happen to know that the CSP has a really good RNG
275 * seed if we don't specify anything; let's use it
277 crtn
= CSSM_CSP_CreateRandomGenContext(ctx
->cspHand
,
278 CSSM_ALGID_APPLE_YARROW
,
283 stPrintCdsaError("CSSM_CSP_CreateRandomGenContext", crtn
);
284 return SSLCryptoError
;
286 SSLBUF_TO_CSSM(buf
, &randData
);
287 crtn
= CSSM_GenerateRandom(rngHand
, &randData
);
289 stPrintCdsaError("CSSM_GenerateRandom", crtn
);
290 serr
= SSLCryptoError
;
292 CSSM_DeleteContext(rngHand
);
297 * Raw RSA sign/verify.
299 * Initial X port: CSP doesns't support this, so we'll do sign/verify via
300 * raw RSA encrypt/decrypt here.
302 #define SIGN_VFY_VIA_ENCR_DECR 0
304 #if SIGN_VFY_VIA_ENCR_DECR
306 SSLErr
sslRsaRawSign(
308 const CSSM_KEY_PTR privKey
,
309 CSSM_CSP_HANDLE cspHand
,
310 const UInt8
*plainText
,
312 UInt8
*sig
, // mallocd by caller; RETURNED
313 UInt32 sigLen
, // available
314 UInt32
*actualBytes
) // RETURNED
316 /* Raw RSA sign with no digest is the same as raw RSA encrypt. */
317 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
318 * than we really want */
320 CSSM_KEYUSE savedKeyUse
= privKey
->KeyHeader
.KeyUsage
;
321 privKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
322 serr
= sslRsaEncrypt(ctx
,
330 privKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
334 SSLErr
sslRsaRawVerify(
336 const CSSM_KEY_PTR pubKey
,
337 CSSM_CSP_HANDLE cspHand
,
338 const UInt8
*plainText
,
344 * Raw RSA verify with no digest is just a comparison of the incoming
345 * plaintext with (signature, decrypted via raw RSA decrypt).
352 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
353 * than we really want */
354 CSSM_KEYUSE savedKeyUse
= pubKey
->KeyHeader
.KeyUsage
;
355 pubKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
357 /* malloc space for decrypting the signature */
358 digest
= sslMalloc(plainTextLen
);
363 /* decrypt signature */
364 serr
= sslRsaDecrypt(ctx
,
372 pubKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
376 if((actualBytes
!= plainTextLen
) ||
377 (memcmp(plainText
, digest
, plainTextLen
))) {
378 errorLog0("sslRsaRawVerify: sig miscompare\n");
379 serr
= SSLCryptoError
;
389 #else /* OS9 and future post-cheetah version */
391 SSLErr
sslRsaRawSign(
393 const CSSM_KEY_PTR privKey
,
394 CSSM_CSP_HANDLE cspHand
,
395 const UInt8
*plainText
,
397 UInt8
*sig
, // mallocd by caller; RETURNED
398 UInt32 sigLen
, // available
399 UInt32
*actualBytes
) // RETURNED
401 CSSM_CC_HANDLE sigHand
= 0;
407 CASSERT(ctx
!= NULL
);
408 if((privKey
== NULL
) ||
410 (plainText
== NULL
) ||
412 (actualBytes
== NULL
)) {
413 errorLog0("sslRsaRawSign: bad arguments\n");
414 return SSLInternalError
;
418 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
424 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
425 return SSLCryptoError
;
428 ptextData
.Data
= (uint8
*)plainText
;
429 ptextData
.Length
= plainTextLen
;
431 /* caller better get this right, or the SignData will fail */
433 sigData
.Length
= sigLen
;
435 crtn
= CSSM_SignData(sigHand
,
438 CSSM_ALGID_NONE
, // digestAlg
441 stPrintCdsaError("CSSM_SignData", crtn
);
442 serr
= SSLCryptoError
;
445 *actualBytes
= sigData
.Length
;
449 CSSM_DeleteContext(sigHand
);
454 SSLErr
sslRsaRawVerify(
456 const CSSM_KEY_PTR pubKey
,
457 CSSM_CSP_HANDLE cspHand
,
458 const UInt8
*plainText
,
463 CSSM_CC_HANDLE sigHand
= 0;
469 CASSERT(ctx
!= NULL
);
470 if((pubKey
== NULL
) ||
472 (plainText
== NULL
) ||
474 errorLog0("sslRsaRawVerify: bad arguments\n");
475 return SSLInternalError
;
478 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
484 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
485 return SSLCryptoError
;
488 ptextData
.Data
= (uint8
*)plainText
;
489 ptextData
.Length
= plainTextLen
;
490 sigData
.Data
= (uint8
*)sig
;
491 sigData
.Length
= sigLen
;
493 crtn
= CSSM_VerifyData(sigHand
,
496 CSSM_ALGID_NONE
, // digestAlg
499 stPrintCdsaError("CSSM_VerifyData", crtn
);
500 serr
= SSLCryptoError
;
506 CSSM_DeleteContext(sigHand
);
510 #endif /* SIGN_VFY_VIA_ENCR_DECR */
515 #if APPLE_DOMESTIC_CSP_REQUIRED
518 * Mucho work needed to get this functionality out of export CSP....
521 SSLErr
sslRsaEncrypt(
523 const CSSM_KEY_PTR pubKey
,
524 CSSM_CSP_HANDLE cspHand
,
525 const UInt8
*plainText
,
527 UInt8
*cipherText
, // mallocd by caller; RETURNED
528 UInt32 cipherTextLen
, // available
529 UInt32
*actualBytes
) // RETURNED
531 CSSM_DATA ctextData
= {0, NULL
};
533 CSSM_DATA remData
= {0, NULL
};
534 CSSM_CC_HANDLE cryptHand
= 0;
535 SSLErr serr
= SSLInternalError
;
537 uint32 bytesMoved
= 0;
538 CSSM_ACCESS_CREDENTIALS creds
;
540 CASSERT(ctx
!= NULL
);
541 CASSERT(actualBytes
!= NULL
);
544 if((pubKey
== NULL
) || (cspHand
== 0)) {
545 errorLog0("sslRsaEncrypt: bad pubKey/cspHand\n");
546 return SSLInternalError
;
549 #if RSA_PUB_KEY_USAGE_HACK
550 pubKey
->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
552 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
554 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
561 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
562 return SSLCryptoError
;
564 ptextData
.Data
= (uint8
*)plainText
;
565 ptextData
.Length
= plainTextLen
;
567 if(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
569 * Special case, encrypting with private key (i.e., raw sign). Add
570 * the required context attr.
572 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
574 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
575 modeAttr
.AttributeLength
= sizeof(uint32
);
576 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PRIVATE_KEY
;
577 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
579 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
580 CSSM_DeleteContext(cryptHand
);
581 return SSLCryptoError
;
586 * Have CSP malloc ciphertext
588 crtn
= CSSM_EncryptData(cryptHand
,
595 if(crtn
== CSSM_OK
) {
597 * ciphertext in both ctextData and remData; ensure it'll fit
598 * in caller's buf & copy
600 if(bytesMoved
> cipherTextLen
) {
601 errorLog2("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
602 cipherTextLen
, bytesMoved
);
603 serr
= SSLDataOverflow
;
609 *actualBytes
= bytesMoved
;
611 * Snag valid data from ctextData - its length or bytesMoved,
614 if(ctextData
.Length
> bytesMoved
) {
615 /* everything's in ctext */
616 toMoveCtext
= bytesMoved
;
620 /* must be some in remData too */
621 toMoveCtext
= ctextData
.Length
;
622 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
625 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
628 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
635 stPrintCdsaError("CSSM_EncryptData", crtn
);
636 serr
= SSLCryptoError
;
639 CSSM_DeleteContext(cryptHand
);
642 /* free data mallocd by CSP */
643 stFreeCssmData(&ctextData
, CSSM_FALSE
);
644 stFreeCssmData(&remData
, CSSM_FALSE
);
648 SSLErr
sslRsaDecrypt(
650 const CSSM_KEY_PTR privKey
,
651 CSSM_CSP_HANDLE cspHand
,
652 const UInt8
*cipherText
,
653 UInt32 cipherTextLen
,
654 UInt8
*plainText
, // mallocd by caller; RETURNED
655 UInt32 plainTextLen
, // available
656 UInt32
*actualBytes
) // RETURNED
658 CSSM_DATA ptextData
= {0, NULL
};
660 CSSM_DATA remData
= {0, NULL
};
661 CSSM_CC_HANDLE cryptHand
= 0;
662 SSLErr serr
= SSLInternalError
;
664 uint32 bytesMoved
= 0;
665 CSSM_ACCESS_CREDENTIALS creds
;
667 CASSERT(ctx
!= NULL
);
668 CASSERT(actualBytes
!= NULL
);
671 if((privKey
== NULL
) || (cspHand
== 0)) {
672 errorLog0("sslRsaDecrypt: bad privKey/cspHand\n");
673 return SSLInternalError
;
675 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
676 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
683 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
684 return SSLCryptoError
;
686 ctextData
.Data
= (uint8
*)cipherText
;
687 ctextData
.Length
= cipherTextLen
;
689 if(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
691 * Special case, decrypting with public key (i.e., raw verify). Add
692 * the required context attr.
694 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
696 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
697 modeAttr
.AttributeLength
= sizeof(uint32
);
698 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PUBLIC_KEY
;
699 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
701 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
702 CSSM_DeleteContext(cryptHand
);
703 return SSLCryptoError
;
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 errorLog2("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
724 plainTextLen
, bytesMoved
);
725 serr
= SSLDataOverflow
;
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
);
758 serr
= SSLCryptoError
;
761 CSSM_DeleteContext(cryptHand
);
764 /* free data mallocd by CSP */
765 stFreeCssmData(&ptextData
, CSSM_FALSE
);
766 stFreeCssmData(&remData
, CSSM_FALSE
);
770 #endif /* APPLE_DOMESTIC_CSP_REQUIRED */
773 * Obtain size of key in bytes.
775 UInt32
sslKeyLengthInBytes(const CSSM_KEY_PTR key
)
777 CASSERT(key
!= NULL
);
778 return (((key
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
782 * Get raw key bits from an RSA public key.
784 SSLErr
sslGetPubKeyBits(
786 const CSSM_KEY_PTR pubKey
,
787 CSSM_CSP_HANDLE cspHand
,
788 SSLBuffer
*modulus
, // data mallocd and RETURNED
789 SSLBuffer
*exponent
) // data mallocd and RETURNED
792 CSSM_BOOL didWrap
= CSSM_FALSE
;
793 CSSM_KEYHEADER_PTR hdr
;
794 CSSM_CC_HANDLE ccHand
;
796 SSLBuffer pubKeyBlob
;
798 CSSM_ACCESS_CREDENTIALS creds
;
800 CASSERT(ctx
!= NULL
);
801 CASSERT(modulus
!= NULL
);
802 CASSERT(exponent
!= NULL
);
803 CASSERT(pubKey
!= NULL
);
805 hdr
= &pubKey
->KeyHeader
;
806 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
807 errorLog1("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr
->KeyClass
);
808 return SSLInternalError
;
810 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
811 errorLog1("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr
->AlgorithmId
);
812 return SSLInternalError
;
816 * Handle possible reference format - I think it should be in
817 * blob form since it came from the DL, but conversion is
820 switch(hdr
->BlobType
) {
821 case CSSM_KEYBLOB_RAW
:
823 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
826 case CSSM_KEYBLOB_REFERENCE
:
828 * Convert to a blob via "NULL wrap"; no wrapping key,
831 srtn
= attachToCsp(ctx
);
835 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
836 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
846 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
849 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
850 crtn
= CSSM_WrapKey(ccHand
,
853 NULL
, // descriptiveData
855 CSSM_DeleteContext(ccHand
);
857 stPrintCdsaError("CSSM_WrapKey", crtn
);
858 return SSLCryptoError
;
860 hdr
= &wrappedKey
.KeyHeader
;
861 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
862 errorLog1("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
864 return SSLCryptoError
;
867 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
871 errorLog1("sslGetPubKeyBits: bad BlobType (%ld)\n",
873 return SSLInternalError
;
875 } /* switch BlobType */
877 CASSERT(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
878 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
880 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
886 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
887 * Server-initiated key exchange.
889 SSLErr
sslGetPubKeyFromBits(
891 const SSLBuffer
*modulus
,
892 const SSLBuffer
*exponent
,
893 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
894 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
896 CSSM_KEY_PTR key
= NULL
;
899 CSSM_KEYHEADER_PTR hdr
;
900 CSSM_KEY_SIZE keySize
;
903 CASSERT((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
904 CASSERT((pubKey
!= NULL
) && (cspHand
!= NULL
));
909 serr
= attachToCsp(ctx
);
913 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
918 /* the rest is boilerplate, cook up a good-looking public key */
919 key
= sslMalloc(sizeof(CSSM_KEY
));
923 memset(key
, 0, sizeof(CSSM_KEY
));
924 hdr
= &key
->KeyHeader
;
926 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
927 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
928 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
929 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
930 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
931 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
932 /* comply with ASA requirements */
933 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
934 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
935 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
936 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
937 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
938 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
940 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
942 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
945 * Get keySizeInBits. This also serves to validate the key blob
948 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
950 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
951 serr
= SSLCryptoError
;
956 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
958 *cspHand
= ctx
->cspHand
;
962 /* note this frees the blob */
963 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
968 #pragma mark *** Public Certificate Functions ***
971 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
972 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
974 * For now, the returned cspHand is a copy of ctx->cspHand, so it
975 * doesn't have to be detached later - this may change....
977 SSLErr
sslPubKeyFromCert(
979 const SSLBuffer
*derCert
,
980 CSSM_KEY_PTR
*pubKey
, // RETURNED
981 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
987 CASSERT(ctx
!= NULL
);
988 CASSERT(derCert
!= NULL
);
989 CASSERT(pubKey
!= NULL
);
990 CASSERT(cspHand
!= NULL
);
995 serr
= attachToCl(ctx
);
999 serr
= attachToCsp(ctx
);
1003 SSLBUF_TO_CSSM(derCert
, &certData
);
1004 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, pubKey
);
1009 *cspHand
= ctx
->cspHand
;
1019 /* for writing root cert to a file */
1021 static OSErr
writeBlob(const CSSM_DATA_PTR blob
,
1022 const char *fileName
)
1027 long count
= blob
->Length
;
1028 int len
= strlen(fileName
);
1033 memmove(&fsp
.name
[1], fileName
, len
);
1035 err
= FSpCreate(&fsp
, 0, 0, 0);
1036 if(err
&& (err
!= dupFNErr
)) {
1037 dprintf1("***FSpCreate() returned %d\n", err
);
1040 err
= FSpOpenDF(&fsp
, fsRdWrPerm
, &fileRef
);
1042 dprintf1("***FSpOpenDF() returned %d\n", err
);
1045 err
= FSWrite(fileRef
, &count
, blob
->Data
);
1047 dprintf1("***FSWrite() returned %d\n", err
);
1050 err
= FSClose(fileRef
);
1052 dprintf1("***FSClose() returned %d\n", err
);
1058 void writeBufBlob(const SSLBuffer
*blob
,
1059 const char *fileName
)
1063 SSLBUF_TO_CSSM(blob
, &d
)
1064 writeBlob(&d
, fileName
);
1069 #if ST_KEYCHAIN_ENABLE
1072 * Given a CSSM_CERTGROUP which fails due to CSSM_TP_INVALID_ANCHOR
1073 * (chain verifies to an unknown root):
1075 * -- find the root cert
1076 * -- add it to newRootCertKc if present (else error)
1077 * -- add it to trustedCerts
1078 * -- re-verify certgroup, demand full success
1080 static SSLErr
sslHandleNewRoot(
1082 CSSM_CERTGROUP_PTR certGroup
)
1085 CSSM_DATA_PTR rootCert
;
1090 CASSERT(ctx
!= NULL
);
1091 CASSERT(certGroup
!= NULL
);
1093 if(ctx
->newRootCertKc
== NULL
) {
1094 /* no place to add this; done */
1095 return SSLUnknownRootCert
;
1099 * The root cert "should" be at the end of the chain, but
1100 * let's not assume that. (We are assuming that there is
1101 * only one root in the cert group...)
1103 for(i
=0; i
<certGroup
->NumCerts
; i
++) {
1104 rootCert
= &certGroup
->CertList
[i
];
1105 if(sslVerifyCert(ctx
, rootCert
, rootCert
, ctx
->cspHand
, &expired
)) {
1109 if(i
== certGroup
->NumCerts
) {
1110 /* Huh! no root cert!? We should not have been called! */
1111 errorLog0("sslHandleNewRoot: no root cert!\n");
1112 return SSLInternalError
;
1116 * Add to newRootCertKc. This may well fail due to user interaction.
1118 serr
= sslAddNewRoot(ctx
, rootCert
);
1124 * Just to be sure...reverify the whole cert chain.
1126 brtn
= CSSM_TP_CertGroupVerify(
1131 NULL
, // PolicyIdentifiers
1132 0, // NumberofPolicyIdentifiers
1133 CSSM_TP_STOP_ON_POLICY
,
1135 ctx
->trustedCerts
, // AnchorCerts
1136 ctx
->numTrustedCerts
,
1137 NULL
, // VerifyScope
1142 NULL
); // evidenceSize
1143 if(brtn
== CSSM_FALSE
) {
1144 errorLog0("sslHandleNewRoot: adding new root did not help!\n");
1145 return SSLUnknownRootCert
;
1150 #endif /* ST_KEYCHAIN_ENABLE */
1152 /* free a CSSM_CERT_GROUP */
1153 static void sslFreeCertGroup(
1154 CSSM_CERTGROUP_PTR certGroup
,
1155 CSSM_BOOL freeCerts
, // free individual cert fields
1156 CSSM_BOOL freeStruct
) // free the overall CSSM_CERTGROUP
1160 if(certGroup
== NULL
) {
1164 /* free the individual cert Data fields */
1165 if(certGroup
->GroupList
.CertList
) {
1167 for(dex
=0; dex
<certGroup
->NumCerts
; dex
++) {
1168 stFreeCssmData(&certGroup
->GroupList
.CertList
[dex
], CSSM_FALSE
);
1171 /* and the array of CSSM_DATAs */
1172 stAppFree(certGroup
->GroupList
.CertList
, NULL
);
1175 stAppFree(certGroup
, NULL
);
1180 * Verify a chain of DER-encoded certs.
1181 * First cert in a chain is root; this must also be present
1182 * in ctx->trustedCerts.
1184 SSLErr
sslVerifyCertChain(
1186 const SSLCertificate
*certChain
)
1189 CSSM_CERTGROUP certGroup
;
1192 SSLCertificate
*c
= (SSLCertificate
*)certChain
;
1194 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
1195 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
1196 CSSM_FIELD policyId
;
1197 CSSM_DL_DB_LIST dbList
;
1199 numCerts
= SSLGetCertificateChainLength(certChain
);
1205 serr
= attachToAll(ctx
);
1212 * SSLCertificate chain --> CSSM TP cert group.
1213 * TP Cert group has root at the end, opposite of
1214 * SSLCertificate chain.
1216 certGroup
.GroupList
.CertList
=
1217 (CSSM_DATA_PTR
)sslMalloc(numCerts
* sizeof(CSSM_DATA
));
1218 if(certGroup
.GroupList
.CertList
== NULL
) {
1219 return SSLMemoryErr
;
1221 certGroup
.CertGroupType
= CSSM_CERTGROUP_ENCODED_CERT
;
1222 certGroup
.CertType
= CSSM_CERT_X_509v3
;
1223 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
1224 certGroup
.NumCerts
= numCerts
;
1226 memset(certGroup
.GroupList
.CertList
, 0, numCerts
* sizeof(CSSM_DATA
));
1228 for(i
=numCerts
-1; i
>=0; i
--) {
1229 SSLBUF_TO_CSSM(&c
->derCert
, &certGroup
.GroupList
.CertList
[i
]);
1234 if(ctx
->rootCertName
!= NULL
) {
1235 /* save root cert */
1236 writeBlob(&certGroup
.CertList
[numCerts
-1], ctx
->rootCertName
);
1238 #endif /* SSL_DEBUG */
1240 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
1241 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
1242 vfyCtx
.Cred
= &authCtx
;
1244 /* CSSM_TP_CALLERAUTH_CONTEXT components */
1246 typedef struct cssm_tp_callerauth_context {
1247 CSSM_TP_POLICYINFO Policy;
1248 CSSM_TIMESTRING VerifyTime;
1249 CSSM_TP_STOP_ON VerificationAbortOn;
1250 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
1251 uint32 NumberOfAnchorCerts;
1252 CSSM_DATA_PTR AnchorCerts;
1253 CSSM_DL_DB_LIST_PTR DBList;
1254 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
1255 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
1257 /* zero or one policy here */
1258 policyId
.FieldValue
.Data
= NULL
;
1259 policyId
.FieldValue
.Length
= 0;
1260 policyId
.FieldOid
= CSSMOID_APPLE_TP_SSL
;
1261 authCtx
.Policy
.NumberOfPolicyIds
= 1;
1262 authCtx
.Policy
.PolicyIds
= &policyId
;
1263 authCtx
.Policy
.PolicyControl
= ctx
->allowExpiredCerts
?
1264 CSSM_TP_ALLOW_EXPIRE
: NULL
;
1265 authCtx
.VerifyTime
= NULL
;
1266 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
1267 authCtx
.CallbackWithVerifiedCert
= NULL
;
1268 authCtx
.NumberOfAnchorCerts
= ctx
->numTrustedCerts
;
1269 authCtx
.AnchorCerts
= ctx
->trustedCerts
;
1270 memset(&dbList
, 0, sizeof(CSSM_DL_DB_LIST
));
1271 authCtx
.DBList
= &dbList
;
1272 authCtx
.CallerCredentials
= NULL
;
1275 * Here we go; hand it over to TP. Note trustedCerts are our
1276 * known good Anchor certs; they're already formatted properly.
1277 * Unlike most other Apple code, we demand full success here,
1278 * implying that the last cert in the chain is indeed an Anchor
1279 * cert. We already know that all of our anchor certs are
1280 * roots, so on successful return, we'll know the incoming
1281 * chain has a root, it verifies to that root, and that that
1282 * root is in trustedCerts.
1284 crtn
= CSSM_TP_CertGroupVerify(ctx
->tpHand
,
1289 NULL
); // no evidence needed
1293 /* get some detailed error info */
1295 case CSSMERR_TP_INVALID_ANCHOR_CERT
:
1296 /* root found but we don't trust it */
1297 if(ctx
->allowAnyRoot
) {
1298 dprintf0("***Warning: accepting unknown root cert\n");
1301 #if ST_KEYCHAIN_ENABLE
1302 if(ctx
->newRootCertKc
!= NULL
) {
1303 /* see if user wants to handle new root */
1304 serr
= sslHandleNewRoot(ctx
, &certGroup
);
1307 serr
= SSLUnknownRootCert
;
1310 serr
= SSLUnknownRootCert
;
1311 #endif /* ST_KEYCHAIN_ENABLE */
1313 case CSSMERR_TP_NOT_TRUSTED
:
1314 /* no root, not even in implicit SSL roots */
1315 if(ctx
->allowAnyRoot
) {
1316 dprintf0("***Warning: accepting unverified cert chain\n");
1319 serr
= SSLNoRootCert
;
1321 case CSSMERR_TP_CERT_EXPIRED
:
1322 /* FIXME - tolerate this case via some TBD flag */
1323 serr
= SSLCertExpired
;
1325 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1326 serr
= SSLCertNotYetValid
;
1330 "sslVerifyCertChain: CSSM_TP_CertGroupVerify returned", crtn
);
1331 serr
= X509CertChainInvalidErr
;
1337 * don't free individual certs - caller still owns them
1338 * don't free struct - on stack
1340 sslFreeCertGroup(&certGroup
, CSSM_FALSE
, CSSM_FALSE
);
1346 /* not needed in X */
1349 * Given two certs, verify subjectCert with issuerCert. Returns
1350 * CSSM_TRUE on successful verify.
1351 * Only special case on error is "subject cert expired", indicated by
1352 * *subjectExpired returned as CSSM_TRUE.
1354 CSSM_BOOL
sslVerifyCert(
1356 const CSSM_DATA_PTR subjectCert
,
1357 const CSSM_DATA_PTR issuerCert
,
1358 CSSM_CSP_HANDLE cspHand
, // can verify with issuerCert
1359 CSSM_BOOL
*subjectExpired
) // RETURNED
1361 CSSM_KEY_PTR issuerPubKey
= NULL
;
1362 CSSM_DATA_PTR sigOid
= NULL
;
1363 CSSM_HANDLE ResultsHandle
;
1364 uint32 NumberOfFields
;
1365 CSSM_ERROR_PTR pErr
= NULL
;
1367 uint32
*algId
= NULL
; // mallocd by CL_Passthrough
1368 CSSM_CC_HANDLE ccHand
= 0;
1370 *subjectExpired
= CSSM_FALSE
;
1372 /* ensure connection to CL, TP */
1373 if(attachToCl(ctx
)) {
1376 if(attachToTp(ctx
)) {
1380 /* public key from issuer cert */
1381 issuerPubKey
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, issuerCert
);
1382 if(issuerPubKey
== NULL
) {
1385 /* subsequent errors to abort: */
1387 /* signature alg from subject cert */
1388 sigOid
= CSSM_CL_CertGetFirstFieldValue(ctx
->clHand
,
1390 &CSSMOID_X509V1SignatureAlgorithm
,
1393 if(sigOid
== NULL
) {
1394 stPrintCdsaError("CSSM_CL_CertGetFirstFieldValue");
1396 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1399 /* cleanup query state */
1400 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1402 /* convert: alg OID to CSSM_ALGID_xxx */
1403 algId
= (uint32
*)CSSM_CL_PassThrough(ctx
->clHand
,
1404 0, // no handle needed
1405 INTEL_X509V3_PASSTHROUGH_ALGOID_TO_ALGID
,
1407 if(*algId
== CSSM_ALGID_NONE
) {
1412 /* set up a sign context with obtained pub key and algorithm */
1413 ccHand
= CSSM_CSP_CreateSignatureContext(cspHand
,
1415 NULL
, // no passphrase
1422 /* go for it - CL takes over from here */
1423 brtn
= CSSM_CL_CertVerify(ctx
->clHand
,
1427 NULL
, // VerifyScope
1429 if(!brtn
&& (CSSM_GetError()->error
== CSSM_CL_CERT_EXPIRED
)) {
1430 *subjectExpired
= CSSM_TRUE
;
1434 if(issuerPubKey
!= NULL
) {
1435 CSSM_Free(issuerPubKey
->KeyData
.Data
);
1436 CSSM_Free(issuerPubKey
);
1438 if(sigOid
!= NULL
) {
1439 CSSM_Free(sigOid
->Data
);
1443 CSSM_DeleteContext(ccHand
);
1450 #endif /* 0 - not needed */
1452 #if ST_KEYCHAIN_ENABLE
1453 /* no cert parsing in this version */
1456 * Given a DER-encoded cert, obtain its DER-encoded subject name.
1458 CSSM_DATA_PTR
sslGetCertSubjectName(
1460 const CSSM_DATA_PTR cert
)
1462 uint32 NumberOfFields
= 0;
1463 CSSM_HANDLE ResultsHandle
= 0;
1464 CSSM_DATA_PTR pEncodedName
= NULL
;
1467 /* ensure connection to CL */
1468 if(attachToCl(ctx
)) {
1471 crtn
= CSSM_CL_CertGetFirstFieldValue(
1474 &CSSMOID_X509V1SubjectName
,
1479 stPrintCdsaError("CertGetFirstFieldValue", crtn
);
1481 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1482 return pEncodedName
;
1484 #endif ST_KEYCHAIN_ENABLE
1486 #if (SSL_DEBUG && ST_KEYCHAIN_ENABLE)
1487 void verifyTrustedRoots(SSLContext
*ctx
,
1488 CSSM_DATA_PTR certs
,
1495 for(i
=0; i
<numCerts
; i
++) {
1497 if(!sslVerifyCert(ctx
,
1502 sslPanic("Bad trusted cert!\n");