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