]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 1999-2001,2005-2008,2010-2014 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 | #include <Security/SecBase.h> | |
34 | #include <Security/SecCertificate.h> | |
35 | #include <Security/SecCertificatePriv.h> | |
36 | #include <Security/SecIdentity.h> | |
37 | #include <Security/SecPolicy.h> | |
38 | #include <Security/SecTrust.h> | |
39 | #include "utilities/SecCFRelease.h" | |
40 | ||
41 | #include "sslDebug.h" | |
42 | #include "sslKeychain.h" | |
d8f41ccd A |
43 | #include <string.h> |
44 | #include <assert.h> | |
45 | ||
46 | ||
47 | #include <Security/Security.h> | |
48 | #include <Security/SecKeyPriv.h> | |
6b200bc3 A |
49 | #if SEC_OS_IPHONE |
50 | #include <Security/SecECKey.h> | |
51 | #endif | |
d8f41ccd A |
52 | #include <AssertMacros.h> |
53 | #include <tls_handshake.h> | |
54 | ||
55 | #if TARGET_OS_IPHONE | |
56 | #include <Security/oidsalg.h> | |
5c19dc3a | 57 | #include <Security/SecECKey.h> |
d8f41ccd A |
58 | #endif |
59 | ||
60 | /* Private Key operations */ | |
61 | static | |
62 | SecAsn1Oid oidForSSLHash(SSL_HashAlgorithm hash) | |
63 | { | |
64 | switch (hash) { | |
65 | case tls_hash_algorithm_SHA1: | |
66 | return CSSMOID_SHA1WithRSA; | |
67 | case tls_hash_algorithm_SHA256: | |
68 | return CSSMOID_SHA256WithRSA; | |
69 | case tls_hash_algorithm_SHA384: | |
70 | return CSSMOID_SHA384WithRSA; | |
71 | default: | |
72 | break; | |
73 | } | |
74 | // Internal error | |
75 | assert(0); | |
76 | // This guarantee failure down the line | |
77 | return CSSMOID_MD5WithRSA; | |
78 | } | |
79 | ||
80 | static | |
81 | int mySSLPrivKeyRSA_sign(void *key, tls_hash_algorithm hash, const uint8_t *plaintext, size_t plaintextLen, uint8_t *sig, size_t *sigLen) | |
82 | { | |
83 | SecKeyRef keyRef = key; | |
84 | ||
85 | if(hash == tls_hash_algorithm_None) { | |
86 | return SecKeyRawSign(keyRef, kSecPaddingPKCS1, plaintext, plaintextLen, sig, sigLen); | |
87 | } else { | |
88 | SecAsn1AlgId algId; | |
89 | algId.algorithm = oidForSSLHash(hash); | |
90 | return SecKeySignDigest(keyRef, &algId, plaintext, plaintextLen, sig, sigLen); | |
91 | } | |
92 | } | |
93 | ||
94 | static | |
95 | int mySSLPrivKeyRSA_decrypt(void *key, const uint8_t *ciphertext, size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen) | |
96 | { | |
97 | SecKeyRef keyRef = key; | |
98 | ||
99 | return SecKeyDecrypt(keyRef, kSecPaddingPKCS1, ciphertext, ciphertextLen, plaintext, plaintextLen); | |
100 | } | |
101 | ||
5c19dc3a A |
102 | static |
103 | int mySSLPrivKeyECDSA_sign(void *key, const uint8_t *plaintext, size_t plaintextLen, uint8_t *sig, size_t *sigLen) | |
104 | { | |
105 | SecKeyRef keyRef = key; | |
106 | ||
107 | return SecKeyRawSign(keyRef, kSecPaddingPKCS1, plaintext, plaintextLen, sig, sigLen); | |
108 | } | |
109 | ||
d8f41ccd A |
110 | void sslFreePrivKey(tls_private_key_t *sslPrivKey) |
111 | { | |
112 | assert(sslPrivKey); | |
113 | ||
114 | if(*sslPrivKey) { | |
115 | CFReleaseSafe(tls_private_key_get_context(*sslPrivKey)); | |
116 | tls_private_key_destroy(*sslPrivKey); | |
117 | *sslPrivKey = NULL; | |
118 | } | |
119 | } | |
120 | ||
121 | OSStatus | |
122 | parseIncomingCerts( | |
123 | SSLContext *ctx, | |
124 | CFArrayRef certs, | |
125 | SSLCertificate **destCertChain, /* &ctx->{localCertChain,encryptCertChain} */ | |
126 | tls_private_key_t *sslPrivKey) /* &ctx->signingPrivKeyRef, etc. */ | |
127 | { | |
128 | OSStatus ortn; | |
129 | CFIndex ix, numCerts; | |
130 | SecIdentityRef identity; | |
131 | SSLCertificate *certChain = NULL; /* Retained */ | |
132 | SecCertificateRef leafCert = NULL; /* Retained */ | |
133 | SecKeyRef privKey = NULL; /* Retained */ | |
134 | ||
135 | assert(ctx != NULL); | |
136 | assert(destCertChain != NULL); /* though its referent may be NULL */ | |
137 | assert(sslPrivKey != NULL); | |
138 | ||
139 | if (certs == NULL) { | |
140 | sslErrorLog("parseIncomingCerts: NULL incoming cert array\n"); | |
141 | ortn = errSSLBadCert; | |
142 | goto errOut; | |
143 | } | |
144 | numCerts = CFArrayGetCount(certs); | |
145 | if (numCerts == 0) { | |
146 | sslErrorLog("parseIncomingCerts: empty incoming cert array\n"); | |
147 | ortn = errSSLBadCert; | |
148 | goto errOut; | |
149 | } | |
150 | ||
151 | certChain=sslMalloc(numCerts*sizeof(SSLCertificate)); | |
152 | if (!certChain) { | |
153 | ortn = errSecAllocate; | |
154 | goto errOut; | |
155 | } | |
156 | ||
157 | /* | |
158 | * Certs[0] is an SecIdentityRef from which we extract subject cert, | |
159 | * privKey, pubKey. | |
160 | * | |
161 | * 1. ensure the first element is a SecIdentityRef. | |
162 | */ | |
163 | identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0); | |
164 | if (identity == NULL) { | |
165 | sslErrorLog("parseIncomingCerts: bad cert array (1)\n"); | |
166 | ortn = errSecParam; | |
167 | goto errOut; | |
168 | } | |
169 | if (CFGetTypeID(identity) != SecIdentityGetTypeID()) { | |
170 | sslErrorLog("parseIncomingCerts: bad cert array (2)\n"); | |
171 | ortn = errSecParam; | |
172 | goto errOut; | |
173 | } | |
174 | ||
175 | /* | |
176 | * 2. Extract cert, keys and convert to local format. | |
177 | */ | |
178 | ortn = SecIdentityCopyCertificate(identity, &leafCert); | |
179 | if (ortn) { | |
180 | sslErrorLog("parseIncomingCerts: bad cert array (3)\n"); | |
181 | goto errOut; | |
182 | } | |
183 | ||
184 | /* Fetch private key from identity */ | |
185 | ortn = SecIdentityCopyPrivateKey(identity, &privKey); | |
186 | if (ortn) { | |
187 | sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n", | |
188 | (int)ortn); | |
189 | goto errOut; | |
190 | } | |
191 | ||
192 | /* Convert the input array of SecIdentityRef at the start to an array of | |
193 | all certificates. */ | |
5c19dc3a | 194 | SSLCopyBufferFromData(SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert), &certChain[0].derCert); |
d8f41ccd A |
195 | certChain[0].next = NULL; |
196 | ||
197 | for (ix = 1; ix < numCerts; ++ix) { | |
198 | SecCertificateRef intermediate = | |
199 | (SecCertificateRef)CFArrayGetValueAtIndex(certs, ix); | |
200 | if (intermediate == NULL) { | |
201 | sslErrorLog("parseIncomingCerts: bad cert array (5)\n"); | |
202 | ortn = errSecParam; | |
203 | goto errOut; | |
204 | } | |
205 | if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) { | |
206 | sslErrorLog("parseIncomingCerts: bad cert array (6)\n"); | |
207 | ortn = errSecParam; | |
208 | goto errOut; | |
209 | } | |
210 | ||
5c19dc3a | 211 | SSLCopyBufferFromData(SecCertificateGetBytePtr(intermediate), SecCertificateGetLength(intermediate), &certChain[ix].derCert); |
d8f41ccd A |
212 | certChain[ix].next = NULL; |
213 | certChain[ix-1].next = &certChain[ix]; | |
214 | ||
215 | } | |
216 | ||
5c19dc3a A |
217 | sslFreePrivKey(sslPrivKey); |
218 | size_t size = SecKeyGetBlockSize(privKey); | |
219 | if(sslPrivKeyGetAlgorithmID(privKey) == kSecRSAAlgorithmID) { | |
220 | *sslPrivKey = tls_private_key_rsa_create(privKey, SecKeyGetBlockSize(privKey), mySSLPrivKeyRSA_sign, mySSLPrivKeyRSA_decrypt); | |
221 | } else if (sslPrivKeyGetAlgorithmID(privKey) == kSecECDSAAlgorithmID) { | |
222 | #if TARGET_OS_IPHONE | |
223 | /* Compute signature size from key size */ | |
224 | size_t sigSize = 8+2*size; | |
225 | #else | |
226 | size_t sigSize = size; | |
227 | #endif | |
228 | *sslPrivKey = tls_private_key_ecdsa_create(privKey, sigSize, SecECKeyGetNamedCurve(privKey), mySSLPrivKeyECDSA_sign); | |
229 | } else { | |
d8f41ccd A |
230 | ortn = errSecParam; |
231 | goto errOut; | |
232 | } | |
d8f41ccd A |
233 | if(*sslPrivKey) |
234 | ortn = errSecSuccess; | |
235 | else | |
236 | ortn = errSecAllocate; | |
237 | ||
238 | /* SUCCESS */ | |
239 | errOut: | |
240 | CFReleaseSafe(leafCert); | |
241 | ||
242 | sslFree(*destCertChain); | |
243 | ||
244 | if (ortn) { | |
245 | free(certChain); | |
246 | CFReleaseSafe(privKey); | |
247 | *destCertChain = NULL; | |
248 | } else { | |
249 | *destCertChain = certChain; | |
250 | } | |
251 | ||
252 | return ortn; | |
253 | } |