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>
51 /* X.509 includes, from cssmapi */
52 #include <Security/x509defs.h> /* x.509 function and type defs */
53 #include <Security/oidsalg.h>
54 #include <Security/oidscert.h>
56 #pragma mark *** Utilities ***
59 * Set up a Raw symmetric key with specified algorithm and key bits.
61 OSStatus
sslSetUpSymmKey(
64 CSSM_KEYUSE keyUse
, // CSSM_KEYUSE_ENCRYPT, etc.
65 CSSM_BOOL copyKey
, // true: copy keyData false: set by reference
67 uint32 keyDataLen
) // in bytes
72 memset(symKey
, 0, sizeof(CSSM_KEY
));
74 serr
= stSetUpCssmData(&symKey
->KeyData
, keyDataLen
);
78 memmove(symKey
->KeyData
.Data
, keyData
, keyDataLen
);
81 symKey
->KeyData
.Data
= keyData
;
82 symKey
->KeyData
.Length
= keyDataLen
;
85 /* set up the header */
86 hdr
= &symKey
->KeyHeader
;
87 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
88 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
89 hdr
->AlgorithmId
= alg
;
90 hdr
->KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
91 hdr
->LogicalKeySizeInBits
= keyDataLen
* 8;
92 hdr
->KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
93 hdr
->KeyUsage
= keyUse
;
94 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
99 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
102 CSSM_CSP_HANDLE cspHand
,
103 CSSM_KEY_PTR
*key
, /* so we can null it out */
104 #if ST_KC_KEYS_NEED_REF
105 SecKeychainRef
*kcItem
)
114 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
116 stAppFree(*key
, NULL
); // key mallocd by CL using our callback
119 #if ST_KC_KEYS_NEED_REF
120 if((kcItem
!= NULL
) && (*kcItem
!= NULL
)) {
121 KCReleaseItem(kcItem
); /* does this NULL the referent? */
129 * Standard app-level memory functions required by CDSA.
131 void * stAppMalloc (uint32 size
, void *allocRef
) {
132 return( malloc(size
) );
134 void stAppFree (void *mem_ptr
, void *allocRef
) {
138 void * stAppRealloc (void *ptr
, uint32 size
, void *allocRef
) {
139 return( realloc( ptr
, size
) );
141 void * stAppCalloc (uint32 num
, uint32 size
, void *allocRef
) {
142 return( calloc( num
, size
) );
146 * Ensure there's a connection to ctx->cspHand. If there
147 * already is one, fine.
148 * Note that as of 12/18/00, we assume we're connected to
149 * all modules all the time (since we do an attachToAll() in
152 OSStatus
attachToCsp(SSLContext
*ctx
)
155 if(ctx
->cspHand
!= 0) {
159 return errSSLModuleAttach
;
164 * Connect to TP, CL; reusable.
166 OSStatus
attachToCl(SSLContext
*ctx
)
169 if(ctx
->clHand
!= 0) {
173 return errSSLModuleAttach
;
177 OSStatus
attachToTp(SSLContext
*ctx
)
180 if(ctx
->tpHand
!= 0) {
184 return errSSLModuleAttach
;
189 * Convenience function - attach to CSP, CL, TP. Reusable.
191 OSStatus
attachToAll(SSLContext
*ctx
)
196 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
, &ctx
->tpHand
);
198 return errSSLModuleAttach
;
205 OSStatus
detachFromAll(SSLContext
*ctx
)
208 /* No more, attachments are kept on a global basis */
210 if(ctx
->cspHand
!= 0) {
211 CSSM_ModuleDetach(ctx
->cspHand
);
214 if(ctx
->tpHand
!= 0) {
215 CSSM_ModuleDetach(ctx
->tpHand
);
218 if(ctx
->clHand
!= 0) {
219 CSSM_ModuleDetach(ctx
->clHand
);
227 #pragma mark *** CSSM_DATA routines ***
229 CSSM_DATA_PTR
stMallocCssmData(
232 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
242 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
249 CSSM_BOOL freeStruct
)
254 if(data
->Data
!= NULL
) {
255 stAppFree(data
->Data
, NULL
);
260 stAppFree(data
, NULL
);
265 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
266 * Malloc the Data ptr if necessary.
268 OSStatus
stSetUpCssmData(
272 assert(data
!= NULL
);
273 if(data
->Length
== 0) {
274 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
275 if(data
->Data
== NULL
) {
279 else if(data
->Length
< length
) {
280 sslErrorLog("stSetUpCssmData: length too small\n");
283 data
->Length
= length
;
288 #pragma mark *** Public CSP Functions ***
291 * Raw RSA sign/verify.
293 * Initial X port: CSP doesns't support this, so we'll do sign/verify via
294 * raw RSA encrypt/decrypt here.
296 #define SIGN_VFY_VIA_ENCR_DECR 0
298 #if SIGN_VFY_VIA_ENCR_DECR
300 OSStatus
sslRsaRawSign(
302 const CSSM_KEY
*privKey
,
303 CSSM_CSP_HANDLE cspHand
,
304 const UInt8
*plainText
,
306 UInt8
*sig
, // mallocd by caller; RETURNED
307 UInt32 sigLen
, // available
308 UInt32
*actualBytes
) // RETURNED
310 /* Raw RSA sign with no digest is the same as raw RSA encrypt. */
311 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
312 * than we really want */
314 CSSM_KEYUSE savedKeyUse
= privKey
->KeyHeader
.KeyUsage
;
315 privKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
316 serr
= sslRsaEncrypt(ctx
,
324 privKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
328 OSStatus
sslRsaRawVerify(
330 const CSSM_KEY
*pubKey
,
331 CSSM_CSP_HANDLE cspHand
,
332 const UInt8
*plainText
,
338 * Raw RSA verify with no digest is just a comparison of the incoming
339 * plaintext with (signature, decrypted via raw RSA decrypt).
346 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
347 * than we really want */
348 CSSM_KEYUSE savedKeyUse
= pubKey
->KeyHeader
.KeyUsage
;
349 pubKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
351 /* malloc space for decrypting the signature */
352 digest
= sslMalloc(plainTextLen
);
357 /* decrypt signature */
358 serr
= sslRsaDecrypt(ctx
,
366 pubKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
370 if((actualBytes
!= plainTextLen
) ||
371 (memcmp(plainText
, digest
, plainTextLen
))) {
372 sslErrorLog("sslRsaRawVerify: sig miscompare\n");
383 #else /* OS9 and future post-cheetah version */
385 OSStatus
sslRsaRawSign(
387 const CSSM_KEY
*privKey
,
388 CSSM_CSP_HANDLE cspHand
,
389 const UInt8
*plainText
,
391 UInt8
*sig
, // mallocd by caller; RETURNED
392 UInt32 sigLen
, // available
393 UInt32
*actualBytes
) // RETURNED
395 CSSM_CC_HANDLE sigHand
= 0;
402 if((privKey
== NULL
) ||
404 (plainText
== NULL
) ||
406 (actualBytes
== NULL
)) {
407 sslErrorLog("sslRsaRawSign: bad arguments\n");
408 return errSSLInternal
;
412 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
418 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
422 ptextData
.Data
= (uint8
*)plainText
;
423 ptextData
.Length
= plainTextLen
;
425 /* caller better get this right, or the SignData will fail */
427 sigData
.Length
= sigLen
;
429 crtn
= CSSM_SignData(sigHand
,
432 CSSM_ALGID_NONE
, // digestAlg
435 stPrintCdsaError("CSSM_SignData", crtn
);
439 *actualBytes
= sigData
.Length
;
443 CSSM_DeleteContext(sigHand
);
448 OSStatus
sslRsaRawVerify(
450 const CSSM_KEY
*pubKey
,
451 CSSM_CSP_HANDLE cspHand
,
452 const UInt8
*plainText
,
457 CSSM_CC_HANDLE sigHand
= 0;
464 if((pubKey
== NULL
) ||
466 (plainText
== NULL
) ||
468 sslErrorLog("sslRsaRawVerify: bad arguments\n");
469 return errSSLInternal
;
472 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
478 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
482 ptextData
.Data
= (uint8
*)plainText
;
483 ptextData
.Length
= plainTextLen
;
484 sigData
.Data
= (uint8
*)sig
;
485 sigData
.Length
= sigLen
;
487 crtn
= CSSM_VerifyData(sigHand
,
490 CSSM_ALGID_NONE
, // digestAlg
493 stPrintCdsaError("CSSM_VerifyData", crtn
);
500 CSSM_DeleteContext(sigHand
);
504 #endif /* SIGN_VFY_VIA_ENCR_DECR */
509 OSStatus
sslRsaEncrypt(
511 const CSSM_KEY
*pubKey
,
512 CSSM_CSP_HANDLE cspHand
,
513 const UInt8
*plainText
,
515 UInt8
*cipherText
, // mallocd by caller; RETURNED
516 UInt32 cipherTextLen
, // available
517 UInt32
*actualBytes
) // RETURNED
519 CSSM_DATA ctextData
= {0, NULL
};
521 CSSM_DATA remData
= {0, NULL
};
522 CSSM_CC_HANDLE cryptHand
= 0;
523 OSStatus serr
= errSSLInternal
;
525 uint32 bytesMoved
= 0;
526 CSSM_ACCESS_CREDENTIALS creds
;
529 assert(actualBytes
!= NULL
);
532 if((pubKey
== NULL
) || (cspHand
== 0)) {
533 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
534 return errSSLInternal
;
537 #if RSA_PUB_KEY_USAGE_HACK
538 ((CSSM_KEY_PTR
)pubKey
)->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
540 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
542 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
549 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
552 ptextData
.Data
= (uint8
*)plainText
;
553 ptextData
.Length
= plainTextLen
;
555 if(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
557 * Special case, encrypting with private key (i.e., raw sign). Add
558 * the required context attr.
560 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
562 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
563 modeAttr
.AttributeLength
= sizeof(uint32
);
564 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PRIVATE_KEY
;
565 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
567 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
568 CSSM_DeleteContext(cryptHand
);
574 * Have CSP malloc ciphertext
576 crtn
= CSSM_EncryptData(cryptHand
,
583 if(crtn
== CSSM_OK
) {
585 * ciphertext in both ctextData and remData; ensure it'll fit
586 * in caller's buf & copy
588 if(bytesMoved
> cipherTextLen
) {
589 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
590 cipherTextLen
, bytesMoved
);
597 *actualBytes
= bytesMoved
;
599 * Snag valid data from ctextData - its length or bytesMoved,
602 if(ctextData
.Length
> bytesMoved
) {
603 /* everything's in ctext */
604 toMoveCtext
= bytesMoved
;
608 /* must be some in remData too */
609 toMoveCtext
= ctextData
.Length
;
610 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
613 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
616 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
623 stPrintCdsaError("CSSM_EncryptData", crtn
);
627 CSSM_DeleteContext(cryptHand
);
630 /* free data mallocd by CSP */
631 stFreeCssmData(&ctextData
, CSSM_FALSE
);
632 stFreeCssmData(&remData
, CSSM_FALSE
);
636 OSStatus
sslRsaDecrypt(
638 const CSSM_KEY
*privKey
,
639 CSSM_CSP_HANDLE cspHand
,
640 const UInt8
*cipherText
,
641 UInt32 cipherTextLen
,
642 UInt8
*plainText
, // mallocd by caller; RETURNED
643 UInt32 plainTextLen
, // available
644 UInt32
*actualBytes
) // RETURNED
646 CSSM_DATA ptextData
= {0, NULL
};
648 CSSM_DATA remData
= {0, NULL
};
649 CSSM_CC_HANDLE cryptHand
= 0;
650 OSStatus serr
= errSSLInternal
;
652 uint32 bytesMoved
= 0;
653 CSSM_ACCESS_CREDENTIALS creds
;
656 assert(actualBytes
!= NULL
);
659 if((privKey
== NULL
) || (cspHand
== 0)) {
660 sslErrorLog("sslRsaDecrypt: bad privKey/cspHand\n");
661 return errSSLInternal
;
663 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
664 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
671 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
674 ctextData
.Data
= (uint8
*)cipherText
;
675 ctextData
.Length
= cipherTextLen
;
677 if(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
679 * Special case, decrypting with public key (i.e., raw verify). Add
680 * the required context attr.
682 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
684 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
685 modeAttr
.AttributeLength
= sizeof(uint32
);
686 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PUBLIC_KEY
;
687 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
689 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
690 CSSM_DeleteContext(cryptHand
);
696 * Have CSP malloc plaintext
698 crtn
= CSSM_DecryptData(cryptHand
,
705 if(crtn
== CSSM_OK
) {
707 * plaintext in both ptextData and remData; ensure it'll fit
708 * in caller's buf & copy
710 if(bytesMoved
> plainTextLen
) {
711 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
712 plainTextLen
, bytesMoved
);
719 *actualBytes
= bytesMoved
;
721 * Snag valid data from ptextData - its length or bytesMoved,
724 if(ptextData
.Length
> bytesMoved
) {
725 /* everything's in ptext */
726 toMovePtext
= bytesMoved
;
730 /* must be some in remData too */
731 toMovePtext
= ptextData
.Length
;
732 toMoveRem
= bytesMoved
- toMovePtext
; // remainder
735 memmove(plainText
, ptextData
.Data
, toMovePtext
);
738 memmove(plainText
+ toMovePtext
, remData
.Data
,
745 stPrintCdsaError("CSSM_DecryptData", crtn
);
749 CSSM_DeleteContext(cryptHand
);
752 /* free data mallocd by CSP */
753 stFreeCssmData(&ptextData
, CSSM_FALSE
);
754 stFreeCssmData(&remData
, CSSM_FALSE
);
759 * Obtain size of key in bytes.
761 UInt32
sslKeyLengthInBytes(const CSSM_KEY
*key
)
764 return (((key
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
768 * Get raw key bits from an RSA public key.
770 OSStatus
sslGetPubKeyBits(
772 const CSSM_KEY
*pubKey
,
773 CSSM_CSP_HANDLE cspHand
,
774 SSLBuffer
*modulus
, // data mallocd and RETURNED
775 SSLBuffer
*exponent
) // data mallocd and RETURNED
778 CSSM_BOOL didWrap
= CSSM_FALSE
;
779 const CSSM_KEYHEADER
*hdr
;
780 CSSM_CC_HANDLE ccHand
;
782 SSLBuffer pubKeyBlob
;
784 CSSM_ACCESS_CREDENTIALS creds
;
787 assert(modulus
!= NULL
);
788 assert(exponent
!= NULL
);
789 assert(pubKey
!= NULL
);
791 hdr
= &pubKey
->KeyHeader
;
792 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
793 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr
->KeyClass
);
794 return errSSLInternal
;
796 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
797 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr
->AlgorithmId
);
798 return errSSLInternal
;
802 * Handle possible reference format - I think it should be in
803 * blob form since it came from the DL, but conversion is
806 switch(hdr
->BlobType
) {
807 case CSSM_KEYBLOB_RAW
:
809 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
812 case CSSM_KEYBLOB_REFERENCE
:
814 * Convert to a blob via "NULL wrap"; no wrapping key,
817 srtn
= attachToCsp(ctx
);
821 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
822 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
832 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
835 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
836 crtn
= CSSM_WrapKey(ccHand
,
839 NULL
, // descriptiveData
841 CSSM_DeleteContext(ccHand
);
843 stPrintCdsaError("CSSM_WrapKey", crtn
);
846 hdr
= &wrappedKey
.KeyHeader
;
847 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
848 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
853 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
857 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
859 return errSSLInternal
;
861 } /* switch BlobType */
863 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
864 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
866 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
872 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
873 * Server-initiated key exchange.
875 OSStatus
sslGetPubKeyFromBits(
877 const SSLBuffer
*modulus
,
878 const SSLBuffer
*exponent
,
879 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
880 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
882 CSSM_KEY_PTR key
= NULL
;
885 CSSM_KEYHEADER_PTR hdr
;
886 CSSM_KEY_SIZE keySize
;
889 assert((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
890 assert((pubKey
!= NULL
) && (cspHand
!= NULL
));
895 serr
= attachToCsp(ctx
);
899 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
904 /* the rest is boilerplate, cook up a good-looking public key */
905 key
= (CSSM_KEY_PTR
)sslMalloc(sizeof(CSSM_KEY
));
909 memset(key
, 0, sizeof(CSSM_KEY
));
910 hdr
= &key
->KeyHeader
;
912 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
913 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
914 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
915 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
916 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
917 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
918 /* comply with ASA requirements */
919 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
920 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
921 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
922 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
923 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
924 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
926 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
928 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
931 * Get keySizeInBits. This also serves to validate the key blob
934 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
936 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
942 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
944 *cspHand
= ctx
->cspHand
;
948 /* note this frees the blob */
949 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
954 #pragma mark *** Public Certificate Functions ***
957 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
958 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
960 * For now, the returned cspHand is a copy of ctx->cspHand, so it
961 * doesn't have to be detached later - this may change.
963 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
964 * us to tell the CL what CSP to use, we really have no way of knowing
965 * what is going on here...we return the process-wide (bare) cspHand,
966 * which is currently always able to deal with this raw public key.
968 OSStatus
sslPubKeyFromCert(
970 const SSLBuffer
&derCert
,
971 CSSM_KEY_PTR
*pubKey
, // RETURNED
972 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
979 assert(pubKey
!= NULL
);
980 assert(cspHand
!= NULL
);
985 serr
= attachToCl(ctx
);
989 serr
= attachToCsp(ctx
);
993 SSLBUF_TO_CSSM(&derCert
, &certData
);
994 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, pubKey
);
996 return errSSLBadCert
;
999 *cspHand
= ctx
->cspHand
;
1004 #if ST_MANAGES_TRUSTED_ROOTS
1007 * Given a CSSM_CERTGROUP which fails due to CSSM_TP_INVALID_ANCHOR
1008 * (chain verifies to an unknown root):
1010 * -- find the root cert
1011 * -- add it to newRootCertKc if present (else error)
1012 * -- add it to trustedCerts
1013 * -- re-verify certgroup, demand full success
1015 static OSStatus
sslHandleNewRoot(
1017 CSSM_CERTGROUP_PTR certGroup
)
1020 CSSM_DATA_PTR rootCert
;
1025 assert(ctx
!= NULL
);
1026 assert(certGroup
!= NULL
);
1028 if(ctx
->newRootCertKc
== NULL
) {
1029 /* no place to add this; done */
1030 return errSSLUnknownRootCert
;
1034 * The root cert "should" be at the end of the chain, but
1035 * let's not assume that. (We are assuming that there is
1036 * only one root in the cert group...)
1038 for(i
=0; i
<certGroup
->NumCerts
; i
++) {
1039 rootCert
= &certGroup
->CertList
[i
];
1040 if(sslVerifyCert(ctx
, rootCert
, rootCert
, ctx
->cspHand
, &expired
)) {
1044 if(i
== certGroup
->NumCerts
) {
1045 /* Huh! no root cert!? We should not have been called! */
1046 sslErrorLog("sslHandleNewRoot: no root cert!\n");
1047 return errSSLInternal
;
1051 * Add to newRootCertKc. This may well fail due to user interaction.
1053 serr
= sslAddNewRoot(ctx
, rootCert
);
1059 * Just to be sure...reverify the whole cert chain.
1061 brtn
= CSSM_TP_CertGroupVerify(
1066 NULL
, // PolicyIdentifiers
1067 0, // NumberofPolicyIdentifiers
1068 CSSM_TP_STOP_ON_POLICY
,
1070 ctx
->trustedCerts
, // AnchorCerts
1071 ctx
->numTrustedCerts
,
1072 NULL
, // VerifyScope
1077 NULL
); // evidenceSize
1078 if(brtn
== CSSM_FALSE
) {
1079 sslErrorLog("sslHandleNewRoot: adding new root did not help!\n");
1080 return errSSLUnknownRootCert
;
1085 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1088 * Verify a chain of DER-encoded certs.
1089 * First cert in a chain is root; this must also be present
1090 * in ctx->trustedCerts.
1092 OSStatus
sslVerifyCertChain(
1094 const SSLCertificate
&certChain
,
1095 bool verifyHostName
/* = true */)
1098 CSSM_CERTGROUP certGroup
;
1101 SSLCertificate
*c
= (SSLCertificate
*)&certChain
;
1103 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
1104 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
1105 CSSM_FIELD policyId
;
1106 CSSM_DL_DB_LIST dbList
;
1107 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
1108 CSSM_APPLE_TP_ACTION_DATA actionData
;
1110 if(!ctx
->enableCertVerify
) {
1111 /* trivial case, this is caller's responsibility */
1114 numCerts
= SSLGetCertificateChainLength(&certChain
);
1117 return errSSLBadCert
;
1120 serr
= attachToAll(ctx
);
1127 * SSLCertificate chain --> CSSM TP cert group.
1128 * TP Cert group has root at the end, opposite of
1129 * SSLCertificate chain.
1131 certGroup
.GroupList
.CertList
=
1132 (CSSM_DATA_PTR
)sslMalloc(numCerts
* sizeof(CSSM_DATA
));
1133 if(certGroup
.GroupList
.CertList
== NULL
) {
1136 certGroup
.CertGroupType
= CSSM_CERTGROUP_DATA
;
1137 certGroup
.CertType
= CSSM_CERT_X_509v3
;
1138 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
1139 certGroup
.NumCerts
= numCerts
;
1141 memset(certGroup
.GroupList
.CertList
, 0, numCerts
* sizeof(CSSM_DATA
));
1143 for(i
=numCerts
-1; i
>=0; i
--) {
1144 SSLBUF_TO_CSSM(&c
->derCert
, &certGroup
.GroupList
.CertList
[i
]);
1148 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
1149 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
1150 vfyCtx
.Cred
= &authCtx
;
1152 /* CSSM_TP_CALLERAUTH_CONTEXT components */
1154 typedef struct cssm_tp_callerauth_context {
1155 CSSM_TP_POLICYINFO Policy;
1156 CSSM_TIMESTRING VerifyTime;
1157 CSSM_TP_STOP_ON VerificationAbortOn;
1158 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
1159 uint32 NumberOfAnchorCerts;
1160 CSSM_DATA_PTR AnchorCerts;
1161 CSSM_DL_DB_LIST_PTR DBList;
1162 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
1163 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
1166 /* SSL-specific FieldValue */
1167 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
1168 if(verifyHostName
) {
1169 sslOpts
.ServerNameLen
= ctx
->peerDomainNameLen
;
1170 sslOpts
.ServerName
= ctx
->peerDomainName
;
1173 sslOpts
.ServerNameLen
= 0;
1174 sslOpts
.ServerName
= NULL
;
1177 /* TP-wide ActionData */
1178 actionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
1179 if(ctx
->numTrustedCerts
!= 0) {
1180 /* use our anchors */
1181 actionData
.ActionFlags
= 0;
1184 /* secret root-cert-enable */
1185 actionData
.ActionFlags
= 0x80000000;
1187 if(ctx
->allowExpiredCerts
) {
1188 actionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED
;
1190 if(ctx
->allowExpiredRoots
) {
1191 actionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
;
1193 vfyCtx
.ActionData
.Data
= (uint8
*)&actionData
;
1194 vfyCtx
.ActionData
.Length
= sizeof(actionData
);
1196 /* zero or one policy here */
1197 policyId
.FieldOid
= CSSMOID_APPLE_TP_SSL
;
1198 policyId
.FieldValue
.Data
= (uint8
*)&sslOpts
;
1199 policyId
.FieldValue
.Length
= sizeof(sslOpts
);
1200 authCtx
.Policy
.NumberOfPolicyIds
= 1;
1201 authCtx
.Policy
.PolicyIds
= &policyId
;
1203 authCtx
.VerifyTime
= NULL
;
1204 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
1205 authCtx
.CallbackWithVerifiedCert
= NULL
;
1206 authCtx
.NumberOfAnchorCerts
= ctx
->numTrustedCerts
;
1207 authCtx
.AnchorCerts
= ctx
->trustedCerts
;
1208 memset(&dbList
, 0, sizeof(CSSM_DL_DB_LIST
));
1209 authCtx
.DBList
= &dbList
;
1210 authCtx
.CallerCredentials
= NULL
;
1213 * Here we go; hand it over to TP. Note trustedCerts are our
1214 * known good Anchor certs; they're already formatted properly.
1215 * Unlike most other Apple code, we demand full success here,
1216 * implying that the last cert in the chain is indeed an Anchor
1217 * cert. We already know that all of our anchor certs are
1218 * roots, so on successful return, we'll know the incoming
1219 * chain has a root, it verifies to that root, and that that
1220 * root is in trustedCerts.
1222 crtn
= CSSM_TP_CertGroupVerify(ctx
->tpHand
,
1227 NULL
); // no evidence needed
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
) {
1236 sslErrorLog("***Warning: accepting unknown root cert\n");
1239 #if ST_MANAGES_TRUSTED_ROOTS
1240 if(ctx
->newRootCertKc
!= NULL
) {
1241 /* see if user wants to handle new root */
1242 serr
= sslHandleNewRoot(ctx
, &certGroup
);
1245 serr
= errSSLUnknownRootCert
;
1248 serr
= errSSLUnknownRootCert
;
1249 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1251 case CSSMERR_TP_NOT_TRUSTED
:
1252 /* no root, not even in implicit SSL roots */
1253 if(ctx
->allowAnyRoot
) {
1254 sslErrorLog("***Warning: accepting unverified cert chain\n");
1257 serr
= errSSLNoRootCert
;
1259 case CSSMERR_TP_CERT_EXPIRED
:
1260 assert(!ctx
->allowExpiredCerts
);
1261 serr
= errSSLCertExpired
;
1263 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1264 serr
= errSSLCertNotYetValid
;
1268 "sslVerifyCertChain: CSSM_TP_CertGroupVerify returned", crtn
);
1269 serr
= errSSLXCertChainInvalid
;
1275 * don't free individual certs - caller still owns them
1276 * don't free struct - on stack
1278 sslFree(certGroup
.GroupList
.CertList
);
1282 #if ST_MANAGES_TRUSTED_ROOTS
1285 * Given a DER-encoded cert, obtain its DER-encoded subject name.
1287 CSSM_DATA_PTR
sslGetCertSubjectName(
1289 const CSSM_DATA_PTR cert
)
1291 uint32 NumberOfFields
= 0;
1292 CSSM_HANDLE ResultsHandle
= 0;
1293 CSSM_DATA_PTR pEncodedName
= NULL
;
1296 /* ensure connection to CL */
1297 if(attachToCl(ctx
)) {
1300 crtn
= CSSM_CL_CertGetFirstFieldValue(
1303 &CSSMOID_X509V1SubjectName
,
1308 stPrintCdsaError("CertGetFirstFieldValue", crtn
);
1310 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1311 return pEncodedName
;
1313 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1315 #if (SSL_DEBUG && ST_MANAGES_TRUSTED_ROOTS)
1316 void verifyTrustedRoots(SSLContext
*ctx
,
1317 CSSM_DATA_PTR certs
,
1324 for(i
=0; i
<numCerts
; i
++) {
1326 if(!sslVerifyCert(ctx
,
1331 sslErrorLog("Bad trusted cert!\n");
1338 void stPrintCdsaError(const char *op
, CSSM_RETURN crtn
)
1340 cssmPerror(op
, crtn
);
1343 char *stCssmErrToStr(CSSM_RETURN err
)
1345 string errStr
= cssmErrorString(err
);
1346 return const_cast<char *>(errStr
.c_str());