2  * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * sslCrypto.c - interface between SSL and crypto libraries 
  28 #include "sslCrypto.h" 
  29 #include "sslContext.h" 
  30 #include "sslMemory.h" 
  38 #include <Security/SecTrustPriv.h> 
  39 #include <Security/SecPolicy.h> 
  40 #include <Security/SecCertificate.h> 
  42 #include <AssertMacros.h> 
  43 #include "utilities/SecCFRelease.h" 
  46 #include <Security/SecRSAKey.h> 
  47 #include <Security/SecECKey.h> 
  51  * Get algorithm id for a SSLPubKey object. 
  53 CFIndex 
sslPubKeyGetAlgorithmID(SecKeyRef pubKey
) 
  56         return SecKeyGetAlgorithmID(pubKey
); 
  58         return SecKeyGetAlgorithmId(pubKey
); 
  63  * Get algorithm id for a SSLPrivKey object. 
  65 CFIndex 
sslPrivKeyGetAlgorithmID(SecKeyRef privKey
) 
  68         return SecKeyGetAlgorithmID(privKey
); 
  70         return SecKeyGetAlgorithmId(privKey
); 
  75 OSStatus 
sslCreateCFArrayFromList(const tls_buffer_list_t 
*list
, CFArrayRef 
*cfArray
) 
  78     CFMutableArrayRef array 
= NULL
; 
  79     CFDataRef data 
= NULL
; 
  83     array 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
  87         require((data 
= CFDataCreate(kCFAllocatorDefault
, list
->buffer
.data
, list
->buffer
.length
)), out
); 
  88         CFArrayAppendValue(array
, data
); 
 105         CFArrayRef                              certChain
, 
 106     SecTrustRef             
*pTrust
)    /* RETURNED */ 
 108         OSStatus status 
= errSecAllocate
; 
 109         CFStringRef peerDomainName 
= NULL
; 
 110         CFTypeRef policies 
= NULL
; 
 111         SecTrustRef trust 
= NULL
; 
 112     const char *peerDomainNameData 
= NULL
; 
 113     size_t peerDomainNameLen 
= 0; 
 115     if(ctx
->protocolSide
==kSSLClientSide
) { 
 116         tls_handshake_get_peer_hostname(ctx
->hdsk
, &peerDomainNameData
, &peerDomainNameLen
); 
 119     if (CFArrayGetCount(certChain
) == 0) { 
 120                 status 
= errSSLBadCert
; 
 124     if (peerDomainNameLen 
&& peerDomainNameData
) { 
 125         CFIndex len 
= peerDomainNameLen
; 
 126         if (peerDomainNameData
[len 
- 1] == 0) { 
 128             //secwarning("peerDomainName is zero terminated!"); 
 130         /* @@@ Double check that this is the correct encoding. */ 
 131         require(peerDomainName 
= CFStringCreateWithBytes(kCFAllocatorDefault
, 
 132             (const UInt8 
*)peerDomainNameData
, len
, 
 133             kCFStringEncodingUTF8
, false), errOut
); 
 136     /* If we are the client, our peer certificates must satisfy the 
 137        ssl server policy. */ 
 138     bool use_server_policy 
= (ctx
->protocolSide 
== kSSLClientSide
); 
 139         require(policies 
= SecPolicyCreateSSL(use_server_policy
, peerDomainName
), errOut
); 
 141         require_noerr(status 
= SecTrustCreateWithCertificates(certChain
, policies
, 
 144     /* If we are the client, let's see if we have OCSP responses and SCTs in the TLS handshake */ 
 145     if(ctx
->protocolSide 
== kSSLClientSide
) { 
 146         const tls_buffer_list_t 
*sct_list 
= tls_handshake_get_peer_sct_list(ctx
->hdsk
); 
 147         const tls_buffer 
*ocsp_response 
= tls_handshake_get_peer_ocsp_response(ctx
->hdsk
); 
 150             CFDataRef responseData 
= CFDataCreate(kCFAllocatorDefault
, ocsp_response
->data
, ocsp_response
->length
); 
 151             status 
= SecTrustSetOCSPResponse(trust
, responseData
); 
 152             CFReleaseSafe(responseData
); 
 153             require_noerr(status
, errOut
); 
 157             CFArrayRef sctArray 
= NULL
; 
 158             require_noerr(status 
= sslCreateCFArrayFromList(sct_list
, &sctArray
), errOut
); 
 160             status 
= SecTrustSetSignedCertificateTimestamps(trust
, sctArray
); 
 164             CFReleaseSafe(sctArray
); 
 165             require_noerr(status
, errOut
); 
 169         /* If we have trustedAnchors we set them here. */ 
 170     if (ctx
->trustedCerts
) { 
 171         require_noerr(status 
= SecTrustSetAnchorCertificates(trust
, 
 172             ctx
->trustedCerts
), errOut
); 
 173         require_noerr(status 
= SecTrustSetAnchorCertificatesOnly(trust
, 
 174             ctx
->trustedCertsOnly
), errOut
); 
 177     status 
= errSecSuccess
; 
 180         CFReleaseSafe(peerDomainName
); 
 181         CFReleaseSafe(policies
); 
 188 /* Return the first certificate reference from the supplied array 
 189  * whose data matches the given certificate, or NULL if none match. 
 193 sslGetMatchingCertInArray( 
 194         SecCertificateRef       certRef
, 
 195         CFArrayRef                      certArray
) 
 197         SecCertificateRef matchedCert 
= NULL
; 
 199         if (certRef 
== NULL 
|| certArray 
== NULL
) { 
 203         CFDataRef certData 
= SecCertificateCopyData(certRef
); 
 205                 CFIndex idx
, count 
= CFArrayGetCount(certArray
); 
 206                 for(idx
=0; idx
<count
; idx
++) { 
 207                         SecCertificateRef aCert 
= (SecCertificateRef
)CFArrayGetValueAtIndex(certArray
, idx
); 
 208                         CFDataRef aData 
= SecCertificateCopyData(aCert
); 
 209                         if (aData 
&& CFEqual(aData
, certData
)) { 
 212                         CFReleaseSafe(aData
); 
 216                 CFReleaseSafe(certData
); 
 223  * Verify a chain of DER-encoded certs. 
 225 static OSStatus 
sslVerifyCertChain( 
 227         CFArrayRef                              certChain
) 
 230         SecTrustRef trust 
= NULL
; 
 232     /* renegotiate - start with a new SecTrustRef */ 
 233     CFReleaseNull(ctx
->peerSecTrust
); 
 235     if(certChain
==NULL
) { 
 236         if(ctx
->protocolSide 
== kSSLClientSide
) { 
 237             /* No cert chain is always a trust failure on the server side */ 
 238             status 
= errSSLXCertChainInvalid
; 
 239             sslErrorLog("***Error: NULL server cert chain\n"); 
 241             /* No cert chain on the client side is ok unless using kAlwaysAuthenticate */ 
 242             if(ctx
->clientAuth 
== kAlwaysAuthenticate
) { 
 243                 sslErrorLog("***Error: NULL client cert chain\n"); 
 244                 status 
= errSSLXCertChainInvalid
; 
 252         status 
= sslCreateSecTrust(ctx
, certChain
, &trust
); 
 254         if (!ctx
->enableCertVerify
) { 
 255                 /* trivial case, this is caller's responsibility */ 
 256                 status 
= errSecSuccess
; 
 260         SecTrustResultType secTrustResult
; 
 261         require_noerr(status 
= SecTrustEvaluate(trust
, &secTrustResult
), errOut
); 
 262         switch (secTrustResult
) { 
 263         case kSecTrustResultUnspecified
: 
 264             /* cert chain valid, no special UserTrust assignments */ 
 265         case kSecTrustResultProceed
: 
 266             /* cert chain valid AND user explicitly trusts this */ 
 267             status 
= errSecSuccess
; 
 269         case kSecTrustResultDeny
: 
 270         case kSecTrustResultConfirm
: 
 271         case kSecTrustResultRecoverableTrustFailure
: 
 273             if(ctx
->allowAnyRoot
) { 
 274                 sslErrorLog("***Warning: accepting unverified cert chain\n"); 
 275                 status 
= errSecSuccess
; 
 279                                  * If the caller provided a list of trusted leaf certs, check them here 
 281                                 if(ctx
->trustedLeafCerts
) { 
 282                                         if (sslGetMatchingCertInArray((SecCertificateRef
)CFArrayGetValueAtIndex(certChain
, 0), 
 283                                                                 ctx
->trustedLeafCerts
)) { 
 284                                                 status 
= errSecSuccess
; 
 288                                 status 
= errSSLXCertChainInvalid
; 
 290             /* Do we really need to return things like: 
 292                    errSSLUnknownRootCert 
 294                    errSSLCertNotYetValid 
 295                    errSSLHostNameMismatch 
 296                for our client to see what went wrong, or should we just always 
 298                    errSSLXCertChainInvalid 
 299                when something is wrong? */ 
 304         ctx
->peerSecTrust 
= trust
; 
 309 /* Extract public SecKeyRef from Certificate Chain */ 
 311 int sslCopyPeerPubKey(const SSLCertificate 
*certchain
, 
 316     SecTrustRef trust 
= NULL
; 
 317     const SSLCertificate 
*cert
; 
 318     CFMutableArrayRef certArray 
= NULL
; 
 319     CFDataRef certData 
= NULL
; 
 320     SecCertificateRef cfCert 
= NULL
; 
 322     err 
= errSSLInternal
; 
 324     certArray 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
 327         require((certData 
= CFDataCreate(kCFAllocatorDefault
, cert
->derCert
.data
, cert
->derCert
.length
)), out
); 
 328         require_action((cfCert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
)), out
, err
=errSSLBadCert
); 
 329         CFArrayAppendValue(certArray
, cfCert
); 
 330         CFReleaseNull(cfCert
); 
 331         CFReleaseNull(certData
); 
 335     require_noerr((err
=SecTrustCreateWithCertificates(certArray
, NULL
, &trust
)), out
); 
 336     SecKeyRef key 
= SecTrustCopyPublicKey(trust
); 
 337     require_action(key
, out
, err
=errSSLBadCert
); 
 344     CFReleaseSafe(certData
); 
 345     CFReleaseSafe(cfCert
); 
 346     CFReleaseSafe(trust
); 
 347     CFReleaseSafe(certArray
); 
 352 /* Extract the pubkey from a cert chain, and send it to the tls_handshake context */ 
 353 int tls_set_peer_pubkey(SSLContext 
*ctx
) 
 357     SecKeyRef pubkey 
= NULL
; 
 358     CFDataRef modulus 
= NULL
; 
 359     CFDataRef exponent 
= NULL
; 
 360     CFDataRef ecpubdata 
= NULL
; 
 361     const SSLCertificate 
*certchain 
= NULL
; 
 363     certchain 
= tls_handshake_get_peer_certificates(ctx
->hdsk
); 
 364     CFReleaseNull(ctx
->peerCert
); 
 366     /* If there is no certchain, then we don't need to set the pubkey in coreTLS */ 
 367     /* We should really set it to "NULL" or none, but we need to fix the coreTLS API */ 
 368     /* See: <rdar://problem/19723662> coreTLS: replace tls_handshake_set_peer_rsa_public_key and tls_handshake_set_peer_ec_public_key with a common function */ 
 372     ctx
->peerCert 
= tls_get_peer_certs(certchain
); 
 378         const SSLCertificate 
*tmp 
= certchain
; 
 380             printf("cert%d[] = {", i
); 
 381             for(j
=0; j
<tmp
->derCert
.length
; j
++) { 
 384                 printf("0x%02x, ", tmp
->derCert
.data
[j
]); 
 393     require_noerr((err
=sslCopyPeerPubKey(certchain
, &pubkey
)), errOut
); 
 396         algId 
= SecKeyGetAlgorithmID(pubkey
); 
 398         algId 
= SecKeyGetAlgorithmId(pubkey
); 
 404         case kSecRSAAlgorithmID
: 
 406             require((modulus 
= SecKeyCopyModulus(pubkey
)), errOut
); 
 407             require((exponent 
= SecKeyCopyExponent(pubkey
)), errOut
); 
 412             mod
.data 
= (uint8_t *)CFDataGetBytePtr(modulus
); 
 413             mod
.length 
= CFDataGetLength(modulus
); 
 415             exp
.data 
= (uint8_t *)CFDataGetBytePtr(exponent
); 
 416             exp
.length 
= CFDataGetLength(exponent
); 
 418             err 
= tls_handshake_set_peer_rsa_public_key(ctx
->hdsk
, &mod
, &exp
); 
 421         case kSecECDSAAlgorithmID
: 
 423             tls_named_curve curve 
= SecECKeyGetNamedCurve(pubkey
); 
 424             require((ecpubdata 
= SecECKeyCopyPublicBits(pubkey
)), errOut
); 
 427             pubdata
.data 
= (uint8_t *)CFDataGetBytePtr(ecpubdata
); 
 428             pubdata
.length 
= CFDataGetLength(ecpubdata
); 
 430             err 
= tls_handshake_set_peer_ec_public_key(ctx
->hdsk
, curve
, &pubdata
); 
 439     CFReleaseSafe(pubkey
); 
 440     CFReleaseSafe(modulus
); 
 441     CFReleaseSafe(exponent
); 
 442     CFReleaseSafe(ecpubdata
); 
 447 /* Convert cert in DER format into an CFArray of SecCertificateRef */ 
 449 tls_get_peer_certs(const SSLCertificate 
*certs
) 
 451     const SSLCertificate 
*cert
; 
 453     CFMutableArrayRef certArray 
= NULL
; 
 454     CFDataRef certData 
= NULL
; 
 455     SecCertificateRef cfCert 
= NULL
; 
 457     certArray 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
 458     require(certArray
, out
); 
 461         require((certData 
= CFDataCreate(kCFAllocatorDefault
, cert
->derCert
.data
, cert
->derCert
.length
)), out
); 
 462         require((cfCert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
)), out
); 
 463         CFArrayAppendValue(certArray
, cfCert
); 
 464         CFReleaseNull(cfCert
); 
 465         CFReleaseNull(certData
); 
 472     CFReleaseNull(cfCert
); 
 473     CFReleaseNull(certData
); 
 474     CFReleaseNull(certArray
); 
 479 tls_verify_peer_cert(SSLContext 
*ctx
) 
 484     /* Note: A verification failure here does not cause the function to return an error. 
 485        This will allow the handshake to continue, coreTLS will eventually returns an error, 
 486        after sending the appropriate alert messages, based on the trust value set with the 
 487        call to tls_handshake_set_peer_trust(). In some case a verification failure here is  
 488        normal, for example if there is no cert (eg: PSK and Anon DH ciphersuites) */ 
 490     st 
= sslVerifyCertChain(ctx
, ctx
->peerCert
); 
 491     tls_handshake_trust_t trust
; 
 494             trust 
= tls_handshake_trust_ok
; 
 496         case errSSLUnknownRootCert
: 
 497         case errSSLNoRootCert
: 
 498             trust 
= tls_handshake_trust_unknown_root
; 
 500         case errSSLCertExpired
: 
 501         case errSSLCertNotYetValid
: 
 502             trust 
= tls_handshake_trust_cert_expired
; 
 504         case errSSLXCertChainInvalid
: 
 506             trust 
= tls_handshake_trust_cert_invalid
; 
 510     tls_handshake_set_peer_trust(ctx
->hdsk
, trust
); 
 512     /* Now that trust has been (possibly) evaluated, 
 513        we check if we need to break out of the handshake */ 
 514     if(ctx
->protocolSide 
== kSSLServerSide
) { 
 516          * Schedule return to the caller to verify the client's identity. 
 517          * This will return even if there was no client cert sent. 
 519         if (ctx
->breakOnClientAuth
) { 
 520             err 
= errSSLClientAuthCompleted
; 
 522     } else if(ctx
->peerCert
) { 
 524          * Schedule return to the caller to verify the server's identity. 
 525          * This will only return if a server cert was sent. In other cases 
 526          * such as PSK and AnonDH, we don't want to break out of the handshake. 
 528         if (ctx
->breakOnServerAuth
) { 
 529             err 
= errSSLServerAuthCompleted
; 
 537  * After ciphersuite negotiation is complete, verify that we have 
 538  * the capability of actually performing the selected cipher. 
 539  * Currently we just verify that we have a cert and private signing 
 540  * key, if needed, and that the signing key's algorithm matches the 
 541  * expected key exchange method. 
 543  * This is currently called from FindCipherSpec(), after it sets 
 544  * ctx->selectedCipherSpec to a (supposedly) valid value, and from 
 545  * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only. 
 549 OSStatus 
sslVerifySelectedCipher(SSLContext 
*ctx
) 
 552     if(ctx
->protocolSide 
== kSSLClientSide
) { 
 553         return errSecSuccess
; 
 555 #if SSL_PAC_SERVER_ENABLE 
 556     if((ctx
->masterSecretCallback 
!= NULL
) && 
 557        (ctx
->sessionTicket
.data 
!= NULL
)) { 
 558             /* EAP via PAC resumption; we can do it */ 
 559         return errSecSuccess
; 
 561 #endif  /* SSL_PAC_SERVER_ENABLE */ 
 564     switch (ctx
->selectedCipherSpecParams
.keyExchangeMethod
) { 
 568         case SSL_DH_RSA_EXPORT
: 
 570         case SSL_DHE_RSA_EXPORT
: 
 571             requireAlg 
= kSecRSAAlgorithmID
; 
 574         case SSL_DHE_DSS_EXPORT
: 
 576         case SSL_DH_DSS_EXPORT
: 
 577             requireAlg 
= kSecDSAAlgorithmID
; 
 580         case SSL_DH_anon_EXPORT
: 
 582             requireAlg 
= kSecNullAlgorithmID
; /* no signing key */ 
 585          * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side, 
 586          * we'll need to add some logic here... 
 589         case SSL_ECDHE_ECDSA
: 
 594             requireAlg 
= kSecECDSAAlgorithmID
; 
 599             /* needs update per cipherSpecs.c */ 
 601             sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n"); 
 602             return errSSLInternal
; 
 605     if(requireAlg 
== kSecNullAlgorithmID
) { 
 606         return errSecSuccess
; 
 609     /* private signing key required */ 
 610     if(ctx
->signingPrivKeyRef 
== NULL
) { 
 611         sslErrorLog("sslVerifySelectedCipher: no signing key\n"); 
 612         return errSSLBadConfiguration
; 
 615     /* Check the alg of our signing key. */ 
 616     CFIndex keyAlg 
= sslPrivKeyGetAlgorithmID(ctx
->signingPrivKeyRef
); 
 617     if (requireAlg 
!= keyAlg
) { 
 618         sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n"); 
 619         return errSSLBadConfiguration
; 
 622     return errSecSuccess
;