]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslKeychain.cpp
06b3d5aaecd67919c23c20fcbf9255bacfb7cd10
[apple/security.git] / SecureTransport / sslKeychain.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: sslKeychain.c
21
22 Contains: Apple Keychain routines
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29
30 #include "ssl.h"
31 #include "sslContext.h"
32 #include "sslMemory.h"
33 #include "appleCdsa.h"
34 #include "sslDebug.h"
35 #include "sslKeychain.h"
36 #include "sslUtils.h"
37 #include <string.h>
38 #include <assert.h>
39 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
40 #include <Security/Security.h>
41
42 /*
43 * Given an array of certs (as SecIdentityRefs, specified by caller
44 * in SSLSetCertificate or SSLSetEncryptionCertificate) and a
45 * destination SSLCertificate:
46 *
47 * -- free destCerts if we have any
48 * -- Get raw cert data, convert to array of SSLCertificates in *destCert
49 * -- validate cert chain
50 * -- get pub, priv keys from certRef[0], store in *pubKey, *privKey
51 */
52
53 /* Convert a SecCertificateRef to an SSLCertificate * */
54 static OSStatus secCertToSslCert(
55 SSLContext *ctx,
56 SecCertificateRef certRef,
57 SSLCertificate **sslCert)
58 {
59 CSSM_DATA certData; // struct is transient, referent owned by
60 // Sec layer
61 OSStatus ortn;
62 SSLCertificate *thisSslCert = NULL;
63
64 ortn = SecCertificateGetData(certRef, &certData);
65 if(ortn) {
66 sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn);
67 return ortn;
68 }
69
70 thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
71 if(thisSslCert == NULL) {
72 return memFullErr;
73 }
74 if(SSLAllocBuffer(thisSslCert->derCert, certData.Length,
75 ctx)) {
76 return memFullErr;
77 }
78 memcpy(thisSslCert->derCert.data, certData.Data, certData.Length);
79 thisSslCert->derCert.length = certData.Length;
80 *sslCert = thisSslCert;
81 return noErr;
82 }
83
84 OSStatus
85 parseIncomingCerts(
86 SSLContext *ctx,
87 CFArrayRef certs,
88 SSLCertificate **destCert, /* &ctx->{localCert,encryptCert} */
89 CSSM_KEY_PTR *pubKey, /* &ctx->signingPubKey, etc. */
90 CSSM_KEY_PTR *privKey, /* &ctx->signingPrivKey, etc. */
91 CSSM_CSP_HANDLE *cspHand) /* &ctx->signingKeyCsp, etc. */
92 {
93 CFIndex numCerts;
94 CFIndex cert;
95 SSLCertificate *certChain = NULL;
96 SSLCertificate *thisSslCert;
97 SecKeychainRef kcRef;
98 OSStatus ortn;
99 SecIdentityRef identity;
100 SecCertificateRef certRef;
101 SecKeyRef keyRef;
102 CSSM_DATA certData;
103 CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef
104 CSSM_RETURN crtn;
105
106 assert(ctx != NULL);
107 assert(destCert != NULL); /* though its referent may be NULL */
108 assert(pubKey != NULL);
109 assert(privKey != NULL);
110 assert(cspHand != NULL);
111
112 sslDeleteCertificateChain(*destCert, ctx);
113 *destCert = NULL;
114 *pubKey = NULL;
115 *privKey = NULL;
116 *cspHand = 0;
117
118 if(certs == NULL) {
119 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
120 return errSSLBadCert;
121 }
122 numCerts = CFArrayGetCount(certs);
123 if(numCerts == 0) {
124 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
125 return errSSLBadCert;
126 }
127
128 /*
129 * Certs[0] is an SecIdentityRef from which we extract subject cert,
130 * privKey, pubKey, and cspHand.
131 *
132 * 1. ensure the first element is a SecIdentityRef.
133 */
134 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
135 if(identity == NULL) {
136 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
137 return paramErr;
138 }
139 if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
140 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
141 return paramErr;
142 }
143
144 /*
145 * 2. Extract cert, keys, CSP handle and convert to local format.
146 */
147 ortn = SecIdentityCopyCertificate(identity, &certRef);
148 if(ortn) {
149 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
150 return ortn;
151 }
152 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
153 if(ortn) {
154 sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
155 return ortn;
156 }
157 /* enqueue onto head of cert chain */
158 thisSslCert->next = certChain;
159 certChain = thisSslCert;
160
161 /* fetch private key from identity */
162 ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
163 if(ortn) {
164 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
165 (int)ortn);
166 return ortn;
167 }
168 ortn = SecKeyGetCSSMKey(keyRef, (const CSSM_KEY **)privKey);
169 if(ortn) {
170 sslErrorLog("parseIncomingCerts: SecKeyGetCSSMKey err %d\n",
171 (int)ortn);
172 return ortn;
173 }
174 /* FIXME = release keyRef? */
175
176 /* obtain public key from cert */
177 ortn = SecCertificateGetCLHandle(certRef, &clHand);
178 if(ortn) {
179 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
180 (int)ortn);
181 return ortn;
182 }
183 certData.Data = thisSslCert->derCert.data;
184 certData.Length = thisSslCert->derCert.length;
185 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
186 if(crtn) {
187 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
188 return (OSStatus)crtn;
189 }
190
191 /* obtain keychain from key, CSP handle from keychain */
192 ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
193 if(ortn) {
194 sslErrorLog("parseIncomingCerts: SecKeychainItemCopyKeychain err %d\n",
195 (int)ortn);
196 return ortn;
197 }
198 ortn = SecKeychainGetCSPHandle(kcRef, cspHand);
199 if(ortn) {
200 sslErrorLog("parseIncomingCerts: SecKeychainGetCSPHandle err %d\n",
201 (int)ortn);
202 return ortn;
203 }
204
205 /* OK, that's the subject cert. Fetch optional remaining certs. */
206 /*
207 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
208 * Incoming certs have root last; SSLCertificate chain has root
209 * first.
210 */
211 for(cert=1; cert<numCerts; cert++) {
212 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
213 if(certRef == NULL) {
214 sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
215 return paramErr;
216 }
217 if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
218 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
219 return paramErr;
220 }
221
222 /* Extract cert, convert to local format.
223 */
224 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
225 if(ortn) {
226 sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
227 return ortn;
228 }
229 /* enqueue onto head of cert chain */
230 thisSslCert->next = certChain;
231 certChain = thisSslCert;
232 }
233
234 /* validate the whole mess, skipping host name verify */
235 ortn = sslVerifyCertChain(ctx, *certChain, false);
236 if(ortn) {
237 goto errOut;
238 }
239
240 /* SUCCESS */
241 *destCert = certChain;
242 return noErr;
243
244 errOut:
245 /* free certChain, everything in it, other vars, return ortn */
246 sslDeleteCertificateChain(certChain, ctx);
247 /* FIXME - anything else? */
248 return ortn;
249 }
250
251