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
;