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"
48 #include <Security/cssm.h>
49 #include <Security/cssmapple.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 SSLErr
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_KEYCHAIN_ENABLE && ST_KC_KEYS_NEED_REF
105 SecKeychainRef
*kcItem
)
110 CASSERT(key
!= NULL
);
114 CSSM_FreeKey(cspHand
, NULL
, *key
, CSSM_FALSE
);
119 #if ST_KEYCHAIN_ENABLE && 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 SSLErr
attachToCsp(SSLContext
*ctx
)
154 CASSERT(ctx
!= NULL
);
155 if(ctx
->cspHand
!= 0) {
159 return SSLAttachFailure
;
164 * Connect to TP, CL; reusable.
166 SSLErr
attachToCl(SSLContext
*ctx
)
168 CASSERT(ctx
!= NULL
);
169 if(ctx
->clHand
!= 0) {
173 return SSLAttachFailure
;
177 SSLErr
attachToTp(SSLContext
*ctx
)
179 CASSERT(ctx
!= NULL
);
180 if(ctx
->tpHand
!= 0) {
184 return SSLAttachFailure
;
189 * Convenience function - attach to CSP, CL, TP. Reusable.
191 SSLErr
attachToAll(SSLContext
*ctx
)
195 CASSERT(ctx
!= NULL
);
196 crtn
= attachToModules(&ctx
->cspHand
, &ctx
->clHand
,
198 #if ST_FAKE_KEYCHAIN || ST_FAKE_GET_CSPDL_HANDLE
204 return SSLAttachFailure
;
211 SSLErr
detachFromAll(SSLContext
*ctx
)
214 /* No more, attachments are kept on a global basis */
215 CASSERT(ctx
!= NULL
);
216 if(ctx
->cspHand
!= 0) {
217 CSSM_ModuleDetach(ctx
->cspHand
);
220 if(ctx
->tpHand
!= 0) {
221 CSSM_ModuleDetach(ctx
->tpHand
);
224 if(ctx
->clHand
!= 0) {
225 CSSM_ModuleDetach(ctx
->clHand
);
233 #pragma mark *** CSSM_DATA routines ***
235 CSSM_DATA_PTR
stMallocCssmData(
238 CSSM_DATA_PTR rtn
= (CSSM_DATA_PTR
)stAppMalloc(sizeof(CSSM_DATA
), NULL
);
248 rtn
->Data
= (uint8
*)stAppMalloc(size
, NULL
);
255 CSSM_BOOL freeStruct
)
260 if(data
->Data
!= NULL
) {
261 stAppFree(data
->Data
, NULL
);
266 stAppFree(data
, NULL
);
271 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
272 * Malloc the Data ptr if necessary.
274 SSLErr
stSetUpCssmData(
278 CASSERT(data
!= NULL
);
279 if(data
->Length
== 0) {
280 data
->Data
= (uint8
*)stAppMalloc(length
, NULL
);
281 if(data
->Data
== NULL
) {
285 else if(data
->Length
< length
) {
286 errorLog0("stSetUpCssmData: length too small\n");
289 data
->Length
= length
;
294 #pragma mark *** Public CSP Functions ***
297 * Common RNG function; replaces SSLRef's SSLRandomFunc.
298 * FIXME - just use /dev/random.
300 SSLErr
sslRand(SSLContext
*ctx
, SSLBuffer
*buf
)
303 CSSM_CC_HANDLE rngHand
;
307 CASSERT(ctx
!= NULL
);
308 CASSERT(buf
!= NULL
);
309 CASSERT(buf
->data
!= NULL
);
311 serr
= attachToCsp(ctx
);
315 if(buf
->length
== 0) {
316 dprintf0("sslRand: zero buf->length\n");
321 * We happen to know that the CSP has a really good RNG
322 * seed if we don't specify anything; let's use it
324 crtn
= CSSM_CSP_CreateRandomGenContext(ctx
->cspHand
,
325 CSSM_ALGID_APPLE_YARROW
,
330 stPrintCdsaError("CSSM_CSP_CreateRandomGenContext", crtn
);
331 return SSLCryptoError
;
333 SSLBUF_TO_CSSM(buf
, &randData
);
334 crtn
= CSSM_GenerateRandom(rngHand
, &randData
);
336 stPrintCdsaError("CSSM_GenerateRandom", crtn
);
337 serr
= SSLCryptoError
;
339 CSSM_DeleteContext(rngHand
);
344 * Raw RSA sign/verify.
346 * Initial X port: CSP doesns't support this, so we'll do sign/verify via
347 * raw RSA encrypt/decrypt here.
349 #define SIGN_VFY_VIA_ENCR_DECR 0
351 #if SIGN_VFY_VIA_ENCR_DECR
353 SSLErr
sslRsaRawSign(
355 const CSSM_KEY
*privKey
,
356 CSSM_CSP_HANDLE cspHand
,
357 const UInt8
*plainText
,
359 UInt8
*sig
, // mallocd by caller; RETURNED
360 UInt32 sigLen
, // available
361 UInt32
*actualBytes
) // RETURNED
363 /* Raw RSA sign with no digest is the same as raw RSA encrypt. */
364 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
365 * than we really want */
367 CSSM_KEYUSE savedKeyUse
= privKey
->KeyHeader
.KeyUsage
;
368 privKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
369 serr
= sslRsaEncrypt(ctx
,
377 privKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
381 SSLErr
sslRsaRawVerify(
383 const CSSM_KEY
*pubKey
,
384 CSSM_CSP_HANDLE cspHand
,
385 const UInt8
*plainText
,
391 * Raw RSA verify with no digest is just a comparison of the incoming
392 * plaintext with (signature, decrypted via raw RSA decrypt).
399 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
400 * than we really want */
401 CSSM_KEYUSE savedKeyUse
= pubKey
->KeyHeader
.KeyUsage
;
402 pubKey
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
404 /* malloc space for decrypting the signature */
405 digest
= sslMalloc(plainTextLen
);
410 /* decrypt signature */
411 serr
= sslRsaDecrypt(ctx
,
419 pubKey
->KeyHeader
.KeyUsage
= savedKeyUse
;
423 if((actualBytes
!= plainTextLen
) ||
424 (memcmp(plainText
, digest
, plainTextLen
))) {
425 errorLog0("sslRsaRawVerify: sig miscompare\n");
426 serr
= SSLCryptoError
;
436 #else /* OS9 and future post-cheetah version */
438 SSLErr
sslRsaRawSign(
440 const CSSM_KEY
*privKey
,
441 CSSM_CSP_HANDLE cspHand
,
442 const UInt8
*plainText
,
444 UInt8
*sig
, // mallocd by caller; RETURNED
445 UInt32 sigLen
, // available
446 UInt32
*actualBytes
) // RETURNED
448 CSSM_CC_HANDLE sigHand
= 0;
454 CASSERT(ctx
!= NULL
);
455 if((privKey
== NULL
) ||
457 (plainText
== NULL
) ||
459 (actualBytes
== NULL
)) {
460 errorLog0("sslRsaRawSign: bad arguments\n");
461 return SSLInternalError
;
465 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
471 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn
);
472 return SSLCryptoError
;
475 ptextData
.Data
= (uint8
*)plainText
;
476 ptextData
.Length
= plainTextLen
;
478 /* caller better get this right, or the SignData will fail */
480 sigData
.Length
= sigLen
;
482 crtn
= CSSM_SignData(sigHand
,
485 CSSM_ALGID_NONE
, // digestAlg
488 stPrintCdsaError("CSSM_SignData", crtn
);
489 serr
= SSLCryptoError
;
492 *actualBytes
= sigData
.Length
;
496 CSSM_DeleteContext(sigHand
);
501 SSLErr
sslRsaRawVerify(
503 const CSSM_KEY
*pubKey
,
504 CSSM_CSP_HANDLE cspHand
,
505 const UInt8
*plainText
,
510 CSSM_CC_HANDLE sigHand
= 0;
516 CASSERT(ctx
!= NULL
);
517 if((pubKey
== NULL
) ||
519 (plainText
== NULL
) ||
521 errorLog0("sslRsaRawVerify: bad arguments\n");
522 return SSLInternalError
;
525 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
531 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn
);
532 return SSLCryptoError
;
535 ptextData
.Data
= (uint8
*)plainText
;
536 ptextData
.Length
= plainTextLen
;
537 sigData
.Data
= (uint8
*)sig
;
538 sigData
.Length
= sigLen
;
540 crtn
= CSSM_VerifyData(sigHand
,
543 CSSM_ALGID_NONE
, // digestAlg
546 stPrintCdsaError("CSSM_VerifyData", crtn
);
547 serr
= SSLCryptoError
;
553 CSSM_DeleteContext(sigHand
);
557 #endif /* SIGN_VFY_VIA_ENCR_DECR */
562 #if APPLE_DOMESTIC_CSP_REQUIRED
565 * Mucho work needed to get this functionality out of export CSP....
568 SSLErr
sslRsaEncrypt(
570 const CSSM_KEY
*pubKey
,
571 CSSM_CSP_HANDLE cspHand
,
572 const UInt8
*plainText
,
574 UInt8
*cipherText
, // mallocd by caller; RETURNED
575 UInt32 cipherTextLen
, // available
576 UInt32
*actualBytes
) // RETURNED
578 CSSM_DATA ctextData
= {0, NULL
};
580 CSSM_DATA remData
= {0, NULL
};
581 CSSM_CC_HANDLE cryptHand
= 0;
582 SSLErr serr
= SSLInternalError
;
584 uint32 bytesMoved
= 0;
585 CSSM_ACCESS_CREDENTIALS creds
;
587 CASSERT(ctx
!= NULL
);
588 CASSERT(actualBytes
!= NULL
);
591 if((pubKey
== NULL
) || (cspHand
== 0)) {
592 errorLog0("sslRsaEncrypt: bad pubKey/cspHand\n");
593 return SSLInternalError
;
596 #if RSA_PUB_KEY_USAGE_HACK
597 ((CSSM_KEY_PTR
)pubKey
)->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
599 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
601 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
608 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
609 return SSLCryptoError
;
611 ptextData
.Data
= (uint8
*)plainText
;
612 ptextData
.Length
= plainTextLen
;
614 if(pubKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
616 * Special case, encrypting with private key (i.e., raw sign). Add
617 * the required context attr.
619 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
621 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
622 modeAttr
.AttributeLength
= sizeof(uint32
);
623 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PRIVATE_KEY
;
624 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
626 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
627 CSSM_DeleteContext(cryptHand
);
628 return SSLCryptoError
;
633 * Have CSP malloc ciphertext
635 crtn
= CSSM_EncryptData(cryptHand
,
642 if(crtn
== CSSM_OK
) {
644 * ciphertext in both ctextData and remData; ensure it'll fit
645 * in caller's buf & copy
647 if(bytesMoved
> cipherTextLen
) {
648 errorLog2("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
649 cipherTextLen
, bytesMoved
);
650 serr
= SSLDataOverflow
;
656 *actualBytes
= bytesMoved
;
658 * Snag valid data from ctextData - its length or bytesMoved,
661 if(ctextData
.Length
> bytesMoved
) {
662 /* everything's in ctext */
663 toMoveCtext
= bytesMoved
;
667 /* must be some in remData too */
668 toMoveCtext
= ctextData
.Length
;
669 toMoveRem
= bytesMoved
- toMoveCtext
; // remainder
672 memmove(cipherText
, ctextData
.Data
, toMoveCtext
);
675 memmove(cipherText
+ toMoveCtext
, remData
.Data
,
682 stPrintCdsaError("CSSM_EncryptData", crtn
);
683 serr
= SSLCryptoError
;
686 CSSM_DeleteContext(cryptHand
);
689 /* free data mallocd by CSP */
690 stFreeCssmData(&ctextData
, CSSM_FALSE
);
691 stFreeCssmData(&remData
, CSSM_FALSE
);
695 SSLErr
sslRsaDecrypt(
697 const CSSM_KEY
*privKey
,
698 CSSM_CSP_HANDLE cspHand
,
699 const UInt8
*cipherText
,
700 UInt32 cipherTextLen
,
701 UInt8
*plainText
, // mallocd by caller; RETURNED
702 UInt32 plainTextLen
, // available
703 UInt32
*actualBytes
) // RETURNED
705 CSSM_DATA ptextData
= {0, NULL
};
707 CSSM_DATA remData
= {0, NULL
};
708 CSSM_CC_HANDLE cryptHand
= 0;
709 SSLErr serr
= SSLInternalError
;
711 uint32 bytesMoved
= 0;
712 CSSM_ACCESS_CREDENTIALS creds
;
714 CASSERT(ctx
!= NULL
);
715 CASSERT(actualBytes
!= NULL
);
718 if((privKey
== NULL
) || (cspHand
== 0)) {
719 errorLog0("sslRsaDecrypt: bad privKey/cspHand\n");
720 return SSLInternalError
;
722 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
723 crtn
= CSSM_CSP_CreateAsymmetricContext(cspHand
,
730 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn
);
731 return SSLCryptoError
;
733 ctextData
.Data
= (uint8
*)cipherText
;
734 ctextData
.Length
= cipherTextLen
;
736 if(privKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
738 * Special case, decrypting with public key (i.e., raw verify). Add
739 * the required context attr.
741 CSSM_CONTEXT_ATTRIBUTE modeAttr
;
743 modeAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
744 modeAttr
.AttributeLength
= sizeof(uint32
);
745 modeAttr
.Attribute
.Uint32
= CSSM_ALGMODE_PUBLIC_KEY
;
746 crtn
= CSSM_UpdateContextAttributes(cryptHand
, 1, &modeAttr
);
748 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn
);
749 CSSM_DeleteContext(cryptHand
);
750 return SSLCryptoError
;
755 * Have CSP malloc plaintext
757 crtn
= CSSM_DecryptData(cryptHand
,
764 if(crtn
== CSSM_OK
) {
766 * plaintext in both ptextData and remData; ensure it'll fit
767 * in caller's buf & copy
769 if(bytesMoved
> plainTextLen
) {
770 errorLog2("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
771 plainTextLen
, bytesMoved
);
772 serr
= SSLDataOverflow
;
778 *actualBytes
= bytesMoved
;
780 * Snag valid data from ptextData - its length or bytesMoved,
783 if(ptextData
.Length
> bytesMoved
) {
784 /* everything's in ptext */
785 toMovePtext
= bytesMoved
;
789 /* must be some in remData too */
790 toMovePtext
= ptextData
.Length
;
791 toMoveRem
= bytesMoved
- toMovePtext
; // remainder
794 memmove(plainText
, ptextData
.Data
, toMovePtext
);
797 memmove(plainText
+ toMovePtext
, remData
.Data
,
804 stPrintCdsaError("CSSM_DecryptData", crtn
);
805 serr
= SSLCryptoError
;
808 CSSM_DeleteContext(cryptHand
);
811 /* free data mallocd by CSP */
812 stFreeCssmData(&ptextData
, CSSM_FALSE
);
813 stFreeCssmData(&remData
, CSSM_FALSE
);
817 #endif /* APPLE_DOMESTIC_CSP_REQUIRED */
820 * Obtain size of key in bytes.
822 UInt32
sslKeyLengthInBytes(const CSSM_KEY
*key
)
824 CASSERT(key
!= NULL
);
825 return (((key
->KeyHeader
.LogicalKeySizeInBits
) + 7) / 8);
829 * Get raw key bits from an RSA public key.
831 SSLErr
sslGetPubKeyBits(
833 const CSSM_KEY
*pubKey
,
834 CSSM_CSP_HANDLE cspHand
,
835 SSLBuffer
*modulus
, // data mallocd and RETURNED
836 SSLBuffer
*exponent
) // data mallocd and RETURNED
839 CSSM_BOOL didWrap
= CSSM_FALSE
;
840 const CSSM_KEYHEADER
*hdr
;
841 CSSM_CC_HANDLE ccHand
;
843 SSLBuffer pubKeyBlob
;
845 CSSM_ACCESS_CREDENTIALS creds
;
847 CASSERT(ctx
!= NULL
);
848 CASSERT(modulus
!= NULL
);
849 CASSERT(exponent
!= NULL
);
850 CASSERT(pubKey
!= NULL
);
852 hdr
= &pubKey
->KeyHeader
;
853 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
854 errorLog1("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr
->KeyClass
);
855 return SSLInternalError
;
857 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
858 errorLog1("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr
->AlgorithmId
);
859 return SSLInternalError
;
863 * Handle possible reference format - I think it should be in
864 * blob form since it came from the DL, but conversion is
867 switch(hdr
->BlobType
) {
868 case CSSM_KEYBLOB_RAW
:
870 CSSM_TO_SSLBUF(&pubKey
->KeyData
, &pubKeyBlob
);
873 case CSSM_KEYBLOB_REFERENCE
:
875 * Convert to a blob via "NULL wrap"; no wrapping key,
878 srtn
= attachToCsp(ctx
);
882 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
883 crtn
= CSSM_CSP_CreateSymmetricContext(ctx
->cspHand
,
893 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn
);
896 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
897 crtn
= CSSM_WrapKey(ccHand
,
900 NULL
, // descriptiveData
902 CSSM_DeleteContext(ccHand
);
904 stPrintCdsaError("CSSM_WrapKey", crtn
);
905 return SSLCryptoError
;
907 hdr
= &wrappedKey
.KeyHeader
;
908 if(hdr
->BlobType
!= CSSM_KEYBLOB_RAW
) {
909 errorLog1("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
911 return SSLCryptoError
;
914 CSSM_TO_SSLBUF(&wrappedKey
.KeyData
, &pubKeyBlob
);
918 errorLog1("sslGetPubKeyBits: bad BlobType (%ld)\n",
920 return SSLInternalError
;
922 } /* switch BlobType */
924 CASSERT(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
925 srtn
= sslDecodeRsaBlob(&pubKeyBlob
, modulus
, exponent
);
927 CSSM_FreeKey(ctx
->cspHand
, NULL
, &wrappedKey
, CSSM_FALSE
);
933 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
934 * Server-initiated key exchange.
936 SSLErr
sslGetPubKeyFromBits(
938 const SSLBuffer
*modulus
,
939 const SSLBuffer
*exponent
,
940 CSSM_KEY_PTR
*pubKey
, // mallocd and RETURNED
941 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
943 CSSM_KEY_PTR key
= NULL
;
946 CSSM_KEYHEADER_PTR hdr
;
947 CSSM_KEY_SIZE keySize
;
950 CASSERT((ctx
!= NULL
) && (modulus
!= NULL
) && (exponent
!= NULL
));
951 CASSERT((pubKey
!= NULL
) && (cspHand
!= NULL
));
956 serr
= attachToCsp(ctx
);
960 serr
= sslEncodeRsaBlob(modulus
, exponent
, &blob
);
965 /* the rest is boilerplate, cook up a good-looking public key */
966 key
= sslMalloc(sizeof(CSSM_KEY
));
970 memset(key
, 0, sizeof(CSSM_KEY
));
971 hdr
= &key
->KeyHeader
;
973 hdr
->HeaderVersion
= CSSM_KEYHEADER_VERSION
;
974 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
975 hdr
->BlobType
= CSSM_KEYBLOB_RAW
;
976 hdr
->AlgorithmId
= CSSM_ALGID_RSA
;
977 hdr
->Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
978 hdr
->KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
979 /* comply with ASA requirements */
980 hdr
->KeyUsage
= CSSM_KEYUSE_VERIFY
;
981 hdr
->KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
982 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
983 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
984 hdr
->WrapAlgorithmId
= CSSM_ALGID_NONE
;
985 hdr
->WrapMode
= CSSM_ALGMODE_NONE
;
987 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
989 SSLBUF_TO_CSSM(&blob
, &key
->KeyData
);
992 * Get keySizeInBits. This also serves to validate the key blob
995 crtn
= CSSM_QueryKeySizeInBits(ctx
->cspHand
, CSSM_INVALID_HANDLE
, key
, &keySize
);
997 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn
);
998 serr
= SSLCryptoError
;
1003 hdr
->LogicalKeySizeInBits
= keySize
.EffectiveKeySizeInBits
;
1005 *cspHand
= ctx
->cspHand
;
1009 /* note this frees the blob */
1010 sslFreeKey(ctx
->cspHand
, &key
, NULL
);
1015 #pragma mark *** Public Certificate Functions ***
1018 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
1019 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
1021 * For now, the returned cspHand is a copy of ctx->cspHand, so it
1022 * doesn't have to be detached later - this may change.
1024 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
1025 * us to tell the CL what CSP to use, we really have no way of knowing
1026 * what is going on here...we return the process-wide (bare) cspHand,
1027 * which is currently always able to deal with this raw public key.
1029 SSLErr
sslPubKeyFromCert(
1031 const SSLBuffer
*derCert
,
1032 CSSM_KEY_PTR
*pubKey
, // RETURNED
1033 CSSM_CSP_HANDLE
*cspHand
) // RETURNED
1039 CASSERT(ctx
!= NULL
);
1040 CASSERT(derCert
!= NULL
);
1041 CASSERT(pubKey
!= NULL
);
1042 CASSERT(cspHand
!= NULL
);
1047 serr
= attachToCl(ctx
);
1051 serr
= attachToCsp(ctx
);
1055 SSLBUF_TO_CSSM(derCert
, &certData
);
1056 crtn
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, &certData
, pubKey
);
1061 *cspHand
= ctx
->cspHand
;
1071 /* for writing root cert to a file */
1073 static OSErr
writeBlob(const CSSM_DATA_PTR blob
,
1074 const char *fileName
)
1079 long count
= blob
->Length
;
1080 int len
= strlen(fileName
);
1085 memmove(&fsp
.name
[1], fileName
, len
);
1087 err
= FSpCreate(&fsp
, 0, 0, 0);
1088 if(err
&& (err
!= dupFNErr
)) {
1089 dprintf1("***FSpCreate() returned %d\n", err
);
1092 err
= FSpOpenDF(&fsp
, fsRdWrPerm
, &fileRef
);
1094 dprintf1("***FSpOpenDF() returned %d\n", err
);
1097 err
= FSWrite(fileRef
, &count
, blob
->Data
);
1099 dprintf1("***FSWrite() returned %d\n", err
);
1102 err
= FSClose(fileRef
);
1104 dprintf1("***FSClose() returned %d\n", err
);
1110 void writeBufBlob(const SSLBuffer
*blob
,
1111 const char *fileName
)
1115 SSLBUF_TO_CSSM(blob
, &d
)
1116 writeBlob(&d
, fileName
);
1121 #if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
1124 * Given a CSSM_CERTGROUP which fails due to CSSM_TP_INVALID_ANCHOR
1125 * (chain verifies to an unknown root):
1127 * -- find the root cert
1128 * -- add it to newRootCertKc if present (else error)
1129 * -- add it to trustedCerts
1130 * -- re-verify certgroup, demand full success
1132 static SSLErr
sslHandleNewRoot(
1134 CSSM_CERTGROUP_PTR certGroup
)
1137 CSSM_DATA_PTR rootCert
;
1142 CASSERT(ctx
!= NULL
);
1143 CASSERT(certGroup
!= NULL
);
1145 if(ctx
->newRootCertKc
== NULL
) {
1146 /* no place to add this; done */
1147 return SSLUnknownRootCert
;
1151 * The root cert "should" be at the end of the chain, but
1152 * let's not assume that. (We are assuming that there is
1153 * only one root in the cert group...)
1155 for(i
=0; i
<certGroup
->NumCerts
; i
++) {
1156 rootCert
= &certGroup
->CertList
[i
];
1157 if(sslVerifyCert(ctx
, rootCert
, rootCert
, ctx
->cspHand
, &expired
)) {
1161 if(i
== certGroup
->NumCerts
) {
1162 /* Huh! no root cert!? We should not have been called! */
1163 errorLog0("sslHandleNewRoot: no root cert!\n");
1164 return SSLInternalError
;
1168 * Add to newRootCertKc. This may well fail due to user interaction.
1170 serr
= sslAddNewRoot(ctx
, rootCert
);
1176 * Just to be sure...reverify the whole cert chain.
1178 brtn
= CSSM_TP_CertGroupVerify(
1183 NULL
, // PolicyIdentifiers
1184 0, // NumberofPolicyIdentifiers
1185 CSSM_TP_STOP_ON_POLICY
,
1187 ctx
->trustedCerts
, // AnchorCerts
1188 ctx
->numTrustedCerts
,
1189 NULL
, // VerifyScope
1194 NULL
); // evidenceSize
1195 if(brtn
== CSSM_FALSE
) {
1196 errorLog0("sslHandleNewRoot: adding new root did not help!\n");
1197 return SSLUnknownRootCert
;
1202 #endif /* ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS */
1204 /* free a CSSM_CERT_GROUP */
1205 static void sslFreeCertGroup(
1206 CSSM_CERTGROUP_PTR certGroup
,
1207 CSSM_BOOL freeCerts
, // free individual cert fields
1208 CSSM_BOOL freeStruct
) // free the overall CSSM_CERTGROUP
1212 if(certGroup
== NULL
) {
1216 /* free the individual cert Data fields */
1217 if(certGroup
->GroupList
.CertList
) {
1219 for(dex
=0; dex
<certGroup
->NumCerts
; dex
++) {
1220 stFreeCssmData(&certGroup
->GroupList
.CertList
[dex
], CSSM_FALSE
);
1223 /* and the array of CSSM_DATAs */
1224 stAppFree(certGroup
->GroupList
.CertList
, NULL
);
1227 stAppFree(certGroup
, NULL
);
1232 * Verify a chain of DER-encoded certs.
1233 * First cert in a chain is root; this must also be present
1234 * in ctx->trustedCerts.
1236 SSLErr
sslVerifyCertChain(
1238 const SSLCertificate
*certChain
)
1241 CSSM_CERTGROUP certGroup
;
1244 SSLCertificate
*c
= (SSLCertificate
*)certChain
;
1246 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
1247 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
1248 CSSM_FIELD policyId
;
1249 CSSM_DL_DB_LIST dbList
;
1250 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
1251 CSSM_APPLE_TP_ACTION_DATA actionData
;
1253 /* FIXME - allowAnyRoot should probably mean "return success" with
1256 numCerts
= SSLGetCertificateChainLength(certChain
);
1262 serr
= attachToAll(ctx
);
1269 * SSLCertificate chain --> CSSM TP cert group.
1270 * TP Cert group has root at the end, opposite of
1271 * SSLCertificate chain.
1273 certGroup
.GroupList
.CertList
=
1274 (CSSM_DATA_PTR
)sslMalloc(numCerts
* sizeof(CSSM_DATA
));
1275 if(certGroup
.GroupList
.CertList
== NULL
) {
1276 return SSLMemoryErr
;
1278 certGroup
.CertGroupType
= CSSM_CERTGROUP_DATA
;
1279 certGroup
.CertType
= CSSM_CERT_X_509v3
;
1280 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
1281 certGroup
.NumCerts
= numCerts
;
1283 memset(certGroup
.GroupList
.CertList
, 0, numCerts
* sizeof(CSSM_DATA
));
1285 for(i
=numCerts
-1; i
>=0; i
--) {
1286 SSLBUF_TO_CSSM(&c
->derCert
, &certGroup
.GroupList
.CertList
[i
]);
1290 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
1291 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
1292 vfyCtx
.Cred
= &authCtx
;
1294 /* CSSM_TP_CALLERAUTH_CONTEXT components */
1296 typedef struct cssm_tp_callerauth_context {
1297 CSSM_TP_POLICYINFO Policy;
1298 CSSM_TIMESTRING VerifyTime;
1299 CSSM_TP_STOP_ON VerificationAbortOn;
1300 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
1301 uint32 NumberOfAnchorCerts;
1302 CSSM_DATA_PTR AnchorCerts;
1303 CSSM_DL_DB_LIST_PTR DBList;
1304 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
1305 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
1308 /* SSL-specific FieldValue */
1309 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
1310 sslOpts
.ServerNameLen
= ctx
->peerDomainNameLen
;
1311 sslOpts
.ServerName
= ctx
->peerDomainName
;
1313 /* TP-wide ActionData */
1314 actionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
1315 actionData
.ActionFlags
= 0x80000000; // @@@ secret root-cert-enable
1316 if(ctx
->allowExpiredCerts
) {
1317 actionData
.ActionFlags
|= CSSM_TP_ACTION_ALLOW_EXPIRED
;
1319 vfyCtx
.ActionData
.Data
= (uint8
*)&actionData
;
1320 vfyCtx
.ActionData
.Length
= sizeof(actionData
);
1322 /* zero or one policy here */
1323 policyId
.FieldOid
= CSSMOID_APPLE_TP_SSL
;
1324 policyId
.FieldValue
.Data
= (uint8
*)&sslOpts
;
1325 policyId
.FieldValue
.Length
= sizeof(sslOpts
);
1326 authCtx
.Policy
.NumberOfPolicyIds
= 1;
1327 authCtx
.Policy
.PolicyIds
= &policyId
;
1329 authCtx
.VerifyTime
= NULL
;
1330 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
1331 authCtx
.CallbackWithVerifiedCert
= NULL
;
1332 authCtx
.NumberOfAnchorCerts
= ctx
->numTrustedCerts
;
1333 authCtx
.AnchorCerts
= ctx
->trustedCerts
;
1334 memset(&dbList
, 0, sizeof(CSSM_DL_DB_LIST
));
1335 authCtx
.DBList
= &dbList
;
1336 authCtx
.CallerCredentials
= NULL
;
1339 * Here we go; hand it over to TP. Note trustedCerts are our
1340 * known good Anchor certs; they're already formatted properly.
1341 * Unlike most other Apple code, we demand full success here,
1342 * implying that the last cert in the chain is indeed an Anchor
1343 * cert. We already know that all of our anchor certs are
1344 * roots, so on successful return, we'll know the incoming
1345 * chain has a root, it verifies to that root, and that that
1346 * root is in trustedCerts.
1348 crtn
= CSSM_TP_CertGroupVerify(ctx
->tpHand
,
1353 NULL
); // no evidence needed
1357 /* get some detailed error info */
1359 case CSSMERR_TP_INVALID_ANCHOR_CERT
:
1360 /* root found but we don't trust it */
1361 if(ctx
->allowAnyRoot
) {
1362 dprintf0("***Warning: accepting unknown root cert\n");
1365 #if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
1366 if(ctx
->newRootCertKc
!= NULL
) {
1367 /* see if user wants to handle new root */
1368 serr
= sslHandleNewRoot(ctx
, &certGroup
);
1371 serr
= SSLUnknownRootCert
;
1374 serr
= SSLUnknownRootCert
;
1375 #endif /* ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS */
1377 case CSSMERR_TP_NOT_TRUSTED
:
1378 /* no root, not even in implicit SSL roots */
1379 if(ctx
->allowAnyRoot
) {
1380 dprintf0("***Warning: accepting unverified cert chain\n");
1383 serr
= SSLNoRootCert
;
1385 case CSSMERR_TP_CERT_EXPIRED
:
1386 assert(!ctx
->allowExpiredCerts
);
1387 serr
= SSLCertExpired
;
1389 case CSSMERR_TP_CERT_NOT_VALID_YET
:
1390 serr
= SSLCertNotYetValid
;
1394 "sslVerifyCertChain: CSSM_TP_CertGroupVerify returned", crtn
);
1395 serr
= X509CertChainInvalidErr
;
1401 * don't free individual certs - caller still owns them
1402 * don't free struct - on stack
1404 sslFreeCertGroup(&certGroup
, CSSM_FALSE
, CSSM_FALSE
);
1410 /* not needed in X */
1413 * Given two certs, verify subjectCert with issuerCert. Returns
1414 * CSSM_TRUE on successful verify.
1415 * Only special case on error is "subject cert expired", indicated by
1416 * *subjectExpired returned as CSSM_TRUE.
1418 CSSM_BOOL
sslVerifyCert(
1420 const CSSM_DATA_PTR subjectCert
,
1421 const CSSM_DATA_PTR issuerCert
,
1422 CSSM_CSP_HANDLE cspHand
, // can verify with issuerCert
1423 CSSM_BOOL
*subjectExpired
) // RETURNED
1425 CSSM_KEY_PTR issuerPubKey
= NULL
;
1426 CSSM_DATA_PTR sigOid
= NULL
;
1427 CSSM_HANDLE ResultsHandle
;
1428 uint32 NumberOfFields
;
1429 CSSM_ERROR_PTR pErr
= NULL
;
1431 uint32
*algId
= NULL
; // mallocd by CL_Passthrough
1432 CSSM_CC_HANDLE ccHand
= 0;
1434 *subjectExpired
= CSSM_FALSE
;
1436 /* ensure connection to CL, TP */
1437 if(attachToCl(ctx
)) {
1440 if(attachToTp(ctx
)) {
1444 /* public key from issuer cert */
1445 issuerPubKey
= CSSM_CL_CertGetKeyInfo(ctx
->clHand
, issuerCert
);
1446 if(issuerPubKey
== NULL
) {
1449 /* subsequent errors to abort: */
1451 /* signature alg from subject cert */
1452 sigOid
= CSSM_CL_CertGetFirstFieldValue(ctx
->clHand
,
1454 &CSSMOID_X509V1SignatureAlgorithm
,
1457 if(sigOid
== NULL
) {
1458 stPrintCdsaError("CSSM_CL_CertGetFirstFieldValue");
1460 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1463 /* cleanup query state */
1464 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1466 /* convert: alg OID to CSSM_ALGID_xxx */
1467 algId
= (uint32
*)CSSM_CL_PassThrough(ctx
->clHand
,
1468 0, // no handle needed
1469 INTEL_X509V3_PASSTHROUGH_ALGOID_TO_ALGID
,
1471 if(*algId
== CSSM_ALGID_NONE
) {
1476 /* set up a sign context with obtained pub key and algorithm */
1477 ccHand
= CSSM_CSP_CreateSignatureContext(cspHand
,
1479 NULL
, // no passphrase
1486 /* go for it - CL takes over from here */
1487 brtn
= CSSM_CL_CertVerify(ctx
->clHand
,
1491 NULL
, // VerifyScope
1493 if(!brtn
&& (CSSM_GetError()->error
== CSSM_CL_CERT_EXPIRED
)) {
1494 *subjectExpired
= CSSM_TRUE
;
1498 if(issuerPubKey
!= NULL
) {
1499 CSSM_Free(issuerPubKey
->KeyData
.Data
);
1500 CSSM_Free(issuerPubKey
);
1502 if(sigOid
!= NULL
) {
1503 CSSM_Free(sigOid
->Data
);
1507 CSSM_DeleteContext(ccHand
);
1514 #endif /* 0 - not needed */
1516 #if ST_KEYCHAIN_ENABLE
1517 /* no cert parsing in this version */
1520 * Given a DER-encoded cert, obtain its DER-encoded subject name.
1522 CSSM_DATA_PTR
sslGetCertSubjectName(
1524 const CSSM_DATA_PTR cert
)
1526 uint32 NumberOfFields
= 0;
1527 CSSM_HANDLE ResultsHandle
= 0;
1528 CSSM_DATA_PTR pEncodedName
= NULL
;
1531 /* ensure connection to CL */
1532 if(attachToCl(ctx
)) {
1535 crtn
= CSSM_CL_CertGetFirstFieldValue(
1538 &CSSMOID_X509V1SubjectName
,
1543 stPrintCdsaError("CertGetFirstFieldValue", crtn
);
1545 CSSM_CL_CertAbortQuery(ctx
->clHand
, ResultsHandle
);
1546 return pEncodedName
;
1548 #endif ST_KEYCHAIN_ENABLE
1550 #if (SSL_DEBUG && ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS)
1551 void verifyTrustedRoots(SSLContext
*ctx
,
1552 CSSM_DATA_PTR certs
,
1559 for(i
=0; i
<numCerts
; i
++) {
1561 if(!sslVerifyCert(ctx
,
1566 sslPanic("Bad trusted cert!\n");