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 * */
68static 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 */
102static 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	}
167errOut:
168	SecCertificateReleaseFirstFieldValue(certRef,
169		&CSSMOID_X509V1SignatureAlgorithm, fieldPtr);
170	return ortn;
171}
172
173OSStatus
174parseIncomingCerts(
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
324OSStatus
325parseIncomingCerts(
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 */
468errOut:
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 */
490