]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/lib/sslCrypto.c
Security-58286.200.222.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 <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 * Get algorithm id for a SSLPubKey object.
53 */
54 CFIndex sslPubKeyGetAlgorithmID(SecKeyRef pubKey)
55 {
56 return SecKeyGetAlgorithmId(pubKey);
57 }
58
59 /*
60 * Get algorithm id for a SSLPrivKey object.
61 */
62 CFIndex sslPrivKeyGetAlgorithmID(SecKeyRef privKey)
63 {
64 return SecKeyGetAlgorithmId(privKey);
65 }
66
67
68 OSStatus
69 sslCreateSecTrust(
70 SSLContext *ctx,
71 SecTrustRef *pTrust) /* RETURNED */
72 {
73 OSStatus status = errSecAllocate;
74 SecTrustRef trust = NULL;
75
76 require_noerr(status = tls_helper_create_peer_trust(ctx->hdsk, ctx->protocolSide==kSSLServerSide, &trust), errOut);
77
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);
82 }
83
84 status = errSecSuccess;
85
86 errOut:
87 if(status != noErr) {
88 CFReleaseSafe(trust);
89 *pTrust = NULL;
90 } else {
91 *pTrust = trust;
92 }
93
94 return status;
95 }
96
97 #if !TARGET_OS_IPHONE
98 /* Return the first certificate reference from the supplied array
99 * whose data matches the given certificate, or NULL if none match.
100 */
101 static
102 SecCertificateRef
103 sslGetMatchingCertInArray(
104 SecCertificateRef certRef,
105 CFArrayRef certArray)
106 {
107 SecCertificateRef matchedCert = NULL;
108
109 if (certRef == NULL || certArray == NULL) {
110 return NULL;
111 }
112
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;
118 break;
119 }
120 }
121
122 return matchedCert;
123 }
124 #endif
125
126 /*
127 * Verify a chain of DER-encoded certs.
128 */
129 static OSStatus sslVerifyCertChain(
130 SSLContext *ctx)
131 {
132 OSStatus status;
133 SecTrustRef trust = NULL;
134
135 /* renegotiate - start with a new SecTrustRef */
136 CFReleaseNull(ctx->peerSecTrust);
137
138 /* on failure, we always return trust==NULL, so we don't check the returned status here */
139 sslCreateSecTrust(ctx, &trust);
140
141 if(trust==NULL) {
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");
146 } else {
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;
151 } else {
152 status = noErr;
153 }
154 }
155 goto errOut;
156 }
157
158
159 if (!ctx->enableCertVerify) {
160 /* trivial case, this is caller's responsibility */
161 status = errSecSuccess;
162 goto errOut;
163 }
164
165 SecTrustResultType secTrustResult;
166 require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
167
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;
174 break;
175 case kSecTrustResultDeny:
176 case kSecTrustResultRecoverableTrustFailure:
177 default:
178 if(ctx->allowAnyRoot) {
179 sslErrorLog("***Warning: accepting unverified cert chain\n");
180 status = errSecSuccess;
181 }
182 else {
183 #if !TARGET_OS_IPHONE
184 /*
185 * If the caller provided a list of trusted leaf certs, check them here
186 */
187 if(ctx->trustedLeafCerts) {
188 if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust, 0),
189 ctx->trustedLeafCerts)) {
190 status = errSecSuccess;
191 goto errOut;
192 }
193 }
194 #endif
195 status = errSSLXCertChainInvalid;
196 }
197 /* Do we really need to return things like:
198 errSSLNoRootCert
199 errSSLUnknownRootCert
200 errSSLCertExpired
201 errSSLCertNotYetValid
202 errSSLHostNameMismatch
203 for our client to see what went wrong, or should we just always
204 return
205 errSSLXCertChainInvalid
206 when something is wrong? */
207 break;
208 }
209
210 errOut:
211 ctx->peerSecTrust = trust;
212
213 return status;
214 }
215
216 /* Convert cert in DER format into an CFArray of SecCertificateRef */
217 CFArrayRef
218 tls_get_peer_certs(const SSLCertificate *certs)
219 {
220 const SSLCertificate *cert;
221
222 CFMutableArrayRef certArray = NULL;
223 CFDataRef certData = NULL;
224 SecCertificateRef cfCert = NULL;
225
226 certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
227 require(certArray, out);
228 cert = certs;
229 while(cert) {
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);
235 cert=cert->next;
236 }
237
238 return certArray;
239
240 out:
241 CFReleaseNull(cfCert);
242 CFReleaseNull(certData);
243 CFReleaseNull(certArray);
244 return NULL;
245 }
246
247 int
248 tls_verify_peer_cert(SSLContext *ctx)
249 {
250 int err = 0;
251 OSStatus st;
252
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) */
258
259 st = sslVerifyCertChain(ctx);
260 tls_handshake_trust_t trust;
261 switch (st) {
262 case errSecSuccess:
263 trust = tls_handshake_trust_ok;
264 break;
265 case errSSLUnknownRootCert:
266 case errSSLNoRootCert:
267 trust = tls_handshake_trust_unknown_root;
268 break;
269 case errSSLCertExpired:
270 case errSSLCertNotYetValid:
271 trust = tls_handshake_trust_cert_expired;
272 break;
273 case errSSLXCertChainInvalid:
274 default:
275 trust = tls_handshake_trust_cert_invalid;
276 break;
277 }
278
279 tls_handshake_set_peer_trust(ctx->hdsk, trust);
280
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) {
284 /*
285 * Schedule return to the caller to verify the client's identity.
286 * This will return even if there was no client cert sent.
287 */
288 if (ctx->breakOnClientAuth) {
289 err = errSSLClientAuthCompleted;
290 }
291 } else if(ctx->peerSecTrust) {
292 /*
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.
296 */
297 if (ctx->breakOnServerAuth) {
298 err = errSSLServerAuthCompleted;
299 }
300 }
301
302 return err;
303 }
304
305 /*
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.
311 *
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.
315 */
316
317 #if 0
318 OSStatus sslVerifySelectedCipher(SSLContext *ctx)
319 {
320
321 if(ctx->protocolSide == kSSLClientSide) {
322 return errSecSuccess;
323 }
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;
329 }
330 #endif /* SSL_PAC_SERVER_ENABLE */
331
332 CFIndex requireAlg;
333 switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
334 case SSL_RSA:
335 case SSL_RSA_EXPORT:
336 case SSL_DH_RSA:
337 case SSL_DH_RSA_EXPORT:
338 case SSL_DHE_RSA:
339 case SSL_DHE_RSA_EXPORT:
340 requireAlg = kSecRSAAlgorithmID;
341 break;
342 case SSL_DHE_DSS:
343 case SSL_DHE_DSS_EXPORT:
344 case SSL_DH_DSS:
345 case SSL_DH_DSS_EXPORT:
346 requireAlg = kSecDSAAlgorithmID;
347 break;
348 case SSL_DH_anon:
349 case SSL_DH_anon_EXPORT:
350 case TLS_PSK:
351 requireAlg = kSecNullAlgorithmID; /* no signing key */
352 break;
353 /*
354 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
355 * we'll need to add some logic here...
356 */
357 #if SSL_ECDSA_SERVER
358 case SSL_ECDHE_ECDSA:
359 case SSL_ECDHE_RSA:
360 case SSL_ECDH_ECDSA:
361 case SSL_ECDH_RSA:
362 case SSL_ECDH_anon:
363 requireAlg = kSecECDSAAlgorithmID;
364 break;
365 #endif
366
367 default:
368 /* needs update per cipherSpecs.c */
369 assert(0);
370 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
371 return errSSLInternal;
372 }
373
374 if(requireAlg == kSecNullAlgorithmID) {
375 return errSecSuccess;
376 }
377
378 /* private signing key required */
379 if(ctx->signingPrivKeyRef == NULL) {
380 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
381 return errSSLBadConfiguration;
382 }
383
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;
389 }
390
391 return errSecSuccess;
392 }
393
394 #endif