]>
Commit | Line | Data |
---|---|---|
f484cdf5 | 1 | |
2 | /* | |
84f2d773 | 3 | * $Id: ssl_support.cc,v 1.5 2001/10/24 06:55:44 hno Exp $ |
f484cdf5 | 4 | * |
5 | * AUTHOR: Benno Rice | |
6 | * DEBUG: section 81 SSL accelerator support | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by the | |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * the CREDITS file for full details. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | */ | |
35 | ||
36 | #include "squid.h" | |
37 | ||
38 | extern int commUnsetNonBlocking(int fd); | |
39 | extern int commSetNonBlocking(int fd); | |
40 | ||
41 | void clientNegotiateSSL(int fd, void *data); | |
42 | void clientReadSSLRequest(int fd, void *data); | |
f484cdf5 | 43 | |
44 | static RSA * | |
45 | ssl_temp_rsa_cb(SSL * ssl, int export, int keylen) | |
46 | { | |
47 | static RSA *rsa = NULL; | |
48 | ||
49 | if (rsa == NULL) | |
50 | rsa = RSA_generate_key(512, RSA_F4, NULL, NULL); | |
51 | return rsa; | |
52 | } | |
53 | ||
54 | static int | |
55 | ssl_verify_cb(int ok, X509_STORE_CTX * ctx) | |
56 | { | |
57 | char buffer[256]; | |
58 | ||
59 | X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buffer, | |
60 | sizeof(buffer)); | |
61 | if (ok) | |
62 | debug(81, 5) ("SSL Certificate OK: %s\n", buffer); | |
63 | else { | |
64 | switch (ctx->error) { | |
65 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
66 | debug(81, 5) ("SSL Certficate error: CA not known: %s\n", buffer); | |
67 | break; | |
68 | case X509_V_ERR_CERT_NOT_YET_VALID: | |
69 | debug(81, 5) ("SSL Certficate not yet valid: %s\n", buffer); | |
70 | break; | |
71 | case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
72 | debug(81, 5) ("SSL Certificate has illegal \'not before\' field: %s\n", buffer); | |
73 | break; | |
74 | case X509_V_ERR_CERT_HAS_EXPIRED: | |
75 | debug(81, 5) ("SSL Certificate expired: %s\n", buffer); | |
76 | break; | |
77 | case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
78 | debug(81, 5) ("SSL Certificate has invalid \'not after\' field: %s\n", buffer); | |
79 | break; | |
80 | default: | |
81 | debug(81, 5) ("SSL unknown certificate error %d in %s\n", | |
82 | ctx->error, buffer); | |
83 | break; | |
84 | } | |
85 | } | |
86 | return ok; | |
87 | } | |
88 | ||
79d4ccdf | 89 | static struct ssl_option { |
90 | const char *name; | |
91 | long value; | |
92 | } ssl_options[] = { | |
93 | ||
94 | { | |
95 | "MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG | |
96 | }, | |
97 | { | |
98 | "NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG | |
99 | }, | |
100 | { | |
101 | "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | |
102 | }, | |
103 | { | |
104 | "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | |
105 | }, | |
106 | { | |
107 | "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | |
108 | }, | |
109 | { | |
110 | "MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING | |
111 | }, | |
112 | { | |
113 | "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG | |
114 | }, | |
115 | { | |
116 | "TLS_D5_BUG", SSL_OP_TLS_D5_BUG | |
117 | }, | |
118 | { | |
119 | "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG | |
120 | }, | |
121 | { | |
122 | "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG | |
123 | }, | |
124 | { | |
125 | "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE | |
126 | }, | |
127 | { | |
128 | "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA | |
129 | }, | |
130 | { | |
131 | "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 | |
132 | }, | |
133 | { | |
134 | "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 | |
135 | }, | |
136 | { | |
137 | "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG | |
138 | }, | |
139 | { | |
140 | "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST | |
141 | }, | |
142 | { | |
143 | "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG | |
144 | }, | |
145 | { | |
146 | "ALL", SSL_OP_ALL | |
147 | }, | |
148 | { | |
149 | "NO_SSLv2", SSL_OP_NO_SSLv2 | |
150 | }, | |
151 | { | |
152 | "NO_SSLv3", SSL_OP_NO_SSLv3 | |
153 | }, | |
154 | { | |
155 | "NO_TLSv1", SSL_OP_NO_TLSv1 | |
156 | }, | |
157 | { | |
158 | "", 0 | |
159 | }, | |
160 | { | |
161 | NULL, 0 | |
162 | } | |
163 | }; | |
164 | ||
84f2d773 | 165 | static long |
79d4ccdf | 166 | ssl_parse_options(const char *options) |
167 | { | |
168 | long op = SSL_OP_ALL; | |
169 | char *tmp; | |
170 | char *option; | |
171 | ||
172 | if (!options) | |
173 | goto no_options; | |
174 | ||
175 | tmp = xstrdup(options); | |
176 | option = strtok(tmp, ":,"); | |
177 | while (option) { | |
178 | struct ssl_option *opt = NULL, *opttmp; | |
179 | long value = 0; | |
180 | enum { | |
181 | MODE_ADD, MODE_REMOVE | |
182 | } mode; | |
183 | switch (*option) { | |
184 | case '!': | |
185 | case '-': | |
186 | mode = MODE_REMOVE; | |
187 | option++; | |
188 | break; | |
189 | case '+': | |
190 | mode = MODE_ADD; | |
191 | option++; | |
192 | break; | |
193 | default: | |
194 | mode = MODE_ADD; | |
195 | break; | |
196 | } | |
197 | for (opttmp = ssl_options; opttmp->name; opttmp++) { | |
198 | if (strcmp(opttmp->name, option) == 0) { | |
199 | opt = opttmp; | |
200 | break; | |
201 | } | |
202 | } | |
203 | if (opt) | |
204 | value = opt->value; | |
205 | else if (strncmp(option, "0x", 2) == 0) { | |
206 | /* Special case.. hex specification */ | |
207 | value = strtol(option + 2, NULL, 16); | |
208 | } else { | |
209 | fatalf("Unknown SSL option '%s'", option); | |
210 | value = 0; /* Keep GCC happy */ | |
211 | } | |
212 | switch (mode) { | |
213 | case MODE_ADD: | |
214 | op |= value; | |
215 | break; | |
216 | case MODE_REMOVE: | |
217 | op &= ~value; | |
218 | break; | |
219 | } | |
220 | option = strtok(NULL, ":,"); | |
221 | } | |
222 | ||
223 | safe_free(tmp); | |
224 | no_options: | |
225 | return op; | |
226 | } | |
227 | ||
d193a436 | 228 | SSL_CTX * |
79d4ccdf | 229 | sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options) |
f484cdf5 | 230 | { |
231 | int ssl_error; | |
232 | SSL_METHOD *method; | |
d193a436 | 233 | SSL_CTX *sslContext; |
234 | static int ssl_initialized = 0; | |
235 | if (!ssl_initialized) { | |
236 | ssl_initialized = 1; | |
237 | SSL_load_error_strings(); | |
238 | SSLeay_add_ssl_algorithms(); | |
239 | } | |
f484cdf5 | 240 | if (!keyfile) |
241 | keyfile = certfile; | |
242 | if (!certfile) | |
243 | certfile = keyfile; | |
244 | ||
245 | debug(81, 1) ("Initialising SSL.\n"); | |
79d4ccdf | 246 | switch (version) { |
f484cdf5 | 247 | case 2: |
248 | debug(81, 5) ("Using SSLv2.\n"); | |
249 | method = SSLv2_server_method(); | |
250 | break; | |
251 | case 3: | |
252 | debug(81, 5) ("Using SSLv3.\n"); | |
253 | method = SSLv3_server_method(); | |
254 | break; | |
255 | case 4: | |
256 | debug(81, 5) ("Using TLSv1.\n"); | |
257 | method = TLSv1_server_method(); | |
258 | break; | |
259 | case 1: | |
260 | default: | |
261 | debug(81, 5) ("Using SSLv2/SSLv3.\n"); | |
262 | method = SSLv23_server_method(); | |
263 | break; | |
264 | } | |
265 | ||
266 | sslContext = SSL_CTX_new(method); | |
267 | if (sslContext == NULL) { | |
268 | ssl_error = ERR_get_error(); | |
269 | fatalf("Failed to allocate SSL context: %s\n", | |
270 | ERR_error_string(ssl_error, NULL)); | |
271 | } | |
79d4ccdf | 272 | SSL_CTX_set_options(sslContext, ssl_parse_options(options)); |
f484cdf5 | 273 | |
79d4ccdf | 274 | if (cipher) { |
275 | debug(81, 5) ("Using chiper suite %s.\n", cipher); | |
276 | if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { | |
277 | ssl_error = ERR_get_error(); | |
278 | fatalf("Failed to set SSL cipher suite: %s\n", | |
279 | ERR_error_string(ssl_error, NULL)); | |
280 | } | |
281 | } | |
f484cdf5 | 282 | debug(81, 1) ("Using certificate in %s\n", certfile); |
283 | if (!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)) { | |
284 | ssl_error = ERR_get_error(); | |
285 | fatalf("Failed to acquire SSL certificate: %s\n", | |
286 | ERR_error_string(ssl_error, NULL)); | |
287 | } | |
288 | debug(81, 1) ("Using private key in %s\n", keyfile); | |
289 | if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { | |
290 | ssl_error = ERR_get_error(); | |
291 | fatalf("Failed to acquire SSL private key: %s\n", | |
292 | ERR_error_string(ssl_error, NULL)); | |
293 | } | |
294 | debug(81, 5) ("Comparing private and public SSL keys.\n"); | |
295 | if (!SSL_CTX_check_private_key(sslContext)) | |
296 | fatal("SSL private key does not match public key: %s\n"); | |
297 | ||
298 | debug(81, 9) ("Setting RSA key generation callback.\n"); | |
299 | SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); | |
300 | ||
301 | debug(81, 9) ("Setting certificate verification callback.\n"); | |
302 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb); | |
303 | ||
304 | debug(81, 9) ("Setting default CA certificate location.\n"); | |
305 | if (!SSL_CTX_set_default_verify_paths(sslContext)) { | |
306 | ssl_error = ERR_get_error(); | |
307 | debug(81, 1) ("Error error setting default CA certificate location: %s\n", | |
308 | ERR_error_string(ssl_error, NULL)); | |
309 | debug(81, 1) ("continuing anyway...\n"); | |
310 | } | |
311 | debug(81, 9) ("Set client certifying authority list.\n"); | |
312 | SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile)); | |
d193a436 | 313 | return sslContext; |
f484cdf5 | 314 | } |
315 | ||
d193a436 | 316 | int |
f484cdf5 | 317 | ssl_read_method(fd, buf, len) |
318 | int fd; | |
319 | char *buf; | |
320 | int len; | |
321 | { | |
79d4ccdf | 322 | int i; |
323 | ||
324 | i = SSL_read(fd_table[fd].ssl, buf, len); | |
325 | ||
326 | if (i > 0 && SSL_pending(fd_table[fd].ssl) > 0) { | |
327 | debug(81, 2) ("SSL fd %d is pending\n", fd); | |
328 | fd_table[fd].flags.read_pending = 1; | |
329 | } else | |
330 | fd_table[fd].flags.read_pending = 0; | |
331 | ||
332 | return i; | |
f484cdf5 | 333 | } |
334 | ||
d193a436 | 335 | int |
f484cdf5 | 336 | ssl_write_method(fd, buf, len) |
337 | int fd; | |
338 | const char *buf; | |
339 | int len; | |
340 | { | |
341 | return (SSL_write(fd_table[fd].ssl, buf, len)); | |
342 | } | |
79d4ccdf | 343 | |
344 | void | |
345 | ssl_shutdown_method(fd) | |
346 | { | |
347 | SSL *ssl = fd_table[fd].ssl; | |
348 | if (!fd_table[fd].ssl_shutdown) { | |
349 | fd_table[fd].ssl_shutdown = 1; | |
350 | if (Config.SSL.unclean_shutdown) | |
351 | SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); | |
352 | else | |
353 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); | |
354 | } | |
355 | SSL_shutdown(ssl); | |
356 | } |