]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/sslKeychain.c
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_ssl / lib / sslKeychain.c
1 /*
2 * Copyright (c) 1999-2001,2005-2008,2010-2012 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 * sslKeychain.c - Apple Keychain routines
26 */
27
28 #include "ssl.h"
29 #include "sslContext.h"
30 #include "sslMemory.h"
31
32 #include "sslCrypto.h"
33 #ifdef USE_CDSA_CRYPTO
34 #include <Security/Security.h>
35 #else
36 #include <Security/SecBase.h>
37 #include <Security/SecCertificate.h>
38 #include <Security/SecIdentity.h>
39 #include <Security/SecPolicy.h>
40 #include <Security/SecTrust.h>
41 #endif /* !USE_CDSA_CRYPTO */
42 #include "utilities/SecCFRelease.h"
43
44 #include "sslDebug.h"
45 #include "sslKeychain.h"
46 #include "sslUtils.h"
47 #include <string.h>
48 #include <assert.h>
49
50 #if TARGET_OS_IPHONE
51 #include "utilities/SecCFRelease.h"
52 #endif
53
54 #ifdef USE_SSLCERTIFICATE
55
56 /*
57 * Given an array of certs (as SecIdentityRefs, specified by caller
58 * in SSLSetCertificate or SSLSetEncryptionCertificate) and a
59 * destination SSLCertificate:
60 *
61 * -- free destCerts if we have any
62 * -- Get raw cert data, convert to array of SSLCertificates in *destCert
63 * -- validate cert chain
64 * -- get pub, priv keys from certRef[0], store in *pubKey, *privKey
65 */
66
67 /* Convert a SecCertificateRef to an SSLCertificate * */
68 static OSStatus secCertToSslCert(
69 SSLContext *ctx,
70 SecCertificateRef certRef,
71 SSLCertificate **sslCert)
72 {
73 CSSM_DATA certData; // struct is transient, referent owned by
74 // Sec layer
75 OSStatus ortn;
76 SSLCertificate *thisSslCert = NULL;
77
78 ortn = SecCertificateGetData(certRef, &certData);
79 if(ortn) {
80 sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn);
81 return ortn;
82 }
83
84 thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
85 if(thisSslCert == NULL) {
86 return errSecAllocate;
87 }
88 if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length,
89 ctx)) {
90 return errSecAllocate;
91 }
92 memcpy(thisSslCert->derCert.data, certData.Data, certData.Length);
93 thisSslCert->derCert.length = certData.Length;
94 *sslCert = thisSslCert;
95 return errSecSuccess;
96 }
97
98 /*
99 * Determine the basic signing algorithm, without the digest, component, of
100 * a cert. The returned algorithm will be RSA, DSA, or ECDSA.
101 */
102 static OSStatus sslCertSignerAlg(
103 SecCertificateRef certRef,
104 CSSM_ALGORITHMS *signerAlg)
105 {
106 OSStatus ortn;
107 CSSM_DATA_PTR fieldPtr;
108 CSSM_X509_ALGORITHM_IDENTIFIER *algId;
109 CSSM_ALGORITHMS sigAlg;
110
111 /*
112 * Extract the full signature algorithm OID
113 */
114 *signerAlg = CSSM_ALGID_NONE;
115 ortn = SecCertificateCopyFirstFieldValue(certRef,
116 &CSSMOID_X509V1SignatureAlgorithm,
117 &fieldPtr);
118 if(ortn) {
119 return ortn;
120 }
121 if(fieldPtr->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
122 sslErrorLog("sslCertSignerAlg() length error\n");
123 ortn = errSSLCrypto;
124 goto errOut;
125 }
126 algId = (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldPtr->Data;
127 if(!cssmOidToAlg(&algId->algorithm, &sigAlg)) {
128 /* Only way this could happen is if we're given a bad cert */
129 sslErrorLog("sslCertSignerAlg() bad sigAlg OID\n");
130 ortn = errSecParam;
131 goto errOut;
132 }
133
134 /*
135 * OK we have the full signature algorithm as a CSSM_ALGORITHMS.
136 * Extract the core signature alg.
137 */
138 switch(sigAlg) {
139 case CSSM_ALGID_RSA:
140 case CSSM_ALGID_MD2WithRSA:
141 case CSSM_ALGID_MD5WithRSA:
142 case CSSM_ALGID_SHA1WithRSA:
143 case CSSM_ALGID_SHA224WithRSA:
144 case CSSM_ALGID_SHA256WithRSA:
145 case CSSM_ALGID_SHA384WithRSA:
146 case CSSM_ALGID_SHA512WithRSA:
147 *signerAlg = CSSM_ALGID_RSA;
148 break;
149 case CSSM_ALGID_SHA1WithECDSA:
150 case CSSM_ALGID_SHA224WithECDSA:
151 case CSSM_ALGID_SHA256WithECDSA:
152 case CSSM_ALGID_SHA384WithECDSA:
153 case CSSM_ALGID_SHA512WithECDSA:
154 case CSSM_ALGID_ECDSA:
155 case CSSM_ALGID_ECDSA_SPECIFIED:
156 *signerAlg = CSSM_ALGID_ECDSA;
157 break;
158 case CSSM_ALGID_DSA:
159 case CSSM_ALGID_SHA1WithDSA:
160 *signerAlg = CSSM_ALGID_DSA;
161 break;
162 default:
163 sslErrorLog("sslCertSignerAlg() unknown sigAlg\n");
164 ortn = errSecParam;
165 break;
166 }
167 errOut:
168 SecCertificateReleaseFirstFieldValue(certRef,
169 &CSSMOID_X509V1SignatureAlgorithm, fieldPtr);
170 return ortn;
171 }
172
173 OSStatus
174 parseIncomingCerts(
175 SSLContext *ctx,
176 CFArrayRef certs,
177 SSLCertificate **destCert, /* &ctx->{localCert,encryptCert} */
178 CSSM_KEY_PTR *pubKey, /* &ctx->signingPubKey, etc. */
179 SecKeyRef *privKeyRef, /* &ctx->signingPrivKeyRef, etc. */
180 CSSM_ALGORITHMS *signerAlg) /* optional */
181 {
182 CFIndex numCerts;
183 CFIndex cert;
184 SSLCertificate *certChain = NULL;
185 SSLCertificate *thisSslCert;
186 OSStatus ortn;
187 SecIdentityRef identity;
188 SecCertificateRef certRef;
189 SecKeyRef keyRef;
190 CSSM_DATA certData;
191 CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef
192 CSSM_RETURN crtn;
193 CSSM_KEY_PTR *pubKey;
194 SecKeyRef *privKeyRef;
195
196 assert(ctx != NULL);
197 assert(destCert != NULL); /* though its referent may be NULL */
198 assert(sslPubKey != NULL);
199 assert(sslPrivKeyRef != NULL);
200
201 pubKey = &sslPubKey->key;
202 privKeyRef = &sslPrivKey->key;
203
204 sslDeleteCertificateChain(*destCert, ctx);
205 *destCert = NULL;
206 *pubKey = NULL;
207 *privKeyRef = NULL;
208
209 if(certs == NULL) {
210 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
211 return errSSLBadCert;
212 }
213 numCerts = CFArrayGetCount(certs);
214 if(numCerts == 0) {
215 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
216 return errSSLBadCert;
217 }
218
219 /*
220 * Certs[0] is an SecIdentityRef from which we extract subject cert,
221 * privKeyRef, pubKey.
222 *
223 * 1. ensure the first element is a SecIdentityRef.
224 */
225 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
226 if(identity == NULL) {
227 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
228 return errSecParam;
229 }
230 if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
231 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
232 return errSecParam;
233 }
234
235 /*
236 * 2. Extract cert, keys and convert to local format.
237 */
238 ortn = SecIdentityCopyCertificate(identity, &certRef);
239 if(ortn) {
240 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
241 return ortn;
242 }
243 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
244 if(ortn) {
245 sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
246 return ortn;
247 }
248 /* enqueue onto head of cert chain */
249 thisSslCert->next = certChain;
250 certChain = thisSslCert;
251
252 if(signerAlg != NULL) {
253 ortn = sslCertSignerAlg(certRef, signerAlg);
254 if(ortn) {
255 return ortn;
256 }
257 }
258
259 /* fetch private key from identity */
260 ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
261 if(ortn) {
262 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
263 (int)ortn);
264 return ortn;
265 }
266 *privKeyRef = keyRef;
267
268 /* obtain public key from cert */
269 ortn = SecCertificateGetCLHandle(certRef, &clHand);
270 if(ortn) {
271 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
272 (int)ortn);
273 return ortn;
274 }
275 certData.Data = thisSslCert->derCert.data;
276 certData.Length = thisSslCert->derCert.length;
277 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
278 if(crtn) {
279 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
280 return (OSStatus)crtn;
281 }
282
283 /* OK, that's the subject cert. Fetch optional remaining certs. */
284 /*
285 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
286 * Incoming certs have root last; SSLCertificate chain has root
287 * first.
288 */
289 for(cert=1; cert<numCerts; cert++) {
290 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
291 if(certRef == NULL) {
292 sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
293 return errSecParam;
294 }
295 if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
296 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
297 return errSecParam;
298 }
299
300 /* Extract cert, convert to local format.
301 */
302 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
303 if(ortn) {
304 sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
305 return ortn;
306 }
307 /* enqueue onto head of cert chain */
308 thisSslCert->next = certChain;
309 certChain = thisSslCert;
310 }
311
312 /* SUCCESS */
313 *destCert = certChain;
314 return errSecSuccess;
315
316 /* free certChain, everything in it, other vars, return ortn */
317 sslDeleteCertificateChain(certChain, ctx);
318 /* FIXME - anything else? */
319 return ortn;
320 }
321
322 #else /* !USE_SSLCERTIFICATE */
323
324 OSStatus
325 parseIncomingCerts(
326 SSLContext *ctx,
327 CFArrayRef certs,
328 CFArrayRef *destCertChain, /* &ctx->{localCertChain,encryptCertChain} */
329 SSLPubKey **sslPubKey, /* &ctx->signingPubKey, etc. */
330 SSLPrivKey **sslPrivKey, /* &ctx->signingPrivKeyRef, etc. */
331 CFIndex *signerAlg) /* optional */
332 {
333 OSStatus ortn;
334 CFIndex ix, numCerts;
335 SecIdentityRef identity;
336 CFMutableArrayRef certChain = NULL; /* Retained */
337 SecCertificateRef leafCert = NULL; /* Retained */
338 SecKeyRef pubKey = NULL; /* Retained */
339 SecKeyRef privKey = NULL; /* Retained */
340 SecTrustRef trust = NULL; /* Retained */
341
342 assert(ctx != NULL);
343 assert(destCertChain != NULL); /* though its referent may be NULL */
344 assert(sslPubKey != NULL);
345 assert(sslPrivKey != NULL);
346
347 if (certs == NULL) {
348 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
349 ortn = errSSLBadCert;
350 goto errOut;
351 }
352 numCerts = CFArrayGetCount(certs);
353 if (numCerts == 0) {
354 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
355 ortn = errSSLBadCert;
356 goto errOut;
357 }
358
359 /*
360 * Certs[0] is an SecIdentityRef from which we extract subject cert,
361 * privKey, pubKey.
362 *
363 * 1. ensure the first element is a SecIdentityRef.
364 */
365 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
366 if (identity == NULL) {
367 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
368 ortn = errSecParam;
369 goto errOut;
370 }
371 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
372 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
373 ortn = errSecParam;
374 goto errOut;
375 }
376
377 /*
378 * 2. Extract cert, keys and convert to local format.
379 */
380 ortn = SecIdentityCopyCertificate(identity, &leafCert);
381 if (ortn) {
382 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
383 goto errOut;
384 }
385
386 /* Fetch private key from identity */
387 ortn = SecIdentityCopyPrivateKey(identity, &privKey);
388 if (ortn) {
389 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
390 (int)ortn);
391 goto errOut;
392 }
393
394 /* Convert the input array of SecIdentityRef at the start to an array of
395 all certificates. */
396 certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts,
397 &kCFTypeArrayCallBacks);
398 if (!certChain) {
399 ortn = errSecAllocate;
400 goto errOut;
401 }
402 CFArrayAppendValue(certChain, leafCert);
403 for (ix = 1; ix < numCerts; ++ix) {
404 SecCertificateRef intermediate =
405 (SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
406 if (intermediate == NULL) {
407 sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
408 ortn = errSecParam;
409 goto errOut;
410 }
411 if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
412 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
413 ortn = errSecParam;
414 goto errOut;
415 }
416
417 CFArrayAppendValue(certChain, intermediate);
418 }
419
420 /* Obtain public key from cert */
421 #if TARGET_OS_IPHONE
422 ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust);
423 #else
424 {
425 SecPolicyRef policy = SecPolicyCreateBasicX509();
426 ortn = SecTrustCreateWithCertificates(certChain, policy, &trust);
427 CFReleaseSafe(policy);
428 if (!ortn) {
429 /* We are only interested in getting the public key from the leaf
430 * cert here, so for best performance, don't try to build a chain
431 * or search any keychains.
432 */
433 CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL);
434 (void)SecTrustSetAnchorCertificates(trust, emptyArray);
435 (void)SecTrustSetKeychains(trust, emptyArray);
436 CFReleaseSafe(emptyArray);
437 }
438 }
439 #endif
440 if (ortn) {
441 sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n",
442 (int)ortn);
443 goto errOut;
444 }
445
446
447 #if !TARGET_OS_IPHONE
448 /* This is not required on iOS, but still required on osx */
449 SecTrustResultType trustResult;
450 ortn = SecTrustEvaluate(trust, &trustResult);
451 if (ortn) {
452 sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
453 (int)ortn);
454 goto errOut;
455 }
456 #endif
457
458
459 pubKey = SecTrustCopyPublicKey(trust);
460 if (!pubKey) {
461 /* We parsed the private key succesfully but could not get the public key: return an error */
462 sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
463 ortn = errSecParam;
464 goto errOut;
465 }
466
467 /* SUCCESS */
468 errOut:
469 CFReleaseSafe(trust);
470 CFReleaseSafe(leafCert);
471 CFReleaseSafe(*destCertChain);
472 sslFreePubKey(sslPubKey);
473 sslFreePrivKey(sslPrivKey);
474
475 if (ortn) {
476 CFReleaseSafe(certChain);
477 CFReleaseSafe(pubKey);
478 CFReleaseSafe(privKey);
479
480 *destCertChain = NULL;
481 } else {
482 *destCertChain = certChain;
483 *sslPubKey = (SSLPubKey*)pubKey;
484 *sslPrivKey = (SSLPrivKey*)privKey;
485 }
486
487 return ortn;
488 }
489 #endif /* !USE_SSLCERTIFICATE */