]>
Commit | Line | Data |
---|---|---|
f484cdf5 | 1 | |
2 | /* | |
5a4684b6 | 3 | * $Id: ssl_support.cc,v 1.21 2005/03/18 14:43:33 hno Exp $ |
f484cdf5 | 4 | * |
5 | * AUTHOR: Benno Rice | |
27d8545c | 6 | * DEBUG: section 83 SSL accelerator support |
f484cdf5 | 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" | |
528b2c61 | 37 | #include "fde.h" |
f484cdf5 | 38 | |
307b83b7 | 39 | static int |
40 | ssl_ask_password_cb(char *buf, int size, int rwflag, void *userdata) | |
41 | { | |
42 | FILE *in; | |
43 | int len = 0; | |
44 | char cmdline[1024]; | |
45 | ||
46 | snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", Config.Program.ssl_password, (const char *)userdata); | |
47 | in = popen(cmdline, "r"); | |
48 | ||
49 | if (fgets(buf, size, in)) | |
50 | ||
51 | len = strlen(buf); | |
52 | ||
53 | while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r')) | |
54 | ||
55 | len--; | |
56 | ||
57 | buf[len] = '\0'; | |
58 | ||
59 | pclose(in); | |
60 | ||
61 | return len; | |
62 | } | |
63 | ||
64 | static void | |
65 | ssl_ask_password(SSL_CTX * context, const char * prompt) | |
66 | { | |
67 | if (Config.Program.ssl_password) { | |
68 | SSL_CTX_set_default_passwd_cb(context, ssl_ask_password_cb); | |
69 | SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt); | |
70 | } | |
71 | } | |
72 | ||
f484cdf5 | 73 | static RSA * |
e6ccf245 | 74 | ssl_temp_rsa_cb(SSL * ssl, int anInt, int keylen) |
f484cdf5 | 75 | { |
76 | static RSA *rsa = NULL; | |
77 | ||
78 | if (rsa == NULL) | |
62e76326 | 79 | rsa = RSA_generate_key(512, RSA_F4, NULL, NULL); |
80 | ||
f484cdf5 | 81 | return rsa; |
82 | } | |
83 | ||
84 | static int | |
85 | ssl_verify_cb(int ok, X509_STORE_CTX * ctx) | |
86 | { | |
87 | char buffer[256]; | |
a7ad6e4e | 88 | SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
89 | SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl); | |
90 | const char *server = (const char *)SSL_get_ex_data(ssl, ssl_ex_index_server); | |
91 | void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain); | |
92 | X509 *peer_cert = ctx->cert; | |
f484cdf5 | 93 | |
a7ad6e4e | 94 | X509_NAME_oneline(X509_get_subject_name(peer_cert), buffer, |
62e76326 | 95 | sizeof(buffer)); |
a7ad6e4e | 96 | |
97 | if (ok) { | |
62e76326 | 98 | debug(83, 5) ("SSL Certificate signature OK: %s\n", buffer); |
99 | ||
100 | if (server) { | |
101 | int i; | |
102 | int found = 0; | |
103 | char cn[1024]; | |
104 | X509_NAME *name = X509_get_subject_name(peer_cert); | |
105 | debug(83, 3) ("Verifying server domain %s to certificate dn %s\n", | |
106 | server, buffer); | |
107 | ||
108 | for (i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); i >= 0; i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) { | |
109 | ASN1_STRING *data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); | |
110 | ||
111 | if (data->length > (int)sizeof(cn) - 1) | |
112 | continue; | |
113 | ||
114 | memcpy(cn, data->data, data->length); | |
115 | ||
116 | cn[data->length] = '\0'; | |
117 | ||
118 | debug(83, 4) ("Verifying server domain %s to certificate cn %s\n", | |
119 | server, cn); | |
120 | ||
121 | if (matchDomainName(server, cn[0] == '*' ? cn + 1 : cn) == 0) { | |
122 | found = 1; | |
123 | break; | |
124 | } | |
125 | } | |
126 | ||
127 | if (!found) { | |
128 | debug(83, 2) ("ERROR: Certificate %s does not match domainname %s\n", buffer, server); | |
129 | ok = 0; | |
130 | } | |
131 | } | |
a7ad6e4e | 132 | } else { |
62e76326 | 133 | switch (ctx->error) { |
134 | ||
135 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
136 | debug(83, 5) ("SSL Certficate error: CA not known: %s\n", buffer); | |
137 | break; | |
138 | ||
139 | case X509_V_ERR_CERT_NOT_YET_VALID: | |
140 | debug(83, 5) ("SSL Certficate not yet valid: %s\n", buffer); | |
141 | break; | |
142 | ||
143 | case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
144 | debug(83, 5) ("SSL Certificate has illegal \'not before\' field: %s\n", buffer); | |
145 | break; | |
146 | ||
147 | case X509_V_ERR_CERT_HAS_EXPIRED: | |
148 | debug(83, 5) ("SSL Certificate expired: %s\n", buffer); | |
149 | break; | |
150 | ||
151 | case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
152 | debug(83, 5) ("SSL Certificate has invalid \'not after\' field: %s\n", buffer); | |
153 | break; | |
154 | ||
155 | default: | |
156 | debug(83, 1) ("SSL unknown certificate error %d in %s\n", | |
157 | ctx->error, buffer); | |
158 | break; | |
159 | } | |
a7ad6e4e | 160 | } |
62e76326 | 161 | |
162 | if (!dont_verify_domain && server) {} | |
163 | ||
f484cdf5 | 164 | return ok; |
165 | } | |
166 | ||
62e76326 | 167 | static struct ssl_option |
168 | { | |
79d4ccdf | 169 | const char *name; |
170 | long value; | |
62e76326 | 171 | } |
172 | ||
173 | ssl_options[] = { | |
79d4ccdf | 174 | |
673cd7db | 175 | #ifdef SSL_OP_MICROSOFT_SESS_ID_BUG |
62e76326 | 176 | { |
177 | "MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG | |
178 | }, | |
673cd7db | 179 | #endif |
180 | #ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG | |
62e76326 | 181 | { |
182 | "NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG | |
183 | }, | |
673cd7db | 184 | #endif |
185 | #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | |
62e76326 | 186 | { |
187 | "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | |
188 | }, | |
673cd7db | 189 | #endif |
190 | #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | |
62e76326 | 191 | { |
192 | "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | |
193 | }, | |
673cd7db | 194 | #endif |
195 | #ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | |
62e76326 | 196 | { |
197 | "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | |
198 | }, | |
673cd7db | 199 | #endif |
200 | #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING | |
62e76326 | 201 | { |
202 | "MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING | |
203 | }, | |
673cd7db | 204 | #endif |
205 | #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG | |
62e76326 | 206 | { |
207 | "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG | |
208 | }, | |
673cd7db | 209 | #endif |
210 | #ifdef SSL_OP_TLS_D5_BUG | |
62e76326 | 211 | { |
212 | "TLS_D5_BUG", SSL_OP_TLS_D5_BUG | |
213 | }, | |
673cd7db | 214 | #endif |
215 | #ifdef SSL_OP_TLS_BLOCK_PADDING_BUG | |
62e76326 | 216 | { |
217 | "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG | |
218 | }, | |
673cd7db | 219 | #endif |
220 | #ifdef SSL_OP_TLS_ROLLBACK_BUG | |
62e76326 | 221 | { |
222 | "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG | |
223 | }, | |
673cd7db | 224 | #endif |
225 | #ifdef SSL_OP_ALL | |
62e76326 | 226 | { |
227 | "ALL", SSL_OP_ALL | |
228 | }, | |
673cd7db | 229 | #endif |
230 | #ifdef SSL_OP_SINGLE_DH_USE | |
62e76326 | 231 | { |
232 | "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE | |
233 | }, | |
673cd7db | 234 | #endif |
235 | #ifdef SSL_OP_EPHEMERAL_RSA | |
62e76326 | 236 | { |
237 | "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA | |
238 | }, | |
673cd7db | 239 | #endif |
240 | #ifdef SSL_OP_PKCS1_CHECK_1 | |
62e76326 | 241 | { |
242 | "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 | |
243 | }, | |
673cd7db | 244 | #endif |
245 | #ifdef SSL_OP_PKCS1_CHECK_2 | |
62e76326 | 246 | { |
247 | "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 | |
248 | }, | |
673cd7db | 249 | #endif |
250 | #ifdef SSL_OP_NETSCAPE_CA_DN_BUG | |
62e76326 | 251 | { |
252 | "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG | |
253 | }, | |
673cd7db | 254 | #endif |
255 | #ifdef SSL_OP_NON_EXPORT_FIRST | |
62e76326 | 256 | { |
257 | "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST | |
258 | }, | |
673cd7db | 259 | #endif |
260 | #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE | |
62e76326 | 261 | { |
262 | "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE | |
263 | }, | |
673cd7db | 264 | #endif |
265 | #ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG | |
62e76326 | 266 | { |
267 | "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG | |
268 | }, | |
673cd7db | 269 | #endif |
270 | #ifdef SSL_OP_NO_SSLv2 | |
62e76326 | 271 | { |
272 | "NO_SSLv2", SSL_OP_NO_SSLv2 | |
273 | }, | |
673cd7db | 274 | #endif |
275 | #ifdef SSL_OP_NO_SSLv3 | |
62e76326 | 276 | { |
277 | "NO_SSLv3", SSL_OP_NO_SSLv3 | |
278 | }, | |
673cd7db | 279 | #endif |
280 | #ifdef SSL_OP_NO_TLSv1 | |
62e76326 | 281 | { |
282 | "NO_TLSv1", SSL_OP_NO_TLSv1 | |
283 | }, | |
673cd7db | 284 | #endif |
62e76326 | 285 | { |
286 | "", 0 | |
287 | }, | |
288 | { | |
289 | NULL, 0 | |
290 | } | |
291 | }; | |
79d4ccdf | 292 | |
84f2d773 | 293 | static long |
79d4ccdf | 294 | ssl_parse_options(const char *options) |
295 | { | |
296 | long op = SSL_OP_ALL; | |
297 | char *tmp; | |
298 | char *option; | |
299 | ||
300 | if (!options) | |
62e76326 | 301 | goto no_options; |
79d4ccdf | 302 | |
303 | tmp = xstrdup(options); | |
62e76326 | 304 | |
79d4ccdf | 305 | option = strtok(tmp, ":,"); |
62e76326 | 306 | |
79d4ccdf | 307 | while (option) { |
62e76326 | 308 | |
309 | struct ssl_option *opt = NULL, *opttmp; | |
310 | long value = 0; | |
311 | enum { | |
312 | MODE_ADD, MODE_REMOVE | |
313 | } mode; | |
314 | ||
315 | switch (*option) { | |
316 | ||
317 | case '!': | |
318 | ||
319 | case '-': | |
320 | mode = MODE_REMOVE; | |
321 | option++; | |
322 | break; | |
323 | ||
324 | case '+': | |
325 | mode = MODE_ADD; | |
326 | option++; | |
327 | break; | |
328 | ||
329 | default: | |
330 | mode = MODE_ADD; | |
331 | break; | |
332 | } | |
333 | ||
334 | for (opttmp = ssl_options; opttmp->name; opttmp++) { | |
335 | if (strcmp(opttmp->name, option) == 0) { | |
336 | opt = opttmp; | |
337 | break; | |
338 | } | |
339 | } | |
340 | ||
341 | if (opt) | |
342 | value = opt->value; | |
343 | else if (strncmp(option, "0x", 2) == 0) { | |
344 | /* Special case.. hex specification */ | |
345 | value = strtol(option + 2, NULL, 16); | |
346 | } else { | |
347 | fatalf("Unknown SSL option '%s'", option); | |
348 | value = 0; /* Keep GCC happy */ | |
349 | } | |
350 | ||
351 | switch (mode) { | |
352 | ||
353 | case MODE_ADD: | |
354 | op |= value; | |
355 | break; | |
356 | ||
357 | case MODE_REMOVE: | |
358 | op &= ~value; | |
359 | break; | |
360 | } | |
361 | ||
362 | option = strtok(NULL, ":,"); | |
79d4ccdf | 363 | } |
364 | ||
365 | safe_free(tmp); | |
62e76326 | 366 | |
367 | no_options: | |
79d4ccdf | 368 | return op; |
369 | } | |
370 | ||
a7ad6e4e | 371 | #define SSL_FLAG_NO_DEFAULT_CA (1<<0) |
372 | #define SSL_FLAG_DELAYED_AUTH (1<<1) | |
373 | #define SSL_FLAG_DONT_VERIFY_PEER (1<<2) | |
374 | #define SSL_FLAG_DONT_VERIFY_DOMAIN (1<<3) | |
375 | ||
376 | static long | |
377 | ssl_parse_flags(const char *flags) | |
378 | { | |
379 | long fl = 0; | |
380 | char *tmp; | |
381 | char *flag; | |
382 | ||
383 | if (!flags) | |
62e76326 | 384 | return 0; |
a7ad6e4e | 385 | |
386 | tmp = xstrdup(flags); | |
62e76326 | 387 | |
a7ad6e4e | 388 | flag = strtok(tmp, ":,"); |
62e76326 | 389 | |
a7ad6e4e | 390 | while (flag) { |
62e76326 | 391 | if (strcmp(flag, "NO_DEFAULT_CA") == 0) |
392 | fl |= SSL_FLAG_NO_DEFAULT_CA; | |
393 | else if (strcmp(flag, "DELAYED_AUTH") == 0) | |
394 | fl |= SSL_FLAG_DELAYED_AUTH; | |
395 | else if (strcmp(flag, "DONT_VERIFY_PEER") == 0) | |
396 | fl |= SSL_FLAG_DONT_VERIFY_PEER; | |
397 | else if (strcmp(flag, "DONT_VERIFY_DOMAIN") == 0) | |
398 | fl |= SSL_FLAG_DONT_VERIFY_DOMAIN; | |
399 | else | |
400 | fatalf("Unknown ssl flag '%s'", flag); | |
401 | ||
402 | flag = strtok(NULL, ":,"); | |
a7ad6e4e | 403 | } |
62e76326 | 404 | |
a7ad6e4e | 405 | safe_free(tmp); |
406 | return fl; | |
407 | } | |
408 | ||
409 | ||
410 | static void | |
411 | ssl_initialize(void) | |
f484cdf5 | 412 | { |
d193a436 | 413 | static int ssl_initialized = 0; |
62e76326 | 414 | |
d193a436 | 415 | if (!ssl_initialized) { |
62e76326 | 416 | ssl_initialized = 1; |
417 | SSL_load_error_strings(); | |
418 | SSLeay_add_ssl_algorithms(); | |
a7ad6e4e | 419 | #ifdef HAVE_OPENSSL_ENGINE_H |
62e76326 | 420 | |
421 | if (Config.SSL.ssl_engine) { | |
422 | ENGINE *e; | |
423 | ||
424 | if (!(e = ENGINE_by_id(Config.SSL.ssl_engine))) { | |
425 | fatalf("Unable to find SSL engine '%s'\n", Config.SSL.ssl_engine); | |
426 | } | |
427 | ||
428 | if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { | |
429 | int ssl_error = ERR_get_error(); | |
430 | fatalf("Failed to initialise SSL engine: %s\n", | |
431 | ERR_error_string(ssl_error, NULL)); | |
432 | } | |
433 | } | |
434 | ||
a7ad6e4e | 435 | #else |
62e76326 | 436 | if (Config.SSL.ssl_engine) { |
437 | fatalf("Your OpenSSL has no SSL engine support\n"); | |
438 | } | |
439 | ||
a7ad6e4e | 440 | #endif |
62e76326 | 441 | |
d193a436 | 442 | } |
62e76326 | 443 | |
a7ad6e4e | 444 | ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", NULL, NULL, NULL); |
445 | ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", NULL, NULL, NULL); | |
446 | ||
447 | } | |
448 | ||
449 | SSL_CTX * | |
35105e4b | 450 | sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *dhfile) |
a7ad6e4e | 451 | { |
452 | int ssl_error; | |
453 | SSL_METHOD *method; | |
454 | SSL_CTX *sslContext; | |
455 | long fl = ssl_parse_flags(flags); | |
456 | ||
457 | ssl_initialize(); | |
458 | ||
f484cdf5 | 459 | if (!keyfile) |
62e76326 | 460 | keyfile = certfile; |
461 | ||
f484cdf5 | 462 | if (!certfile) |
62e76326 | 463 | certfile = keyfile; |
464 | ||
a7ad6e4e | 465 | if (!CAfile) |
62e76326 | 466 | CAfile = clientCA; |
f484cdf5 | 467 | |
79d4ccdf | 468 | switch (version) { |
62e76326 | 469 | |
f484cdf5 | 470 | case 2: |
62e76326 | 471 | debug(83, 5) ("Using SSLv2.\n"); |
472 | method = SSLv2_server_method(); | |
473 | break; | |
474 | ||
f484cdf5 | 475 | case 3: |
62e76326 | 476 | debug(83, 5) ("Using SSLv3.\n"); |
477 | method = SSLv3_server_method(); | |
478 | break; | |
479 | ||
f484cdf5 | 480 | case 4: |
62e76326 | 481 | debug(83, 5) ("Using TLSv1.\n"); |
482 | method = TLSv1_server_method(); | |
483 | break; | |
484 | ||
f484cdf5 | 485 | case 1: |
62e76326 | 486 | |
f484cdf5 | 487 | default: |
62e76326 | 488 | debug(83, 5) ("Using SSLv2/SSLv3.\n"); |
489 | method = SSLv23_server_method(); | |
490 | break; | |
f484cdf5 | 491 | } |
492 | ||
493 | sslContext = SSL_CTX_new(method); | |
62e76326 | 494 | |
f484cdf5 | 495 | if (sslContext == NULL) { |
62e76326 | 496 | ssl_error = ERR_get_error(); |
497 | fatalf("Failed to allocate SSL context: %s\n", | |
498 | ERR_error_string(ssl_error, NULL)); | |
f484cdf5 | 499 | } |
62e76326 | 500 | |
79d4ccdf | 501 | SSL_CTX_set_options(sslContext, ssl_parse_options(options)); |
f484cdf5 | 502 | |
79d4ccdf | 503 | if (cipher) { |
62e76326 | 504 | debug(83, 5) ("Using chiper suite %s.\n", cipher); |
505 | ||
506 | if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { | |
507 | ssl_error = ERR_get_error(); | |
508 | fatalf("Failed to set SSL cipher suite '%s': %s\n", | |
509 | cipher, ERR_error_string(ssl_error, NULL)); | |
510 | } | |
79d4ccdf | 511 | } |
62e76326 | 512 | |
27d8545c | 513 | debug(83, 1) ("Using certificate in %s\n", certfile); |
62e76326 | 514 | |
a7ad6e4e | 515 | if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { |
62e76326 | 516 | ssl_error = ERR_get_error(); |
517 | debug(83, 0) ("Failed to acquire SSL certificate '%s': %s\n", | |
518 | certfile, ERR_error_string(ssl_error, NULL)); | |
519 | goto error; | |
f484cdf5 | 520 | } |
62e76326 | 521 | |
27d8545c | 522 | debug(83, 1) ("Using private key in %s\n", keyfile); |
307b83b7 | 523 | ssl_ask_password(sslContext, keyfile); |
62e76326 | 524 | |
f484cdf5 | 525 | if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { |
62e76326 | 526 | ssl_error = ERR_get_error(); |
527 | debug(83, 0) ("Failed to acquire SSL private key '%s': %s\n", | |
528 | keyfile, ERR_error_string(ssl_error, NULL)); | |
529 | goto error; | |
f484cdf5 | 530 | } |
62e76326 | 531 | |
27d8545c | 532 | debug(83, 5) ("Comparing private and public SSL keys.\n"); |
62e76326 | 533 | |
a7ad6e4e | 534 | if (!SSL_CTX_check_private_key(sslContext)) { |
62e76326 | 535 | ssl_error = ERR_get_error(); |
536 | debug(83, 0) ("SSL private key '%s' does not match public key '%s': %s\n", | |
537 | certfile, keyfile, ERR_error_string(ssl_error, NULL)); | |
538 | goto error; | |
a7ad6e4e | 539 | } |
62e76326 | 540 | |
a7ad6e4e | 541 | debug(83, 9) ("Setting RSA key generation callback.\n"); |
542 | SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); | |
543 | ||
544 | debug(83, 9) ("Setting CA certificate locations.\n"); | |
62e76326 | 545 | |
a7ad6e4e | 546 | if ((!SSL_CTX_load_verify_locations(sslContext, CAfile, CApath))) { |
62e76326 | 547 | ssl_error = ERR_get_error(); |
ac6298a7 | 548 | debug(83, 1) ("Error setting CA certificate locations: %s\n", |
62e76326 | 549 | ERR_error_string(ssl_error, NULL)); |
550 | debug(83, 1) ("continuing anyway...\n"); | |
a7ad6e4e | 551 | } |
62e76326 | 552 | |
a7ad6e4e | 553 | if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && |
62e76326 | 554 | !SSL_CTX_set_default_verify_paths(sslContext)) { |
555 | ssl_error = ERR_get_error(); | |
ac6298a7 | 556 | debug(83, 1) ("Error setting default CA certificate location: %s\n", |
62e76326 | 557 | ERR_error_string(ssl_error, NULL)); |
558 | debug(83, 1) ("continuing anyway...\n"); | |
a7ad6e4e | 559 | } |
62e76326 | 560 | |
a7ad6e4e | 561 | if (clientCA) { |
62e76326 | 562 | debug(83, 9) ("Set client certifying authority list.\n"); |
563 | SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(clientCA)); | |
564 | ||
565 | if (fl & SSL_FLAG_DELAYED_AUTH) { | |
566 | debug(83, 9) ("Not requesting client certificates until acl processing requires one\n"); | |
567 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); | |
568 | } else { | |
569 | debug(83, 9) ("Requiring client certificates.\n"); | |
570 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb); | |
571 | } | |
a7ad6e4e | 572 | } else { |
62e76326 | 573 | debug(83, 9) ("Not requiring any client certificates\n"); |
574 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); | |
a7ad6e4e | 575 | } |
f484cdf5 | 576 | |
35105e4b | 577 | if (dhfile) { |
578 | FILE *in = fopen(dhfile, "r"); | |
579 | DH *dh = NULL; | |
580 | int codes; | |
581 | ||
582 | if (in) { | |
583 | dh = PEM_read_DHparams(in, NULL, NULL, NULL); | |
584 | fclose(in); | |
585 | } | |
586 | ||
587 | if (!dh) | |
588 | debug(83, 1) ("WARNING: Failed to read DH parameters '%s'\n", dhfile); | |
589 | else if (dh && DH_check(dh, &codes) == 0) { | |
590 | if (codes) { | |
591 | debug(83, 1) ("WARNING: Failed to verify DH parameters '%s' (%x)\n", dhfile, codes); | |
592 | DH_free(dh); | |
593 | dh = NULL; | |
594 | } | |
595 | } | |
596 | ||
597 | if (dh) | |
598 | SSL_CTX_set_tmp_dh(sslContext, dh); | |
599 | } | |
600 | ||
a7ad6e4e | 601 | if (fl & SSL_FLAG_DONT_VERIFY_DOMAIN) |
62e76326 | 602 | SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1); |
603 | ||
a7ad6e4e | 604 | return sslContext; |
62e76326 | 605 | |
606 | error: | |
a7ad6e4e | 607 | SSL_CTX_free(sslContext); |
62e76326 | 608 | |
a7ad6e4e | 609 | return NULL; |
610 | } | |
611 | ||
612 | SSL_CTX * | |
613 | sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath) | |
614 | { | |
615 | int ssl_error; | |
616 | SSL_METHOD *method; | |
617 | SSL_CTX *sslContext; | |
618 | long fl = ssl_parse_flags(flags); | |
619 | ||
620 | ssl_initialize(); | |
621 | ||
622 | if (!keyfile) | |
62e76326 | 623 | keyfile = certfile; |
624 | ||
a7ad6e4e | 625 | if (!certfile) |
62e76326 | 626 | certfile = keyfile; |
a7ad6e4e | 627 | |
a7ad6e4e | 628 | switch (version) { |
62e76326 | 629 | |
a7ad6e4e | 630 | case 2: |
62e76326 | 631 | debug(83, 5) ("Using SSLv2.\n"); |
632 | method = SSLv2_client_method(); | |
633 | break; | |
634 | ||
a7ad6e4e | 635 | case 3: |
62e76326 | 636 | debug(83, 5) ("Using SSLv3.\n"); |
637 | method = SSLv3_client_method(); | |
638 | break; | |
639 | ||
a7ad6e4e | 640 | case 4: |
62e76326 | 641 | debug(83, 5) ("Using TLSv1.\n"); |
642 | method = TLSv1_client_method(); | |
643 | break; | |
644 | ||
a7ad6e4e | 645 | case 1: |
62e76326 | 646 | |
a7ad6e4e | 647 | default: |
62e76326 | 648 | debug(83, 5) ("Using SSLv2/SSLv3.\n"); |
649 | method = SSLv23_client_method(); | |
650 | break; | |
a7ad6e4e | 651 | } |
652 | ||
653 | sslContext = SSL_CTX_new(method); | |
62e76326 | 654 | |
a7ad6e4e | 655 | if (sslContext == NULL) { |
62e76326 | 656 | ssl_error = ERR_get_error(); |
657 | fatalf("Failed to allocate SSL context: %s\n", | |
658 | ERR_error_string(ssl_error, NULL)); | |
a7ad6e4e | 659 | } |
62e76326 | 660 | |
a7ad6e4e | 661 | SSL_CTX_set_options(sslContext, ssl_parse_options(options)); |
662 | ||
663 | if (cipher) { | |
62e76326 | 664 | debug(83, 5) ("Using chiper suite %s.\n", cipher); |
665 | ||
666 | if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { | |
667 | ssl_error = ERR_get_error(); | |
668 | fatalf("Failed to set SSL cipher suite '%s': %s\n", | |
669 | cipher, ERR_error_string(ssl_error, NULL)); | |
670 | } | |
a7ad6e4e | 671 | } |
62e76326 | 672 | |
a7ad6e4e | 673 | if (certfile) { |
62e76326 | 674 | debug(83, 1) ("Using certificate in %s\n", certfile); |
675 | ||
676 | if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { | |
677 | ssl_error = ERR_get_error(); | |
678 | fatalf("Failed to acquire SSL certificate '%s': %s\n", | |
679 | certfile, ERR_error_string(ssl_error, NULL)); | |
680 | } | |
681 | ||
682 | debug(83, 1) ("Using private key in %s\n", keyfile); | |
307b83b7 | 683 | ssl_ask_password(sslContext, keyfile); |
62e76326 | 684 | |
685 | if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { | |
686 | ssl_error = ERR_get_error(); | |
687 | fatalf("Failed to acquire SSL private key '%s': %s\n", | |
688 | keyfile, ERR_error_string(ssl_error, NULL)); | |
689 | } | |
690 | ||
691 | debug(83, 5) ("Comparing private and public SSL keys.\n"); | |
692 | ||
693 | if (!SSL_CTX_check_private_key(sslContext)) { | |
694 | ssl_error = ERR_get_error(); | |
695 | fatalf("SSL private key '%s' does not match public key '%s': %s\n", | |
696 | certfile, keyfile, ERR_error_string(ssl_error, NULL)); | |
697 | } | |
a7ad6e4e | 698 | } |
62e76326 | 699 | |
27d8545c | 700 | debug(83, 9) ("Setting RSA key generation callback.\n"); |
f484cdf5 | 701 | SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); |
702 | ||
a7ad6e4e | 703 | if (fl & SSL_FLAG_DONT_VERIFY_PEER) { |
62e76326 | 704 | debug(83, 1) ("NOTICE: Peer certificates are not verified for validity!\n"); |
705 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); | |
a7ad6e4e | 706 | } else { |
62e76326 | 707 | debug(83, 9) ("Setting certificate verification callback.\n"); |
708 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb); | |
a7ad6e4e | 709 | } |
f484cdf5 | 710 | |
a7ad6e4e | 711 | debug(83, 9) ("Setting CA certificate locations.\n"); |
62e76326 | 712 | |
ac6298a7 | 713 | if (CAfile || CApath) |
714 | if ((!SSL_CTX_load_verify_locations(sslContext, CAfile, CApath))) { | |
715 | ssl_error = ERR_get_error(); | |
716 | debug(83, 1) ("Error setting CA certificate locations: %s\n", | |
717 | ERR_error_string(ssl_error, NULL)); | |
718 | debug(83, 1) ("continuing anyway...\n"); | |
719 | } | |
62e76326 | 720 | |
a7ad6e4e | 721 | if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && |
62e76326 | 722 | !SSL_CTX_set_default_verify_paths(sslContext)) { |
723 | ssl_error = ERR_get_error(); | |
ac6298a7 | 724 | debug(83, 1) ("Error setting default CA certificate location: %s\n", |
62e76326 | 725 | ERR_error_string(ssl_error, NULL)); |
726 | debug(83, 1) ("continuing anyway...\n"); | |
f484cdf5 | 727 | } |
62e76326 | 728 | |
d193a436 | 729 | return sslContext; |
f484cdf5 | 730 | } |
731 | ||
d193a436 | 732 | int |
e6ccf245 | 733 | ssl_read_method(int fd, char *buf, int len) |
f484cdf5 | 734 | { |
79d4ccdf | 735 | int i; |
736 | ||
737 | i = SSL_read(fd_table[fd].ssl, buf, len); | |
738 | ||
739 | if (i > 0 && SSL_pending(fd_table[fd].ssl) > 0) { | |
62e76326 | 740 | debug(83, 2) ("SSL fd %d is pending\n", fd); |
741 | fd_table[fd].flags.read_pending = 1; | |
79d4ccdf | 742 | } else |
62e76326 | 743 | fd_table[fd].flags.read_pending = 0; |
79d4ccdf | 744 | |
745 | return i; | |
f484cdf5 | 746 | } |
747 | ||
d193a436 | 748 | int |
e6ccf245 | 749 | ssl_write_method(int fd, const char *buf, int len) |
f484cdf5 | 750 | { |
751 | return (SSL_write(fd_table[fd].ssl, buf, len)); | |
752 | } | |
79d4ccdf | 753 | |
754 | void | |
e6ccf245 | 755 | ssl_shutdown_method(int fd) |
79d4ccdf | 756 | { |
757 | SSL *ssl = fd_table[fd].ssl; | |
62e76326 | 758 | |
79d4ccdf | 759 | if (!fd_table[fd].ssl_shutdown) { |
62e76326 | 760 | fd_table[fd].ssl_shutdown = 1; |
761 | ||
762 | if (Config.SSL.unclean_shutdown) | |
763 | SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); | |
764 | else | |
765 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); | |
79d4ccdf | 766 | } |
62e76326 | 767 | |
79d4ccdf | 768 | SSL_shutdown(ssl); |
769 | } | |
a7ad6e4e | 770 | |
771 | static const char * | |
772 | ssl_get_attribute(X509_NAME * name, const char *attribute_name) | |
773 | { | |
774 | static char buffer[1024]; | |
775 | int nid; | |
776 | ||
777 | buffer[0] = '\0'; | |
778 | ||
779 | if (strcmp(attribute_name, "DN") == 0) { | |
62e76326 | 780 | X509_NAME_oneline(name, buffer, sizeof(buffer)); |
781 | goto done; | |
a7ad6e4e | 782 | } |
62e76326 | 783 | |
a7ad6e4e | 784 | nid = OBJ_txt2nid((char *) attribute_name); |
62e76326 | 785 | |
a7ad6e4e | 786 | if (nid == 0) { |
62e76326 | 787 | debug(83, 1) ("WARNING: Unknown SSL attribute name '%s'\n", attribute_name); |
788 | return NULL; | |
a7ad6e4e | 789 | } |
62e76326 | 790 | |
a7ad6e4e | 791 | X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer)); |
62e76326 | 792 | |
793 | done: | |
a7ad6e4e | 794 | return *buffer ? buffer : NULL; |
795 | } | |
796 | ||
797 | const char * | |
798 | sslGetUserAttribute(SSL * ssl, const char *attribute_name) | |
799 | { | |
800 | X509 *cert; | |
801 | X509_NAME *name; | |
802 | ||
803 | if (!ssl) | |
62e76326 | 804 | return NULL; |
a7ad6e4e | 805 | |
806 | cert = SSL_get_peer_certificate(ssl); | |
62e76326 | 807 | |
a7ad6e4e | 808 | if (!cert) |
62e76326 | 809 | return NULL; |
a7ad6e4e | 810 | |
5a4684b6 | 811 | name = X509_get_subject_name(cert); |
a7ad6e4e | 812 | |
813 | return ssl_get_attribute(name, attribute_name); | |
814 | } | |
815 | ||
816 | const char * | |
817 | sslGetCAAttribute(SSL * ssl, const char *attribute_name) | |
818 | { | |
819 | X509 *cert; | |
820 | X509_NAME *name; | |
821 | ||
822 | if (!ssl) | |
62e76326 | 823 | return NULL; |
a7ad6e4e | 824 | |
825 | cert = SSL_get_peer_certificate(ssl); | |
62e76326 | 826 | |
a7ad6e4e | 827 | if (!cert) |
62e76326 | 828 | return NULL; |
a7ad6e4e | 829 | |
5a4684b6 | 830 | name = X509_get_issuer_name(cert); |
a7ad6e4e | 831 | |
832 | return ssl_get_attribute(name, attribute_name); | |
833 | } | |
834 | ||
a7ad6e4e | 835 | const char * |
836 | sslGetUserEmail(SSL * ssl) | |
837 | { | |
838 | return sslGetUserAttribute(ssl, "Email"); | |
839 | } |