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