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 SecKeyRef
*privKeyRef
) /* &ctx->signingPrivKeyRef, etc. */
94 SSLCertificate
*certChain
= NULL
;
95 SSLCertificate
*thisSslCert
;
97 SecIdentityRef identity
;
98 SecCertificateRef certRef
;
101 CSSM_CL_HANDLE clHand
; // carefully derive from a SecCertificateRef
105 assert(destCert
!= NULL
); /* though its referent may be NULL */
106 assert(pubKey
!= NULL
);
107 assert(privKeyRef
!= NULL
);
109 sslDeleteCertificateChain(*destCert
, ctx
);
115 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
116 return errSSLBadCert
;
118 numCerts
= CFArrayGetCount(certs
);
120 sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
121 return errSSLBadCert
;
125 * Certs[0] is an SecIdentityRef from which we extract subject cert,
126 * privKeyRef, pubKey.
128 * 1. ensure the first element is a SecIdentityRef.
130 identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(certs
, 0);
131 if(identity
== NULL
) {
132 sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
135 if(CFGetTypeID(identity
) != SecIdentityGetTypeID()) {
136 sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
141 * 2. Extract cert, keys and convert to local format.
143 ortn
= SecIdentityCopyCertificate(identity
, &certRef
);
145 sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
148 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
150 sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
153 /* enqueue onto head of cert chain */
154 thisSslCert
->next
= certChain
;
155 certChain
= thisSslCert
;
157 /* fetch private key from identity */
158 ortn
= SecIdentityCopyPrivateKey(identity
, &keyRef
);
160 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
164 *privKeyRef
= keyRef
;
166 /* obtain public key from cert */
167 ortn
= SecCertificateGetCLHandle(certRef
, &clHand
);
169 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
173 certData
.Data
= thisSslCert
->derCert
.data
;
174 certData
.Length
= thisSslCert
->derCert
.length
;
175 crtn
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, pubKey
);
177 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
178 return (OSStatus
)crtn
;
181 /* OK, that's the subject cert. Fetch optional remaining certs. */
183 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
184 * Incoming certs have root last; SSLCertificate chain has root
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");
193 if(CFGetTypeID(certRef
) != SecCertificateGetTypeID()) {
194 sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
198 /* Extract cert, convert to local format.
200 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
202 sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
205 /* enqueue onto head of cert chain */
206 thisSslCert
->next
= certChain
;
207 certChain
= thisSslCert
;
211 *destCert
= certChain
;
215 /* free certChain, everything in it, other vars, return ortn */
216 sslDeleteCertificateChain(certChain
, ctx
);
217 /* FIXME - anything else? */