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"
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>
52 * Get algorithm id for a SSLPubKey object.
54 CFIndex
sslPubKeyGetAlgorithmID(SecKeyRef pubKey
)
56 return SecKeyGetAlgorithmId(pubKey
);
60 * Get algorithm id for a SSLPrivKey object.
62 CFIndex
sslPrivKeyGetAlgorithmID(SecKeyRef privKey
)
64 return SecKeyGetAlgorithmId(privKey
);
71 SecTrustRef
*pTrust
) /* RETURNED */
73 OSStatus status
= errSecAllocate
;
74 SecTrustRef trust
= NULL
;
76 require_noerr(status
= tls_helper_create_peer_trust(ctx
->hdsk
, ctx
->protocolSide
==kSSLServerSide
, &trust
), errOut
);
78 /* If we have trustedAnchors we set them here. */
79 if (trust
&& ctx
->trustedCerts
) {
80 require_noerr(status
= SecTrustSetAnchorCertificates(trust
, ctx
->trustedCerts
), errOut
);
81 require_noerr(status
= SecTrustSetAnchorCertificatesOnly(trust
, ctx
->trustedCertsOnly
), errOut
);
84 status
= errSecSuccess
;
98 /* Return the first certificate reference from the supplied array
99 * whose data matches the given certificate, or NULL if none match.
103 sslGetMatchingCertInArray(
104 SecCertificateRef certRef
,
105 CFArrayRef certArray
)
107 SecCertificateRef matchedCert
= NULL
;
109 if (certRef
== NULL
|| certArray
== NULL
) {
113 CFIndex idx
, count
= CFArrayGetCount(certArray
);
114 for (idx
= 0; idx
< count
; idx
++) {
115 SecCertificateRef otherCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certArray
, idx
);
116 if (CFEqual(certRef
, otherCert
)) {
117 matchedCert
= otherCert
;
127 * Verify a chain of DER-encoded certs.
129 static OSStatus
sslVerifyCertChain(
133 SecTrustRef trust
= NULL
;
135 /* renegotiate - start with a new SecTrustRef */
136 CFReleaseNull(ctx
->peerSecTrust
);
138 /* on failure, we always return trust==NULL, so we don't check the returned status here */
139 sslCreateSecTrust(ctx
, &trust
);
142 if(ctx
->protocolSide
== kSSLClientSide
) {
143 /* No cert chain is always a trust failure on the server side */
144 status
= errSSLXCertChainInvalid
;
145 sslErrorLog("***Error: NULL server cert chain\n");
147 /* No cert chain on the client side is ok unless using kAlwaysAuthenticate */
148 if(ctx
->clientAuth
== kAlwaysAuthenticate
) {
149 sslErrorLog("***Error: NULL client cert chain\n");
150 status
= errSSLXCertChainInvalid
;
159 if (!ctx
->enableCertVerify
) {
160 /* trivial case, this is caller's responsibility */
161 status
= errSecSuccess
;
165 SecTrustResultType secTrustResult
;
166 require_noerr(status
= SecTrustEvaluate(trust
, &secTrustResult
), errOut
);
168 switch (secTrustResult
) {
169 case kSecTrustResultUnspecified
:
170 /* cert chain valid, no special UserTrust assignments */
171 case kSecTrustResultProceed
:
172 /* cert chain valid AND user explicitly trusts this */
173 status
= errSecSuccess
;
175 case kSecTrustResultDeny
:
176 case kSecTrustResultRecoverableTrustFailure
:
178 if(ctx
->allowAnyRoot
) {
179 sslErrorLog("***Warning: accepting unverified cert chain\n");
180 status
= errSecSuccess
;
183 #if !TARGET_OS_IPHONE
185 * If the caller provided a list of trusted leaf certs, check them here
187 if(ctx
->trustedLeafCerts
) {
188 if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust
, 0),
189 ctx
->trustedLeafCerts
)) {
190 status
= errSecSuccess
;
195 status
= errSSLXCertChainInvalid
;
197 /* Do we really need to return things like:
199 errSSLUnknownRootCert
201 errSSLCertNotYetValid
202 errSSLHostNameMismatch
203 for our client to see what went wrong, or should we just always
205 errSSLXCertChainInvalid
206 when something is wrong? */
211 ctx
->peerSecTrust
= trust
;
216 /* Convert cert in DER format into an CFArray of SecCertificateRef */
218 tls_get_peer_certs(const SSLCertificate
*certs
)
220 const SSLCertificate
*cert
;
222 CFMutableArrayRef certArray
= NULL
;
223 CFDataRef certData
= NULL
;
224 SecCertificateRef cfCert
= NULL
;
226 certArray
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
227 require(certArray
, out
);
230 require((certData
= CFDataCreate(kCFAllocatorDefault
, cert
->derCert
.data
, cert
->derCert
.length
)), out
);
231 require((cfCert
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
)), out
);
232 CFArrayAppendValue(certArray
, cfCert
);
233 CFReleaseNull(cfCert
);
234 CFReleaseNull(certData
);
241 CFReleaseNull(cfCert
);
242 CFReleaseNull(certData
);
243 CFReleaseNull(certArray
);
248 tls_verify_peer_cert(SSLContext
*ctx
)
253 /* Note: A verification failure here does not cause the function to return an error.
254 This will allow the handshake to continue, coreTLS will eventually returns an error,
255 after sending the appropriate alert messages, based on the trust value set with the
256 call to tls_handshake_set_peer_trust(). In some case a verification failure here is
257 normal, for example if there is no cert (eg: PSK and Anon DH ciphersuites) */
259 st
= sslVerifyCertChain(ctx
);
260 tls_handshake_trust_t trust
;
263 trust
= tls_handshake_trust_ok
;
265 case errSSLUnknownRootCert
:
266 case errSSLNoRootCert
:
267 trust
= tls_handshake_trust_unknown_root
;
269 case errSSLCertExpired
:
270 case errSSLCertNotYetValid
:
271 trust
= tls_handshake_trust_cert_expired
;
273 case errSSLXCertChainInvalid
:
275 trust
= tls_handshake_trust_cert_invalid
;
279 tls_handshake_set_peer_trust(ctx
->hdsk
, trust
);
281 /* Now that trust has been (possibly) evaluated,
282 we check if we need to break out of the handshake */
283 if(ctx
->protocolSide
== kSSLServerSide
) {
285 * Schedule return to the caller to verify the client's identity.
286 * This will return even if there was no client cert sent.
288 if (ctx
->breakOnClientAuth
) {
289 err
= errSSLClientAuthCompleted
;
291 } else if(ctx
->peerSecTrust
) {
293 * Schedule return to the caller to verify the server's identity.
294 * This will only return if a server cert was sent. In other cases
295 * such as PSK and AnonDH, we don't want to break out of the handshake.
297 if (ctx
->breakOnServerAuth
) {
298 err
= errSSLServerAuthCompleted
;
306 * After ciphersuite negotiation is complete, verify that we have
307 * the capability of actually performing the selected cipher.
308 * Currently we just verify that we have a cert and private signing
309 * key, if needed, and that the signing key's algorithm matches the
310 * expected key exchange method.
312 * This is currently called from FindCipherSpec(), after it sets
313 * ctx->selectedCipherSpec to a (supposedly) valid value, and from
314 * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only.
318 OSStatus
sslVerifySelectedCipher(SSLContext
*ctx
)
321 if(ctx
->protocolSide
== kSSLClientSide
) {
322 return errSecSuccess
;
324 #if SSL_PAC_SERVER_ENABLE
325 if((ctx
->masterSecretCallback
!= NULL
) &&
326 (ctx
->sessionTicket
.data
!= NULL
)) {
327 /* EAP via PAC resumption; we can do it */
328 return errSecSuccess
;
330 #endif /* SSL_PAC_SERVER_ENABLE */
333 switch (ctx
->selectedCipherSpecParams
.keyExchangeMethod
) {
337 case SSL_DH_RSA_EXPORT
:
339 case SSL_DHE_RSA_EXPORT
:
340 requireAlg
= kSecRSAAlgorithmID
;
343 case SSL_DHE_DSS_EXPORT
:
345 case SSL_DH_DSS_EXPORT
:
346 requireAlg
= kSecDSAAlgorithmID
;
349 case SSL_DH_anon_EXPORT
:
351 requireAlg
= kSecNullAlgorithmID
; /* no signing key */
354 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
355 * we'll need to add some logic here...
358 case SSL_ECDHE_ECDSA
:
363 requireAlg
= kSecECDSAAlgorithmID
;
368 /* needs update per cipherSpecs.c */
370 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
371 return errSSLInternal
;
374 if(requireAlg
== kSecNullAlgorithmID
) {
375 return errSecSuccess
;
378 /* private signing key required */
379 if(ctx
->signingPrivKeyRef
== NULL
) {
380 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
381 return errSSLBadConfiguration
;
384 /* Check the alg of our signing key. */
385 CFIndex keyAlg
= sslPrivKeyGetAlgorithmID(ctx
->signingPrivKeyRef
);
386 if (requireAlg
!= keyAlg
) {
387 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
388 return errSSLBadConfiguration
;
391 return errSecSuccess
;