]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslKeychain.cpp
Security-177.tar.gz
[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 SecKeyRef *privKeyRef) /* &ctx->signingPrivKeyRef, etc. */
91 {
92 CFIndex numCerts;
93 CFIndex cert;
94 SSLCertificate *certChain = NULL;
95 SSLCertificate *thisSslCert;
96 OSStatus ortn;
97 SecIdentityRef identity;
98 SecCertificateRef certRef;
99 SecKeyRef keyRef;
100 CSSM_DATA certData;
101 CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef
102 CSSM_RETURN crtn;
103
104 assert(ctx != NULL);
105 assert(destCert != NULL); /* though its referent may be NULL */
106 assert(pubKey != NULL);
107 assert(privKeyRef != NULL);
108
109 sslDeleteCertificateChain(*destCert, ctx);
110 *destCert = NULL;
111 *pubKey = NULL;
112 *privKeyRef = NULL;
113
114 if(certs == NULL) {
115 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
116 return errSSLBadCert;
117 }
118 numCerts = CFArrayGetCount(certs);
119 if(numCerts == 0) {
120 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
121 return errSSLBadCert;
122 }
123
124 /*
125 * Certs[0] is an SecIdentityRef from which we extract subject cert,
126 * privKeyRef, pubKey.
127 *
128 * 1. ensure the first element is a SecIdentityRef.
129 */
130 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
131 if(identity == NULL) {
132 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
133 return paramErr;
134 }
135 if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
136 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
137 return paramErr;
138 }
139
140 /*
141 * 2. Extract cert, keys and convert to local format.
142 */
143 ortn = SecIdentityCopyCertificate(identity, &certRef);
144 if(ortn) {
145 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
146 return ortn;
147 }
148 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
149 if(ortn) {
150 sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
151 return ortn;
152 }
153 /* enqueue onto head of cert chain */
154 thisSslCert->next = certChain;
155 certChain = thisSslCert;
156
157 /* fetch private key from identity */
158 ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
159 if(ortn) {
160 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
161 (int)ortn);
162 return ortn;
163 }
164 *privKeyRef = keyRef;
165
166 /* obtain public key from cert */
167 ortn = SecCertificateGetCLHandle(certRef, &clHand);
168 if(ortn) {
169 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
170 (int)ortn);
171 return ortn;
172 }
173 certData.Data = thisSslCert->derCert.data;
174 certData.Length = thisSslCert->derCert.length;
175 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
176 if(crtn) {
177 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
178 return (OSStatus)crtn;
179 }
180
181 /* OK, that's the subject cert. Fetch optional remaining certs. */
182 /*
183 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
184 * Incoming certs have root last; SSLCertificate chain has root
185 * first.
186 */
187 for(cert=1; cert<numCerts; cert++) {
188 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
189 if(certRef == NULL) {
190 sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
191 return paramErr;
192 }
193 if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
194 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
195 return paramErr;
196 }
197
198 /* Extract cert, convert to local format.
199 */
200 ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
201 if(ortn) {
202 sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
203 return ortn;
204 }
205 /* enqueue onto head of cert chain */
206 thisSslCert->next = certChain;
207 certChain = thisSslCert;
208 }
209
210 /* SUCCESS */
211 *destCert = certChain;
212 return noErr;
213
214 errOut:
215 /* free certChain, everything in it, other vars, return ortn */
216 sslDeleteCertificateChain(certChain, ctx);
217 /* FIXME - anything else? */
218 return ortn;
219 }
220
221