]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/lib/sslCrypto.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / lib / sslCrypto.c
1 /*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * sslCrypto.c - interface between SSL and crypto libraries
26 */
27
28 #include "sslCrypto.h"
29 #include "sslContext.h"
30 #include "sslMemory.h"
31 #include "sslDebug.h"
32
33 #include <string.h>
34 #include <stdlib.h>
35 #include "utilities/simulatecrash_assert.h"
36
37 #include <Security/SecTrustPriv.h>
38 #include <Security/SecPolicy.h>
39 #include <Security/SecCertificate.h>
40
41 #include <AssertMacros.h>
42 #include "utilities/SecCFRelease.h"
43
44 #if TARGET_OS_IPHONE
45 #include <Security/SecRSAKey.h>
46 #include <Security/SecECKey.h>
47 #endif
48
49 #include <tls_helpers.h>
50
51
52 OSStatus
53 sslCreateSecTrust(
54 SSLContext *ctx,
55 SecTrustRef *pTrust) /* RETURNED */
56 {
57 OSStatus status = errSecAllocate;
58 SecTrustRef trust = NULL;
59
60 require_noerr(status = tls_helper_create_peer_trust(ctx->hdsk, ctx->protocolSide==kSSLServerSide, &trust), errOut);
61
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);
66 }
67
68 status = errSecSuccess;
69
70 errOut:
71 if(status != noErr) {
72 CFReleaseSafe(trust);
73 *pTrust = NULL;
74 } else {
75 *pTrust = trust;
76 }
77
78 return status;
79 }
80
81 #if !TARGET_OS_IPHONE
82 /* Return the first certificate reference from the supplied array
83 * whose data matches the given certificate, or NULL if none match.
84 */
85 static
86 SecCertificateRef
87 sslGetMatchingCertInArray(
88 SecCertificateRef certRef,
89 CFArrayRef certArray)
90 {
91 SecCertificateRef matchedCert = NULL;
92
93 if (certRef == NULL || certArray == NULL) {
94 return NULL;
95 }
96
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;
102 break;
103 }
104 }
105
106 return matchedCert;
107 }
108 #endif
109
110 /*
111 * Verify a chain of DER-encoded certs.
112 */
113 static OSStatus sslVerifyCertChain(
114 SSLContext *ctx)
115 {
116 OSStatus status;
117 SecTrustRef trust = NULL;
118
119 /* renegotiate - start with a new SecTrustRef */
120 CFReleaseNull(ctx->peerSecTrust);
121
122 /* on failure, we always return trust==NULL, so we don't check the returned status here */
123 sslCreateSecTrust(ctx, &trust);
124
125 if(trust==NULL) {
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");
130 } else {
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;
135 } else {
136 status = noErr;
137 }
138 }
139 goto errOut;
140 }
141
142
143 if (!ctx->enableCertVerify) {
144 /* trivial case, this is caller's responsibility */
145 status = errSecSuccess;
146 goto errOut;
147 }
148
149 SecTrustResultType secTrustResult;
150 require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
151
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;
158 break;
159 case kSecTrustResultDeny:
160 case kSecTrustResultRecoverableTrustFailure:
161 default:
162 if(ctx->allowAnyRoot) {
163 sslErrorLog("***Warning: accepting unverified cert chain\n");
164 status = errSecSuccess;
165 }
166 else {
167 #if !TARGET_OS_IPHONE
168 /*
169 * If the caller provided a list of trusted leaf certs, check them here
170 */
171 if(ctx->trustedLeafCerts) {
172 if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust, 0),
173 ctx->trustedLeafCerts)) {
174 status = errSecSuccess;
175 goto errOut;
176 }
177 }
178 #endif
179 status = errSSLXCertChainInvalid;
180 }
181 /* Do we really need to return things like:
182 errSSLNoRootCert
183 errSSLUnknownRootCert
184 errSSLCertExpired
185 errSSLCertNotYetValid
186 errSSLHostNameMismatch
187 for our client to see what went wrong, or should we just always
188 return
189 errSSLXCertChainInvalid
190 when something is wrong? */
191 break;
192 }
193
194 errOut:
195 ctx->peerSecTrust = trust;
196
197 return status;
198 }
199
200 int
201 tls_verify_peer_cert(SSLContext *ctx)
202 {
203 int err = 0;
204 OSStatus st;
205
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) */
211
212 st = sslVerifyCertChain(ctx);
213 tls_handshake_trust_t trust;
214 switch (st) {
215 case errSecSuccess:
216 trust = tls_handshake_trust_ok;
217 break;
218 case errSSLUnknownRootCert:
219 case errSSLNoRootCert:
220 trust = tls_handshake_trust_unknown_root;
221 break;
222 case errSSLCertExpired:
223 case errSSLCertNotYetValid:
224 trust = tls_handshake_trust_cert_expired;
225 break;
226 case errSSLXCertChainInvalid:
227 default:
228 trust = tls_handshake_trust_cert_invalid;
229 break;
230 }
231
232 tls_handshake_set_peer_trust(ctx->hdsk, trust);
233
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) {
237 /*
238 * Schedule return to the caller to verify the client's identity.
239 * This will return even if there was no client cert sent.
240 */
241 if (ctx->breakOnClientAuth) {
242 err = errSSLClientAuthCompleted;
243 }
244 } else if(ctx->peerSecTrust) {
245 /*
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.
249 */
250 if (ctx->breakOnServerAuth) {
251 err = errSSLServerAuthCompleted;
252 }
253 }
254
255 return err;
256 }
257
258 /*
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.
264 *
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.
268 */
269
270 #if 0
271 OSStatus sslVerifySelectedCipher(SSLContext *ctx)
272 {
273
274 if(ctx->protocolSide == kSSLClientSide) {
275 return errSecSuccess;
276 }
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;
282 }
283 #endif /* SSL_PAC_SERVER_ENABLE */
284
285 CFIndex requireAlg;
286 switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
287 case SSL_RSA:
288 case SSL_RSA_EXPORT:
289 case SSL_DH_RSA:
290 case SSL_DH_RSA_EXPORT:
291 case SSL_DHE_RSA:
292 case SSL_DHE_RSA_EXPORT:
293 requireAlg = kSecRSAAlgorithmID;
294 break;
295 case SSL_DHE_DSS:
296 case SSL_DHE_DSS_EXPORT:
297 case SSL_DH_DSS:
298 case SSL_DH_DSS_EXPORT:
299 requireAlg = kSecDSAAlgorithmID;
300 break;
301 case SSL_DH_anon:
302 case SSL_DH_anon_EXPORT:
303 case TLS_PSK:
304 requireAlg = kSecNullAlgorithmID; /* no signing key */
305 break;
306 /*
307 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
308 * we'll need to add some logic here...
309 */
310 #if SSL_ECDSA_SERVER
311 case SSL_ECDHE_ECDSA:
312 case SSL_ECDHE_RSA:
313 case SSL_ECDH_ECDSA:
314 case SSL_ECDH_RSA:
315 case SSL_ECDH_anon:
316 requireAlg = kSecECDSAAlgorithmID;
317 break;
318 #endif
319
320 default:
321 /* needs update per cipherSpecs.c */
322 assert(0);
323 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
324 return errSSLInternal;
325 }
326
327 if(requireAlg == kSecNullAlgorithmID) {
328 return errSecSuccess;
329 }
330
331 /* private signing key required */
332 if(ctx->signingPrivKeyRef == NULL) {
333 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
334 return errSSLBadConfiguration;
335 }
336
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;
342 }
343
344 return errSecSuccess;
345 }
346
347 #endif