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
;