2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: Apple Keychain routines
24 Written by: Doug Mitchell
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
31 #include "sslContext.h"
32 #include "sslMemory.h"
33 #include "appleCdsa.h"
35 #include "sslKeychain.h"
39 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
40 #include <Security/Security.h>
43 * Given an array of certs (as SecIdentityRefs, specified by caller
44 * in SSLSetCertificate or SSLSetEncryptionCertificate) and a
45 * destination SSLCertificate:
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
53 /* Convert a SecCertificateRef to an SSLCertificate * */
54 static OSStatus
secCertToSslCert(
56 SecCertificateRef certRef
,
57 SSLCertificate
**sslCert
)
59 CSSM_DATA certData
; // struct is transient, referent owned by
62 SSLCertificate
*thisSslCert
= NULL
;
64 ortn
= SecCertificateGetData(certRef
, &certData
);
66 sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn
);
70 thisSslCert
= (SSLCertificate
*)sslMalloc(sizeof(SSLCertificate
));
71 if(thisSslCert
== NULL
) {
74 if(SSLAllocBuffer(thisSslCert
->derCert
, certData
.Length
,
78 memcpy(thisSslCert
->derCert
.data
, certData
.Data
, certData
.Length
);
79 thisSslCert
->derCert
.length
= certData
.Length
;
80 *sslCert
= thisSslCert
;
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. */
95 SSLCertificate
*certChain
= NULL
;
96 SSLCertificate
*thisSslCert
;
99 SecIdentityRef identity
;
100 SecCertificateRef certRef
;
103 CSSM_CL_HANDLE clHand
; // carefully derive from a SecCertificateRef
107 assert(destCert
!= NULL
); /* though its referent may be NULL */
108 assert(pubKey
!= NULL
);
109 assert(privKey
!= NULL
);
110 assert(cspHand
!= NULL
);
112 sslDeleteCertificateChain(*destCert
, ctx
);
119 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
120 return errSSLBadCert
;
122 numCerts
= CFArrayGetCount(certs
);
124 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
125 return errSSLBadCert
;
129 * Certs[0] is an SecIdentityRef from which we extract subject cert,
130 * privKey, pubKey, and cspHand.
132 * 1. ensure the first element is a SecIdentityRef.
134 identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(certs
, 0);
135 if(identity
== NULL
) {
136 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
139 if(CFGetTypeID(identity
) != SecIdentityGetTypeID()) {
140 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
145 * 2. Extract cert, keys, CSP handle and convert to local format.
147 ortn
= SecIdentityCopyCertificate(identity
, &certRef
);
149 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
152 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
154 sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
157 /* enqueue onto head of cert chain */
158 thisSslCert
->next
= certChain
;
159 certChain
= thisSslCert
;
161 /* fetch private key from identity */
162 ortn
= SecIdentityCopyPrivateKey(identity
, &keyRef
);
164 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
168 ortn
= SecKeyGetCSSMKey(keyRef
, (const CSSM_KEY
**)privKey
);
170 sslErrorLog("parseIncomingCerts: SecKeyGetCSSMKey err %d\n",
174 /* FIXME = release keyRef? */
176 /* obtain public key from cert */
177 ortn
= SecCertificateGetCLHandle(certRef
, &clHand
);
179 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
183 certData
.Data
= thisSslCert
->derCert
.data
;
184 certData
.Length
= thisSslCert
->derCert
.length
;
185 crtn
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, pubKey
);
187 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
188 return (OSStatus
)crtn
;
191 /* obtain keychain from key, CSP handle from keychain */
192 ortn
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)keyRef
, &kcRef
);
194 sslErrorLog("parseIncomingCerts: SecKeychainItemCopyKeychain err %d\n",
198 ortn
= SecKeychainGetCSPHandle(kcRef
, cspHand
);
200 sslErrorLog("parseIncomingCerts: SecKeychainGetCSPHandle err %d\n",
205 /* OK, that's the subject cert. Fetch optional remaining certs. */
207 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
208 * Incoming certs have root last; SSLCertificate chain has root
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");
217 if(CFGetTypeID(certRef
) != SecCertificateGetTypeID()) {
218 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
222 /* Extract cert, convert to local format.
224 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
226 sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
229 /* enqueue onto head of cert chain */
230 thisSslCert
->next
= certChain
;
231 certChain
= thisSslCert
;
234 /* validate the whole mess, skipping host name verify */
235 ortn
= sslVerifyCertChain(ctx
, *certChain
, false);
241 *destCert
= certChain
;
245 /* free certChain, everything in it, other vars, return ortn */
246 sslDeleteCertificateChain(certChain
, ctx
);
247 /* FIXME - anything else? */