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