]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/lib/sslCrypto.c
Security-57740.20.22.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 #if TARGET_OS_IPHONE
57 return SecKeyGetAlgorithmID(pubKey);
58 #else
59 return SecKeyGetAlgorithmId(pubKey);
60 #endif
61 }
62
63 /*
64 * Get algorithm id for a SSLPrivKey object.
65 */
66 CFIndex sslPrivKeyGetAlgorithmID(SecKeyRef privKey)
67 {
68 #if TARGET_OS_IPHONE
69 return SecKeyGetAlgorithmID(privKey);
70 #else
71 return SecKeyGetAlgorithmId(privKey);
72 #endif
73 }
74
75
76 OSStatus
77 sslCreateSecTrust(
78 SSLContext *ctx,
79 SecTrustRef *pTrust) /* RETURNED */
80 {
81 OSStatus status = errSecAllocate;
82 SecTrustRef trust = NULL;
83
84 require_noerr(status = tls_helper_create_peer_trust(ctx->hdsk, ctx->protocolSide==kSSLServerSide, &trust), errOut);
85
86 /* If we have trustedAnchors we set them here. */
87 if (trust && ctx->trustedCerts) {
88 require_noerr(status = SecTrustSetAnchorCertificates(trust, ctx->trustedCerts), errOut);
89 require_noerr(status = SecTrustSetAnchorCertificatesOnly(trust, ctx->trustedCertsOnly), errOut);
90 }
91
92 status = errSecSuccess;
93
94 errOut:
95 if(status != noErr) {
96 CFReleaseSafe(trust);
97 *pTrust = NULL;
98 } else {
99 *pTrust = trust;
100 }
101
102 return status;
103 }
104
105 #if !TARGET_OS_IPHONE
106 /* Return the first certificate reference from the supplied array
107 * whose data matches the given certificate, or NULL if none match.
108 */
109 static
110 SecCertificateRef
111 sslGetMatchingCertInArray(
112 SecCertificateRef certRef,
113 CFArrayRef certArray)
114 {
115 SecCertificateRef matchedCert = NULL;
116
117 if (certRef == NULL || certArray == NULL) {
118 return NULL;
119 }
120
121 CFDataRef certData = SecCertificateCopyData(certRef);
122 if (certData) {
123 CFIndex idx, count = CFArrayGetCount(certArray);
124 for(idx=0; idx<count; idx++) {
125 SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx);
126 CFDataRef aData = SecCertificateCopyData(aCert);
127 if (aData && CFEqual(aData, certData)) {
128 matchedCert = aCert;
129 }
130 CFReleaseSafe(aData);
131 if (matchedCert)
132 break;
133 }
134 CFReleaseSafe(certData);
135 }
136
137 return matchedCert;
138 }
139 #endif
140
141 /*
142 * Verify a chain of DER-encoded certs.
143 */
144 static OSStatus sslVerifyCertChain(
145 SSLContext *ctx)
146 {
147 OSStatus status;
148 SecTrustRef trust = NULL;
149
150 /* renegotiate - start with a new SecTrustRef */
151 CFReleaseNull(ctx->peerSecTrust);
152
153 /* on failure, we always return trust==NULL, so we don't check the returned status here */
154 sslCreateSecTrust(ctx, &trust);
155
156 if(trust==NULL) {
157 if(ctx->protocolSide == kSSLClientSide) {
158 /* No cert chain is always a trust failure on the server side */
159 status = errSSLXCertChainInvalid;
160 sslErrorLog("***Error: NULL server cert chain\n");
161 } else {
162 /* No cert chain on the client side is ok unless using kAlwaysAuthenticate */
163 if(ctx->clientAuth == kAlwaysAuthenticate) {
164 sslErrorLog("***Error: NULL client cert chain\n");
165 status = errSSLXCertChainInvalid;
166 } else {
167 status = noErr;
168 }
169 }
170 goto errOut;
171 }
172
173
174 if (!ctx->enableCertVerify) {
175 /* trivial case, this is caller's responsibility */
176 status = errSecSuccess;
177 goto errOut;
178 }
179
180 SecTrustResultType secTrustResult;
181 require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
182 switch (secTrustResult) {
183 case kSecTrustResultUnspecified:
184 /* cert chain valid, no special UserTrust assignments */
185 case kSecTrustResultProceed:
186 /* cert chain valid AND user explicitly trusts this */
187 status = errSecSuccess;
188 break;
189 case kSecTrustResultDeny:
190 case kSecTrustResultConfirm:
191 case kSecTrustResultRecoverableTrustFailure:
192 default:
193 if(ctx->allowAnyRoot) {
194 sslErrorLog("***Warning: accepting unverified cert chain\n");
195 status = errSecSuccess;
196 }
197 else {
198 #if !TARGET_OS_IPHONE
199 /*
200 * If the caller provided a list of trusted leaf certs, check them here
201 */
202 if(ctx->trustedLeafCerts) {
203 if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust, 0),
204 ctx->trustedLeafCerts)) {
205 status = errSecSuccess;
206 goto errOut;
207 }
208 }
209 #endif
210 status = errSSLXCertChainInvalid;
211 }
212 /* Do we really need to return things like:
213 errSSLNoRootCert
214 errSSLUnknownRootCert
215 errSSLCertExpired
216 errSSLCertNotYetValid
217 errSSLHostNameMismatch
218 for our client to see what went wrong, or should we just always
219 return
220 errSSLXCertChainInvalid
221 when something is wrong? */
222 break;
223 }
224
225 errOut:
226 ctx->peerSecTrust = trust;
227
228 return status;
229 }
230
231 /* Convert cert in DER format into an CFArray of SecCertificateRef */
232 CFArrayRef
233 tls_get_peer_certs(const SSLCertificate *certs)
234 {
235 const SSLCertificate *cert;
236
237 CFMutableArrayRef certArray = NULL;
238 CFDataRef certData = NULL;
239 SecCertificateRef cfCert = NULL;
240
241 certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
242 require(certArray, out);
243 cert = certs;
244 while(cert) {
245 require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out);
246 require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out);
247 CFArrayAppendValue(certArray, cfCert);
248 CFReleaseNull(cfCert);
249 CFReleaseNull(certData);
250 cert=cert->next;
251 }
252
253 return certArray;
254
255 out:
256 CFReleaseNull(cfCert);
257 CFReleaseNull(certData);
258 CFReleaseNull(certArray);
259 return NULL;
260 }
261
262 int
263 tls_verify_peer_cert(SSLContext *ctx)
264 {
265 int err = 0;
266 OSStatus st;
267
268 /* Note: A verification failure here does not cause the function to return an error.
269 This will allow the handshake to continue, coreTLS will eventually returns an error,
270 after sending the appropriate alert messages, based on the trust value set with the
271 call to tls_handshake_set_peer_trust(). In some case a verification failure here is
272 normal, for example if there is no cert (eg: PSK and Anon DH ciphersuites) */
273
274 st = sslVerifyCertChain(ctx);
275 tls_handshake_trust_t trust;
276 switch (st) {
277 case errSecSuccess:
278 trust = tls_handshake_trust_ok;
279 break;
280 case errSSLUnknownRootCert:
281 case errSSLNoRootCert:
282 trust = tls_handshake_trust_unknown_root;
283 break;
284 case errSSLCertExpired:
285 case errSSLCertNotYetValid:
286 trust = tls_handshake_trust_cert_expired;
287 break;
288 case errSSLXCertChainInvalid:
289 default:
290 trust = tls_handshake_trust_cert_invalid;
291 break;
292 }
293
294 tls_handshake_set_peer_trust(ctx->hdsk, trust);
295
296 /* Now that trust has been (possibly) evaluated,
297 we check if we need to break out of the handshake */
298 if(ctx->protocolSide == kSSLServerSide) {
299 /*
300 * Schedule return to the caller to verify the client's identity.
301 * This will return even if there was no client cert sent.
302 */
303 if (ctx->breakOnClientAuth) {
304 err = errSSLClientAuthCompleted;
305 }
306 } else if(ctx->peerSecTrust) {
307 /*
308 * Schedule return to the caller to verify the server's identity.
309 * This will only return if a server cert was sent. In other cases
310 * such as PSK and AnonDH, we don't want to break out of the handshake.
311 */
312 if (ctx->breakOnServerAuth) {
313 err = errSSLServerAuthCompleted;
314 }
315 }
316
317 return err;
318 }
319
320 /*
321 * After ciphersuite negotiation is complete, verify that we have
322 * the capability of actually performing the selected cipher.
323 * Currently we just verify that we have a cert and private signing
324 * key, if needed, and that the signing key's algorithm matches the
325 * expected key exchange method.
326 *
327 * This is currently called from FindCipherSpec(), after it sets
328 * ctx->selectedCipherSpec to a (supposedly) valid value, and from
329 * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only.
330 */
331
332 #if 0
333 OSStatus sslVerifySelectedCipher(SSLContext *ctx)
334 {
335
336 if(ctx->protocolSide == kSSLClientSide) {
337 return errSecSuccess;
338 }
339 #if SSL_PAC_SERVER_ENABLE
340 if((ctx->masterSecretCallback != NULL) &&
341 (ctx->sessionTicket.data != NULL)) {
342 /* EAP via PAC resumption; we can do it */
343 return errSecSuccess;
344 }
345 #endif /* SSL_PAC_SERVER_ENABLE */
346
347 CFIndex requireAlg;
348 switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
349 case SSL_RSA:
350 case SSL_RSA_EXPORT:
351 case SSL_DH_RSA:
352 case SSL_DH_RSA_EXPORT:
353 case SSL_DHE_RSA:
354 case SSL_DHE_RSA_EXPORT:
355 requireAlg = kSecRSAAlgorithmID;
356 break;
357 case SSL_DHE_DSS:
358 case SSL_DHE_DSS_EXPORT:
359 case SSL_DH_DSS:
360 case SSL_DH_DSS_EXPORT:
361 requireAlg = kSecDSAAlgorithmID;
362 break;
363 case SSL_DH_anon:
364 case SSL_DH_anon_EXPORT:
365 case TLS_PSK:
366 requireAlg = kSecNullAlgorithmID; /* no signing key */
367 break;
368 /*
369 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
370 * we'll need to add some logic here...
371 */
372 #if SSL_ECDSA_SERVER
373 case SSL_ECDHE_ECDSA:
374 case SSL_ECDHE_RSA:
375 case SSL_ECDH_ECDSA:
376 case SSL_ECDH_RSA:
377 case SSL_ECDH_anon:
378 requireAlg = kSecECDSAAlgorithmID;
379 break;
380 #endif
381
382 default:
383 /* needs update per cipherSpecs.c */
384 assert(0);
385 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
386 return errSSLInternal;
387 }
388
389 if(requireAlg == kSecNullAlgorithmID) {
390 return errSecSuccess;
391 }
392
393 /* private signing key required */
394 if(ctx->signingPrivKeyRef == NULL) {
395 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
396 return errSSLBadConfiguration;
397 }
398
399 /* Check the alg of our signing key. */
400 CFIndex keyAlg = sslPrivKeyGetAlgorithmID(ctx->signingPrivKeyRef);
401 if (requireAlg != keyAlg) {
402 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
403 return errSSLBadConfiguration;
404 }
405
406 return errSecSuccess;
407 }
408
409 #endif