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"
35 #include "utilities/simulatecrash_assert.h"
37 #include <Security/SecTrustPriv.h>
38 #include <Security/SecPolicy.h>
39 #include <Security/SecCertificate.h>
41 #include <AssertMacros.h>
42 #include "utilities/SecCFRelease.h"
45 #include <Security/SecRSAKey.h>
46 #include <Security/SecECKey.h>
49 #include <tls_helpers.h>
55 SecTrustRef
*pTrust
) /* RETURNED */
57 OSStatus status
= errSecAllocate
;
58 SecTrustRef trust
= NULL
;
60 require_noerr(status
= tls_helper_create_peer_trust(ctx
->hdsk
, ctx
->protocolSide
==kSSLServerSide
, &trust
), errOut
);
62 /* If we have trustedAnchors we set them here. */
63 if (trust
&& ctx
->trustedCerts
) {
64 require_noerr(status
= SecTrustSetAnchorCertificates(trust
, ctx
->trustedCerts
), errOut
);
65 require_noerr(status
= SecTrustSetAnchorCertificatesOnly(trust
, ctx
->trustedCertsOnly
), errOut
);
68 status
= errSecSuccess
;
82 /* Return the first certificate reference from the supplied array
83 * whose data matches the given certificate, or NULL if none match.
87 sslGetMatchingCertInArray(
88 SecCertificateRef certRef
,
91 SecCertificateRef matchedCert
= NULL
;
93 if (certRef
== NULL
|| certArray
== NULL
) {
97 CFIndex idx
, count
= CFArrayGetCount(certArray
);
98 for (idx
= 0; idx
< count
; idx
++) {
99 SecCertificateRef otherCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certArray
, idx
);
100 if (CFEqual(certRef
, otherCert
)) {
101 matchedCert
= otherCert
;
111 * Verify a chain of DER-encoded certs.
113 static OSStatus
sslVerifyCertChain(
117 SecTrustRef trust
= NULL
;
119 /* renegotiate - start with a new SecTrustRef */
120 CFReleaseNull(ctx
->peerSecTrust
);
122 /* on failure, we always return trust==NULL, so we don't check the returned status here */
123 sslCreateSecTrust(ctx
, &trust
);
126 if(ctx
->protocolSide
== kSSLClientSide
) {
127 /* No cert chain is always a trust failure on the server side */
128 status
= errSSLXCertChainInvalid
;
129 sslErrorLog("***Error: NULL server cert chain\n");
131 /* No cert chain on the client side is ok unless using kAlwaysAuthenticate */
132 if(ctx
->clientAuth
== kAlwaysAuthenticate
) {
133 sslErrorLog("***Error: NULL client cert chain\n");
134 status
= errSSLXCertChainInvalid
;
143 if (!ctx
->enableCertVerify
) {
144 /* trivial case, this is caller's responsibility */
145 status
= errSecSuccess
;
149 SecTrustResultType secTrustResult
;
150 require_noerr(status
= SecTrustEvaluate(trust
, &secTrustResult
), errOut
);
152 switch (secTrustResult
) {
153 case kSecTrustResultUnspecified
:
154 /* cert chain valid, no special UserTrust assignments */
155 case kSecTrustResultProceed
:
156 /* cert chain valid AND user explicitly trusts this */
157 status
= errSecSuccess
;
159 case kSecTrustResultDeny
:
160 case kSecTrustResultRecoverableTrustFailure
:
162 if(ctx
->allowAnyRoot
) {
163 sslErrorLog("***Warning: accepting unverified cert chain\n");
164 status
= errSecSuccess
;
167 #if !TARGET_OS_IPHONE
169 * If the caller provided a list of trusted leaf certs, check them here
171 if(ctx
->trustedLeafCerts
) {
172 if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust
, 0),
173 ctx
->trustedLeafCerts
)) {
174 status
= errSecSuccess
;
179 status
= errSSLXCertChainInvalid
;
181 /* Do we really need to return things like:
183 errSSLUnknownRootCert
185 errSSLCertNotYetValid
186 errSSLHostNameMismatch
187 for our client to see what went wrong, or should we just always
189 errSSLXCertChainInvalid
190 when something is wrong? */
195 ctx
->peerSecTrust
= trust
;
201 tls_verify_peer_cert(SSLContext
*ctx
)
206 /* Note: A verification failure here does not cause the function to return an error.
207 This will allow the handshake to continue, coreTLS will eventually returns an error,
208 after sending the appropriate alert messages, based on the trust value set with the
209 call to tls_handshake_set_peer_trust(). In some case a verification failure here is
210 normal, for example if there is no cert (eg: PSK and Anon DH ciphersuites) */
212 st
= sslVerifyCertChain(ctx
);
213 tls_handshake_trust_t trust
;
216 trust
= tls_handshake_trust_ok
;
218 case errSSLUnknownRootCert
:
219 case errSSLNoRootCert
:
220 trust
= tls_handshake_trust_unknown_root
;
222 case errSSLCertExpired
:
223 case errSSLCertNotYetValid
:
224 trust
= tls_handshake_trust_cert_expired
;
226 case errSSLXCertChainInvalid
:
228 trust
= tls_handshake_trust_cert_invalid
;
232 tls_handshake_set_peer_trust(ctx
->hdsk
, trust
);
234 /* Now that trust has been (possibly) evaluated,
235 we check if we need to break out of the handshake */
236 if(ctx
->protocolSide
== kSSLServerSide
) {
238 * Schedule return to the caller to verify the client's identity.
239 * This will return even if there was no client cert sent.
241 if (ctx
->breakOnClientAuth
) {
242 err
= errSSLClientAuthCompleted
;
244 } else if(ctx
->peerSecTrust
) {
246 * Schedule return to the caller to verify the server's identity.
247 * This will only return if a server cert was sent. In other cases
248 * such as PSK and AnonDH, we don't want to break out of the handshake.
250 if (ctx
->breakOnServerAuth
) {
251 err
= errSSLServerAuthCompleted
;
259 * After ciphersuite negotiation is complete, verify that we have
260 * the capability of actually performing the selected cipher.
261 * Currently we just verify that we have a cert and private signing
262 * key, if needed, and that the signing key's algorithm matches the
263 * expected key exchange method.
265 * This is currently called from FindCipherSpec(), after it sets
266 * ctx->selectedCipherSpec to a (supposedly) valid value, and from
267 * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only.
271 OSStatus
sslVerifySelectedCipher(SSLContext
*ctx
)
274 if(ctx
->protocolSide
== kSSLClientSide
) {
275 return errSecSuccess
;
277 #if SSL_PAC_SERVER_ENABLE
278 if((ctx
->masterSecretCallback
!= NULL
) &&
279 (ctx
->sessionTicket
.data
!= NULL
)) {
280 /* EAP via PAC resumption; we can do it */
281 return errSecSuccess
;
283 #endif /* SSL_PAC_SERVER_ENABLE */
286 switch (ctx
->selectedCipherSpecParams
.keyExchangeMethod
) {
290 case SSL_DH_RSA_EXPORT
:
292 case SSL_DHE_RSA_EXPORT
:
293 requireAlg
= kSecRSAAlgorithmID
;
296 case SSL_DHE_DSS_EXPORT
:
298 case SSL_DH_DSS_EXPORT
:
299 requireAlg
= kSecDSAAlgorithmID
;
302 case SSL_DH_anon_EXPORT
:
304 requireAlg
= kSecNullAlgorithmID
; /* no signing key */
307 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
308 * we'll need to add some logic here...
311 case SSL_ECDHE_ECDSA
:
316 requireAlg
= kSecECDSAAlgorithmID
;
321 /* needs update per cipherSpecs.c */
323 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
324 return errSSLInternal
;
327 if(requireAlg
== kSecNullAlgorithmID
) {
328 return errSecSuccess
;
331 /* private signing key required */
332 if(ctx
->signingPrivKeyRef
== NULL
) {
333 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
334 return errSSLBadConfiguration
;
337 /* Check the alg of our signing key. */
338 CFIndex keyAlg
= SecKeyGetAlgorithmId(ctx
->signingPrivKeyRef
);
339 if (requireAlg
!= keyAlg
) {
340 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
341 return errSSLBadConfiguration
;
344 return errSecSuccess
;