]>
Commit | Line | Data |
---|---|---|
f484cdf5 | 1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
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. | |
26ac0430 | 24 | * |
f484cdf5 | 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. | |
26ac0430 | 29 | * |
f484cdf5 | 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" | |
454e8283 | 37 | |
38 | /* MS Visual Studio Projects are monolithic, so we need the following | |
39 | * #if to exclude the SSL code from compile process when not needed. | |
40 | */ | |
41 | #if USE_SSL | |
42 | ||
528b2c61 | 43 | #include "fde.h" |
815eaa44 | 44 | #include "ACLChecklist.h" |
f484cdf5 | 45 | |
63be0a78 | 46 | /** |
47 | \defgroup ServerProtocolSSLInternal Server-Side SSL Internals | |
48 | \ingroup ServerProtocolSSLAPI | |
49 | */ | |
50 | ||
51 | /// \ingroup ServerProtocolSSLInternal | |
307b83b7 | 52 | static int |
53 | ssl_ask_password_cb(char *buf, int size, int rwflag, void *userdata) | |
54 | { | |
55 | FILE *in; | |
56 | int len = 0; | |
57 | char cmdline[1024]; | |
58 | ||
59 | snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", Config.Program.ssl_password, (const char *)userdata); | |
60 | in = popen(cmdline, "r"); | |
61 | ||
62 | if (fgets(buf, size, in)) | |
63 | ||
64 | len = strlen(buf); | |
65 | ||
66 | while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r')) | |
67 | ||
68 | len--; | |
69 | ||
70 | buf[len] = '\0'; | |
71 | ||
72 | pclose(in); | |
73 | ||
74 | return len; | |
75 | } | |
76 | ||
63be0a78 | 77 | /// \ingroup ServerProtocolSSLInternal |
307b83b7 | 78 | static void |
79 | ssl_ask_password(SSL_CTX * context, const char * prompt) | |
80 | { | |
81 | if (Config.Program.ssl_password) { | |
82 | SSL_CTX_set_default_passwd_cb(context, ssl_ask_password_cb); | |
83 | SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt); | |
84 | } | |
85 | } | |
86 | ||
63be0a78 | 87 | /// \ingroup ServerProtocolSSLInternal |
f484cdf5 | 88 | static RSA * |
e6ccf245 | 89 | ssl_temp_rsa_cb(SSL * ssl, int anInt, int keylen) |
f484cdf5 | 90 | { |
e01f02ed | 91 | static RSA *rsa_512 = NULL; |
92 | static RSA *rsa_1024 = NULL; | |
93 | RSA *rsa = NULL; | |
94 | int newkey = 0; | |
f484cdf5 | 95 | |
e01f02ed | 96 | switch (keylen) { |
97 | ||
98 | case 512: | |
99 | ||
100 | if (!rsa_512) { | |
101 | rsa_512 = RSA_generate_key(512, RSA_F4, NULL, NULL); | |
102 | newkey = 1; | |
103 | } | |
104 | ||
105 | rsa = rsa_512; | |
106 | break; | |
107 | ||
108 | case 1024: | |
109 | ||
110 | if (!rsa_1024) { | |
111 | rsa_1024 = RSA_generate_key(1024, RSA_F4, NULL, NULL); | |
112 | newkey = 1; | |
113 | } | |
114 | ||
115 | rsa = rsa_1024; | |
116 | break; | |
117 | ||
118 | default: | |
bf8fe701 | 119 | debugs(83, 1, "ssl_temp_rsa_cb: Unexpected key length " << keylen); |
e01f02ed | 120 | return NULL; |
121 | } | |
122 | ||
123 | if (rsa == NULL) { | |
bf8fe701 | 124 | debugs(83, 1, "ssl_temp_rsa_cb: Failed to generate key " << keylen); |
e01f02ed | 125 | return NULL; |
126 | } | |
127 | ||
128 | if (newkey) { | |
129 | if (do_debug(83, 5)) | |
130 | PEM_write_RSAPrivateKey(debug_log, rsa, NULL, NULL, 0, NULL, NULL); | |
131 | ||
bf8fe701 | 132 | debugs(83, 1, "Generated ephemeral RSA key of length " << keylen); |
e01f02ed | 133 | } |
62e76326 | 134 | |
f484cdf5 | 135 | return rsa; |
136 | } | |
137 | ||
63be0a78 | 138 | /// \ingroup ServerProtocolSSLInternal |
f484cdf5 | 139 | static int |
140 | ssl_verify_cb(int ok, X509_STORE_CTX * ctx) | |
141 | { | |
142 | char buffer[256]; | |
a7ad6e4e | 143 | SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
144 | SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl); | |
145 | const char *server = (const char *)SSL_get_ex_data(ssl, ssl_ex_index_server); | |
146 | void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain); | |
815eaa44 | 147 | ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check); |
a7ad6e4e | 148 | X509 *peer_cert = ctx->cert; |
f484cdf5 | 149 | |
a7ad6e4e | 150 | X509_NAME_oneline(X509_get_subject_name(peer_cert), buffer, |
62e76326 | 151 | sizeof(buffer)); |
a7ad6e4e | 152 | |
153 | if (ok) { | |
bf8fe701 | 154 | debugs(83, 5, "SSL Certificate signature OK: " << buffer); |
62e76326 | 155 | |
156 | if (server) { | |
157 | int i; | |
158 | int found = 0; | |
159 | char cn[1024]; | |
160 | X509_NAME *name = X509_get_subject_name(peer_cert); | |
bf8fe701 | 161 | debugs(83, 3, "Verifying server domain " << server << " to certificate dn " << buffer); |
62e76326 | 162 | |
163 | 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)) { | |
164 | ASN1_STRING *data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); | |
165 | ||
166 | if (data->length > (int)sizeof(cn) - 1) | |
167 | continue; | |
168 | ||
169 | memcpy(cn, data->data, data->length); | |
170 | ||
171 | cn[data->length] = '\0'; | |
172 | ||
bf8fe701 | 173 | debugs(83, 4, "Verifying server domain " << server << " to certificate cn " << cn); |
62e76326 | 174 | |
175 | if (matchDomainName(server, cn[0] == '*' ? cn + 1 : cn) == 0) { | |
176 | found = 1; | |
177 | break; | |
178 | } | |
179 | } | |
180 | ||
181 | if (!found) { | |
815eaa44 | 182 | debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << buffer << " does not match domainname " << server); |
62e76326 | 183 | ok = 0; |
815eaa44 | 184 | if (check) |
185 | check->ssl_error = SQUID_X509_V_ERR_DOMAIN_MISMATCH; | |
62e76326 | 186 | } |
187 | } | |
a7ad6e4e | 188 | } else { |
62e76326 | 189 | switch (ctx->error) { |
190 | ||
191 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
bf8fe701 | 192 | debugs(83, 5, "SSL Certficate error: CA not known: " << buffer); |
62e76326 | 193 | break; |
194 | ||
195 | case X509_V_ERR_CERT_NOT_YET_VALID: | |
bf8fe701 | 196 | debugs(83, 5, "SSL Certficate not yet valid: " << buffer); |
62e76326 | 197 | break; |
198 | ||
199 | case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
bf8fe701 | 200 | debugs(83, 5, "SSL Certificate has illegal \'not before\' field: " << |
201 | buffer); | |
26ac0430 | 202 | |
62e76326 | 203 | break; |
204 | ||
205 | case X509_V_ERR_CERT_HAS_EXPIRED: | |
bf8fe701 | 206 | debugs(83, 5, "SSL Certificate expired: " << buffer); |
62e76326 | 207 | break; |
208 | ||
209 | case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
bf8fe701 | 210 | debugs(83, 5, "SSL Certificate has invalid \'not after\' field: " << buffer); |
62e76326 | 211 | break; |
212 | ||
213 | default: | |
bf8fe701 | 214 | debugs(83, 1, "SSL unknown certificate error " << ctx->error << " in " << buffer); |
62e76326 | 215 | break; |
216 | } | |
815eaa44 | 217 | |
218 | if (check) | |
219 | check->ssl_error = ctx->error; | |
220 | } | |
221 | ||
222 | if (!ok && check) { | |
223 | if (check->fastCheck()) { | |
224 | debugs(83, 3, "bypassing SSL error " << ctx->error << " in " << buffer); | |
225 | ok = 1; | |
226 | } else { | |
227 | debugs(83, 5, "confirming SSL error " << ctx->error); | |
228 | } | |
a7ad6e4e | 229 | } |
62e76326 | 230 | |
26ac0430 | 231 | if (!dont_verify_domain && server) {} |
62e76326 | 232 | |
f484cdf5 | 233 | return ok; |
234 | } | |
235 | ||
63be0a78 | 236 | /// \ingroup ServerProtocolSSLInternal |
26ac0430 | 237 | static struct ssl_option { |
79d4ccdf | 238 | const char *name; |
239 | long value; | |
62e76326 | 240 | } |
241 | ||
242 | ssl_options[] = { | |
79d4ccdf | 243 | |
673cd7db | 244 | #ifdef SSL_OP_MICROSOFT_SESS_ID_BUG |
26ac0430 AJ |
245 | { |
246 | "MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG | |
247 | }, | |
673cd7db | 248 | #endif |
249 | #ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG | |
26ac0430 AJ |
250 | { |
251 | "NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG | |
252 | }, | |
673cd7db | 253 | #endif |
254 | #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | |
26ac0430 AJ |
255 | { |
256 | "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | |
257 | }, | |
673cd7db | 258 | #endif |
259 | #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | |
26ac0430 AJ |
260 | { |
261 | "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | |
262 | }, | |
673cd7db | 263 | #endif |
264 | #ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | |
26ac0430 AJ |
265 | { |
266 | "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | |
267 | }, | |
673cd7db | 268 | #endif |
269 | #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING | |
26ac0430 AJ |
270 | { |
271 | "MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING | |
272 | }, | |
673cd7db | 273 | #endif |
274 | #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG | |
26ac0430 AJ |
275 | { |
276 | "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG | |
277 | }, | |
673cd7db | 278 | #endif |
279 | #ifdef SSL_OP_TLS_D5_BUG | |
26ac0430 AJ |
280 | { |
281 | "TLS_D5_BUG", SSL_OP_TLS_D5_BUG | |
282 | }, | |
673cd7db | 283 | #endif |
284 | #ifdef SSL_OP_TLS_BLOCK_PADDING_BUG | |
26ac0430 AJ |
285 | { |
286 | "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG | |
287 | }, | |
673cd7db | 288 | #endif |
289 | #ifdef SSL_OP_TLS_ROLLBACK_BUG | |
26ac0430 AJ |
290 | { |
291 | "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG | |
292 | }, | |
673cd7db | 293 | #endif |
294 | #ifdef SSL_OP_ALL | |
26ac0430 AJ |
295 | { |
296 | "ALL", SSL_OP_ALL | |
297 | }, | |
673cd7db | 298 | #endif |
299 | #ifdef SSL_OP_SINGLE_DH_USE | |
26ac0430 AJ |
300 | { |
301 | "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE | |
302 | }, | |
673cd7db | 303 | #endif |
304 | #ifdef SSL_OP_EPHEMERAL_RSA | |
26ac0430 AJ |
305 | { |
306 | "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA | |
307 | }, | |
673cd7db | 308 | #endif |
309 | #ifdef SSL_OP_PKCS1_CHECK_1 | |
26ac0430 AJ |
310 | { |
311 | "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 | |
312 | }, | |
673cd7db | 313 | #endif |
314 | #ifdef SSL_OP_PKCS1_CHECK_2 | |
26ac0430 AJ |
315 | { |
316 | "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 | |
317 | }, | |
673cd7db | 318 | #endif |
319 | #ifdef SSL_OP_NETSCAPE_CA_DN_BUG | |
26ac0430 AJ |
320 | { |
321 | "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG | |
322 | }, | |
673cd7db | 323 | #endif |
324 | #ifdef SSL_OP_NON_EXPORT_FIRST | |
26ac0430 AJ |
325 | { |
326 | "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST | |
327 | }, | |
673cd7db | 328 | #endif |
329 | #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE | |
26ac0430 AJ |
330 | { |
331 | "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE | |
332 | }, | |
673cd7db | 333 | #endif |
334 | #ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG | |
26ac0430 AJ |
335 | { |
336 | "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG | |
337 | }, | |
673cd7db | 338 | #endif |
339 | #ifdef SSL_OP_NO_SSLv2 | |
26ac0430 AJ |
340 | { |
341 | "NO_SSLv2", SSL_OP_NO_SSLv2 | |
342 | }, | |
673cd7db | 343 | #endif |
344 | #ifdef SSL_OP_NO_SSLv3 | |
26ac0430 AJ |
345 | { |
346 | "NO_SSLv3", SSL_OP_NO_SSLv3 | |
347 | }, | |
673cd7db | 348 | #endif |
349 | #ifdef SSL_OP_NO_TLSv1 | |
26ac0430 AJ |
350 | { |
351 | "NO_TLSv1", SSL_OP_NO_TLSv1 | |
352 | }, | |
673cd7db | 353 | #endif |
26ac0430 AJ |
354 | { |
355 | "", 0 | |
356 | }, | |
357 | { | |
358 | NULL, 0 | |
359 | } | |
360 | }; | |
79d4ccdf | 361 | |
63be0a78 | 362 | /// \ingroup ServerProtocolSSLInternal |
84f2d773 | 363 | static long |
79d4ccdf | 364 | ssl_parse_options(const char *options) |
365 | { | |
366 | long op = SSL_OP_ALL; | |
367 | char *tmp; | |
368 | char *option; | |
369 | ||
370 | if (!options) | |
62e76326 | 371 | goto no_options; |
79d4ccdf | 372 | |
373 | tmp = xstrdup(options); | |
62e76326 | 374 | |
79d4ccdf | 375 | option = strtok(tmp, ":,"); |
62e76326 | 376 | |
79d4ccdf | 377 | while (option) { |
62e76326 | 378 | |
379 | struct ssl_option *opt = NULL, *opttmp; | |
380 | long value = 0; | |
381 | enum { | |
382 | MODE_ADD, MODE_REMOVE | |
383 | } mode; | |
384 | ||
385 | switch (*option) { | |
386 | ||
387 | case '!': | |
388 | ||
389 | case '-': | |
390 | mode = MODE_REMOVE; | |
391 | option++; | |
392 | break; | |
393 | ||
394 | case '+': | |
395 | mode = MODE_ADD; | |
396 | option++; | |
397 | break; | |
398 | ||
399 | default: | |
400 | mode = MODE_ADD; | |
401 | break; | |
402 | } | |
403 | ||
404 | for (opttmp = ssl_options; opttmp->name; opttmp++) { | |
405 | if (strcmp(opttmp->name, option) == 0) { | |
406 | opt = opttmp; | |
407 | break; | |
408 | } | |
409 | } | |
410 | ||
411 | if (opt) | |
412 | value = opt->value; | |
413 | else if (strncmp(option, "0x", 2) == 0) { | |
414 | /* Special case.. hex specification */ | |
415 | value = strtol(option + 2, NULL, 16); | |
416 | } else { | |
417 | fatalf("Unknown SSL option '%s'", option); | |
418 | value = 0; /* Keep GCC happy */ | |
419 | } | |
420 | ||
421 | switch (mode) { | |
422 | ||
423 | case MODE_ADD: | |
424 | op |= value; | |
425 | break; | |
426 | ||
427 | case MODE_REMOVE: | |
428 | op &= ~value; | |
429 | break; | |
430 | } | |
431 | ||
432 | option = strtok(NULL, ":,"); | |
79d4ccdf | 433 | } |
434 | ||
435 | safe_free(tmp); | |
62e76326 | 436 | |
437 | no_options: | |
79d4ccdf | 438 | return op; |
439 | } | |
440 | ||
63be0a78 | 441 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 442 | #define SSL_FLAG_NO_DEFAULT_CA (1<<0) |
63be0a78 | 443 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 444 | #define SSL_FLAG_DELAYED_AUTH (1<<1) |
63be0a78 | 445 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 446 | #define SSL_FLAG_DONT_VERIFY_PEER (1<<2) |
63be0a78 | 447 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 448 | #define SSL_FLAG_DONT_VERIFY_DOMAIN (1<<3) |
63be0a78 | 449 | /// \ingroup ServerProtocolSSLInternal |
b13877cc | 450 | #define SSL_FLAG_NO_SESSION_REUSE (1<<4) |
63be0a78 | 451 | /// \ingroup ServerProtocolSSLInternal |
a82a4fe4 | 452 | #define SSL_FLAG_VERIFY_CRL (1<<5) |
63be0a78 | 453 | /// \ingroup ServerProtocolSSLInternal |
a82a4fe4 | 454 | #define SSL_FLAG_VERIFY_CRL_ALL (1<<6) |
a7ad6e4e | 455 | |
63be0a78 | 456 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 457 | static long |
458 | ssl_parse_flags(const char *flags) | |
459 | { | |
460 | long fl = 0; | |
461 | char *tmp; | |
462 | char *flag; | |
463 | ||
464 | if (!flags) | |
62e76326 | 465 | return 0; |
a7ad6e4e | 466 | |
467 | tmp = xstrdup(flags); | |
62e76326 | 468 | |
a7ad6e4e | 469 | flag = strtok(tmp, ":,"); |
62e76326 | 470 | |
a7ad6e4e | 471 | while (flag) { |
62e76326 | 472 | if (strcmp(flag, "NO_DEFAULT_CA") == 0) |
473 | fl |= SSL_FLAG_NO_DEFAULT_CA; | |
474 | else if (strcmp(flag, "DELAYED_AUTH") == 0) | |
475 | fl |= SSL_FLAG_DELAYED_AUTH; | |
476 | else if (strcmp(flag, "DONT_VERIFY_PEER") == 0) | |
477 | fl |= SSL_FLAG_DONT_VERIFY_PEER; | |
478 | else if (strcmp(flag, "DONT_VERIFY_DOMAIN") == 0) | |
479 | fl |= SSL_FLAG_DONT_VERIFY_DOMAIN; | |
b13877cc | 480 | else if (strcmp(flag, "NO_SESSION_REUSE") == 0) |
481 | fl |= SSL_FLAG_NO_SESSION_REUSE; | |
a82a4fe4 | 482 | |
483 | #ifdef X509_V_FLAG_CRL_CHECK | |
484 | ||
485 | else if (strcmp(flag, "VERIFY_CRL") == 0) | |
486 | fl |= SSL_FLAG_VERIFY_CRL; | |
487 | else if (strcmp(flag, "VERIFY_CRL_ALL") == 0) | |
488 | fl |= SSL_FLAG_VERIFY_CRL_ALL; | |
489 | ||
490 | #endif | |
491 | ||
62e76326 | 492 | else |
493 | fatalf("Unknown ssl flag '%s'", flag); | |
494 | ||
495 | flag = strtok(NULL, ":,"); | |
a7ad6e4e | 496 | } |
62e76326 | 497 | |
a7ad6e4e | 498 | safe_free(tmp); |
499 | return fl; | |
500 | } | |
501 | ||
26ac0430 | 502 | struct SslErrorMapEntry { |
815eaa44 | 503 | const char *name; |
504 | ssl_error_t value; | |
505 | }; | |
506 | ||
507 | static SslErrorMapEntry TheSslErrorMap[] = { | |
508 | { "SQUID_X509_V_ERR_DOMAIN_MISMATCH", SQUID_X509_V_ERR_DOMAIN_MISMATCH }, | |
509 | { "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT", X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT }, | |
510 | { "X509_V_ERR_CERT_NOT_YET_VALID", X509_V_ERR_CERT_NOT_YET_VALID }, | |
511 | { "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD", X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD }, | |
512 | { "X509_V_ERR_CERT_HAS_EXPIRED", X509_V_ERR_CERT_HAS_EXPIRED }, | |
513 | { "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD", X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD }, | |
514 | { "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY", X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY }, | |
515 | { "SSL_ERROR_NONE", SSL_ERROR_NONE }, | |
516 | { NULL, SSL_ERROR_NONE } | |
517 | }; | |
518 | ||
519 | ssl_error_t | |
520 | sslParseErrorString(const char *name) | |
521 | { | |
522 | assert(name); | |
523 | ||
524 | for (int i = 0; TheSslErrorMap[i].name; ++i) { | |
525 | if (strcmp(name, TheSslErrorMap[i].name) == 0) | |
526 | return TheSslErrorMap[i].value; | |
527 | } | |
528 | ||
529 | if (xisdigit(*name)) { | |
530 | const long int value = strtol(name, NULL, 0); | |
531 | if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX) | |
532 | return value; | |
533 | fatalf("Too small or too bug SSL error code '%s'", name); | |
534 | } | |
535 | ||
536 | fatalf("Unknown SSL error name '%s'", name); | |
537 | return SSL_ERROR_SSL; // not reached | |
538 | } | |
539 | ||
540 | const char * | |
541 | sslFindErrorString(ssl_error_t value) | |
542 | { | |
543 | for (int i = 0; TheSslErrorMap[i].name; ++i) { | |
544 | if (TheSslErrorMap[i].value == value) | |
545 | return TheSslErrorMap[i].name; | |
546 | } | |
547 | ||
548 | return NULL; | |
549 | } | |
550 | ||
551 | // "dup" function for SSL_get_ex_new_index("cert_err_check") | |
552 | static int | |
553 | ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *, | |
26ac0430 AJ |
554 | int, long, void *) |
555 | { | |
815eaa44 | 556 | // We do not support duplication of ACLCheckLists. |
557 | // If duplication is needed, we can count copies with cbdata. | |
558 | assert(false); | |
559 | return 0; | |
560 | } | |
561 | ||
562 | // "free" function for SSL_get_ex_new_index("cert_err_check") | |
563 | static void | |
564 | ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *, | |
26ac0430 AJ |
565 | int, long, void *) |
566 | { | |
815eaa44 | 567 | delete static_cast<ACLChecklist *>(ptr); // may be NULL |
568 | } | |
a7ad6e4e | 569 | |
63be0a78 | 570 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 571 | static void |
572 | ssl_initialize(void) | |
f484cdf5 | 573 | { |
d193a436 | 574 | static int ssl_initialized = 0; |
62e76326 | 575 | |
d193a436 | 576 | if (!ssl_initialized) { |
62e76326 | 577 | ssl_initialized = 1; |
578 | SSL_load_error_strings(); | |
579 | SSLeay_add_ssl_algorithms(); | |
a7ad6e4e | 580 | #ifdef HAVE_OPENSSL_ENGINE_H |
62e76326 | 581 | |
582 | if (Config.SSL.ssl_engine) { | |
583 | ENGINE *e; | |
584 | ||
585 | if (!(e = ENGINE_by_id(Config.SSL.ssl_engine))) { | |
586 | fatalf("Unable to find SSL engine '%s'\n", Config.SSL.ssl_engine); | |
587 | } | |
588 | ||
589 | if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { | |
590 | int ssl_error = ERR_get_error(); | |
591 | fatalf("Failed to initialise SSL engine: %s\n", | |
592 | ERR_error_string(ssl_error, NULL)); | |
593 | } | |
594 | } | |
595 | ||
a7ad6e4e | 596 | #else |
62e76326 | 597 | if (Config.SSL.ssl_engine) { |
598 | fatalf("Your OpenSSL has no SSL engine support\n"); | |
599 | } | |
600 | ||
a7ad6e4e | 601 | #endif |
62e76326 | 602 | |
d193a436 | 603 | } |
62e76326 | 604 | |
a7ad6e4e | 605 | ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", NULL, NULL, NULL); |
606 | ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", NULL, NULL, NULL); | |
815eaa44 | 607 | ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", NULL, &ssl_dupAclChecklist, &ssl_freeAclChecklist); |
a7ad6e4e | 608 | } |
609 | ||
63be0a78 | 610 | /// \ingroup ServerProtocolSSLInternal |
a82a4fe4 | 611 | static int |
612 | ssl_load_crl(SSL_CTX *sslContext, const char *CRLfile) | |
613 | { | |
614 | X509_STORE *st = SSL_CTX_get_cert_store(sslContext); | |
615 | X509_CRL *crl; | |
616 | BIO *in = BIO_new_file(CRLfile, "r"); | |
617 | int count = 0; | |
618 | ||
619 | if (!in) { | |
bf8fe701 | 620 | debugs(83, 2, "WARNING: Failed to open CRL file '" << CRLfile << "'"); |
a82a4fe4 | 621 | return 0; |
622 | } | |
623 | ||
624 | while ((crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL))) { | |
625 | if (!X509_STORE_add_crl(st, crl)) | |
bf8fe701 | 626 | debugs(83, 2, "WARNING: Failed to add CRL from file '" << CRLfile << "'"); |
a82a4fe4 | 627 | else |
628 | count++; | |
629 | ||
630 | X509_CRL_free(crl); | |
631 | } | |
632 | ||
633 | BIO_free(in); | |
634 | return count; | |
635 | } | |
636 | ||
a7ad6e4e | 637 | SSL_CTX * |
a82a4fe4 | 638 | 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 *CRLfile, const char *dhfile, const char *context) |
a7ad6e4e | 639 | { |
640 | int ssl_error; | |
641 | SSL_METHOD *method; | |
642 | SSL_CTX *sslContext; | |
643 | long fl = ssl_parse_flags(flags); | |
644 | ||
645 | ssl_initialize(); | |
646 | ||
f484cdf5 | 647 | if (!keyfile) |
62e76326 | 648 | keyfile = certfile; |
649 | ||
f484cdf5 | 650 | if (!certfile) |
62e76326 | 651 | certfile = keyfile; |
652 | ||
a7ad6e4e | 653 | if (!CAfile) |
62e76326 | 654 | CAfile = clientCA; |
f484cdf5 | 655 | |
79d4ccdf | 656 | switch (version) { |
62e76326 | 657 | |
f484cdf5 | 658 | case 2: |
bf8fe701 | 659 | debugs(83, 5, "Using SSLv2."); |
62e76326 | 660 | method = SSLv2_server_method(); |
661 | break; | |
662 | ||
f484cdf5 | 663 | case 3: |
bf8fe701 | 664 | debugs(83, 5, "Using SSLv3."); |
62e76326 | 665 | method = SSLv3_server_method(); |
666 | break; | |
667 | ||
f484cdf5 | 668 | case 4: |
bf8fe701 | 669 | debugs(83, 5, "Using TLSv1."); |
62e76326 | 670 | method = TLSv1_server_method(); |
671 | break; | |
672 | ||
f484cdf5 | 673 | case 1: |
62e76326 | 674 | |
f484cdf5 | 675 | default: |
bf8fe701 | 676 | debugs(83, 5, "Using SSLv2/SSLv3."); |
62e76326 | 677 | method = SSLv23_server_method(); |
678 | break; | |
f484cdf5 | 679 | } |
680 | ||
681 | sslContext = SSL_CTX_new(method); | |
62e76326 | 682 | |
f484cdf5 | 683 | if (sslContext == NULL) { |
62e76326 | 684 | ssl_error = ERR_get_error(); |
685 | fatalf("Failed to allocate SSL context: %s\n", | |
686 | ERR_error_string(ssl_error, NULL)); | |
f484cdf5 | 687 | } |
62e76326 | 688 | |
79d4ccdf | 689 | SSL_CTX_set_options(sslContext, ssl_parse_options(options)); |
f484cdf5 | 690 | |
6b2936d5 | 691 | if (context && *context) { |
3de409f0 | 692 | SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)context, strlen(context)); |
6b2936d5 | 693 | } |
694 | ||
b13877cc | 695 | if (fl & SSL_FLAG_NO_SESSION_REUSE) { |
696 | SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF); | |
697 | } | |
698 | ||
a9d79803 | 699 | if (Config.SSL.unclean_shutdown) { |
bf8fe701 | 700 | debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation)."); |
a9d79803 | 701 | |
702 | SSL_CTX_set_quiet_shutdown(sslContext, 1); | |
703 | } | |
704 | ||
79d4ccdf | 705 | if (cipher) { |
bf8fe701 | 706 | debugs(83, 5, "Using chiper suite " << cipher << "."); |
62e76326 | 707 | |
708 | if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { | |
709 | ssl_error = ERR_get_error(); | |
710 | fatalf("Failed to set SSL cipher suite '%s': %s\n", | |
711 | cipher, ERR_error_string(ssl_error, NULL)); | |
712 | } | |
79d4ccdf | 713 | } |
62e76326 | 714 | |
bf8fe701 | 715 | debugs(83, 1, "Using certificate in " << certfile); |
62e76326 | 716 | |
a7ad6e4e | 717 | if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { |
62e76326 | 718 | ssl_error = ERR_get_error(); |
bf8fe701 | 719 | debugs(83, 0, "Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL) ); |
62e76326 | 720 | goto error; |
f484cdf5 | 721 | } |
62e76326 | 722 | |
bf8fe701 | 723 | debugs(83, 1, "Using private key in " << keyfile); |
307b83b7 | 724 | ssl_ask_password(sslContext, keyfile); |
62e76326 | 725 | |
f484cdf5 | 726 | if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { |
62e76326 | 727 | ssl_error = ERR_get_error(); |
bf8fe701 | 728 | debugs(83, 0, "Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL) ); |
62e76326 | 729 | goto error; |
f484cdf5 | 730 | } |
62e76326 | 731 | |
bf8fe701 | 732 | debugs(83, 5, "Comparing private and public SSL keys."); |
62e76326 | 733 | |
a7ad6e4e | 734 | if (!SSL_CTX_check_private_key(sslContext)) { |
62e76326 | 735 | ssl_error = ERR_get_error(); |
26ac0430 | 736 | debugs(83, 0, "SSL private key '" << |
bf8fe701 | 737 | certfile << "' does not match public key '" << |
738 | keyfile << "': " << ERR_error_string(ssl_error, NULL) ); | |
62e76326 | 739 | goto error; |
a7ad6e4e | 740 | } |
62e76326 | 741 | |
bf8fe701 | 742 | debugs(83, 9, "Setting RSA key generation callback."); |
a7ad6e4e | 743 | SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); |
744 | ||
bf8fe701 | 745 | debugs(83, 9, "Setting CA certificate locations."); |
62e76326 | 746 | |
a82a4fe4 | 747 | if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) { |
62e76326 | 748 | ssl_error = ERR_get_error(); |
bf8fe701 | 749 | debugs(83, 1, "Error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL) ); |
750 | debugs(83, 1, "continuing anyway..." ); | |
a7ad6e4e | 751 | } |
62e76326 | 752 | |
a7ad6e4e | 753 | if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && |
62e76326 | 754 | !SSL_CTX_set_default_verify_paths(sslContext)) { |
755 | ssl_error = ERR_get_error(); | |
bf8fe701 | 756 | debugs(83, 1, "Error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL) ); |
757 | debugs(83, 1, "continuing anyway..." ); | |
a7ad6e4e | 758 | } |
62e76326 | 759 | |
a7ad6e4e | 760 | if (clientCA) { |
8c1ff4ef | 761 | STACK_OF(X509_NAME) *cert_names; |
bf8fe701 | 762 | debugs(83, 9, "Set client certifying authority list."); |
8c1ff4ef | 763 | cert_names = SSL_load_client_CA_file(clientCA); |
764 | ||
765 | if (cert_names == NULL) { | |
26ac0430 | 766 | debugs(83, 1, "Error loading the client CA certificates from '" << clientCA << "\': " << ERR_error_string(ERR_get_error(),NULL) ); |
8c1ff4ef | 767 | goto error; |
768 | } | |
769 | ||
770 | ERR_clear_error(); | |
771 | SSL_CTX_set_client_CA_list(sslContext, cert_names); | |
62e76326 | 772 | |
773 | if (fl & SSL_FLAG_DELAYED_AUTH) { | |
bf8fe701 | 774 | debugs(83, 9, "Not requesting client certificates until acl processing requires one"); |
62e76326 | 775 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); |
776 | } else { | |
bf8fe701 | 777 | debugs(83, 9, "Requiring client certificates."); |
62e76326 | 778 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb); |
779 | } | |
a82a4fe4 | 780 | |
781 | if (CRLfile) { | |
782 | ssl_load_crl(sslContext, CRLfile); | |
783 | fl |= SSL_FLAG_VERIFY_CRL; | |
784 | } | |
785 | ||
786 | #ifdef X509_V_FLAG_CRL_CHECK | |
787 | if (fl & SSL_FLAG_VERIFY_CRL_ALL) | |
788 | X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); | |
789 | else if (fl & SSL_FLAG_VERIFY_CRL) | |
790 | X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK); | |
791 | ||
792 | #endif | |
793 | ||
a7ad6e4e | 794 | } else { |
bf8fe701 | 795 | debugs(83, 9, "Not requiring any client certificates"); |
62e76326 | 796 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); |
a7ad6e4e | 797 | } |
f484cdf5 | 798 | |
35105e4b | 799 | if (dhfile) { |
800 | FILE *in = fopen(dhfile, "r"); | |
801 | DH *dh = NULL; | |
802 | int codes; | |
803 | ||
804 | if (in) { | |
805 | dh = PEM_read_DHparams(in, NULL, NULL, NULL); | |
806 | fclose(in); | |
807 | } | |
808 | ||
809 | if (!dh) | |
bf8fe701 | 810 | debugs(83, 1, "WARNING: Failed to read DH parameters '" << dhfile << "'"); |
35105e4b | 811 | else if (dh && DH_check(dh, &codes) == 0) { |
812 | if (codes) { | |
bf8fe701 | 813 | debugs(83, 1, "WARNING: Failed to verify DH parameters '" << dhfile << "' (" << std::hex << codes << ")"); |
35105e4b | 814 | DH_free(dh); |
815 | dh = NULL; | |
816 | } | |
817 | } | |
818 | ||
819 | if (dh) | |
820 | SSL_CTX_set_tmp_dh(sslContext, dh); | |
821 | } | |
822 | ||
a7ad6e4e | 823 | if (fl & SSL_FLAG_DONT_VERIFY_DOMAIN) |
62e76326 | 824 | SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1); |
825 | ||
a7ad6e4e | 826 | return sslContext; |
62e76326 | 827 | |
828 | error: | |
a7ad6e4e | 829 | SSL_CTX_free(sslContext); |
62e76326 | 830 | |
a7ad6e4e | 831 | return NULL; |
832 | } | |
833 | ||
834 | SSL_CTX * | |
a82a4fe4 | 835 | sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) |
a7ad6e4e | 836 | { |
837 | int ssl_error; | |
838 | SSL_METHOD *method; | |
839 | SSL_CTX *sslContext; | |
840 | long fl = ssl_parse_flags(flags); | |
841 | ||
842 | ssl_initialize(); | |
843 | ||
844 | if (!keyfile) | |
62e76326 | 845 | keyfile = certfile; |
846 | ||
a7ad6e4e | 847 | if (!certfile) |
62e76326 | 848 | certfile = keyfile; |
a7ad6e4e | 849 | |
a7ad6e4e | 850 | switch (version) { |
62e76326 | 851 | |
a7ad6e4e | 852 | case 2: |
bf8fe701 | 853 | debugs(83, 5, "Using SSLv2."); |
62e76326 | 854 | method = SSLv2_client_method(); |
855 | break; | |
856 | ||
a7ad6e4e | 857 | case 3: |
bf8fe701 | 858 | debugs(83, 5, "Using SSLv3."); |
62e76326 | 859 | method = SSLv3_client_method(); |
860 | break; | |
861 | ||
a7ad6e4e | 862 | case 4: |
bf8fe701 | 863 | debugs(83, 5, "Using TLSv1."); |
62e76326 | 864 | method = TLSv1_client_method(); |
865 | break; | |
866 | ||
a7ad6e4e | 867 | case 1: |
62e76326 | 868 | |
a7ad6e4e | 869 | default: |
bf8fe701 | 870 | debugs(83, 5, "Using SSLv2/SSLv3."); |
62e76326 | 871 | method = SSLv23_client_method(); |
872 | break; | |
a7ad6e4e | 873 | } |
874 | ||
875 | sslContext = SSL_CTX_new(method); | |
62e76326 | 876 | |
a7ad6e4e | 877 | if (sslContext == NULL) { |
62e76326 | 878 | ssl_error = ERR_get_error(); |
879 | fatalf("Failed to allocate SSL context: %s\n", | |
880 | ERR_error_string(ssl_error, NULL)); | |
a7ad6e4e | 881 | } |
62e76326 | 882 | |
a7ad6e4e | 883 | SSL_CTX_set_options(sslContext, ssl_parse_options(options)); |
884 | ||
885 | if (cipher) { | |
bf8fe701 | 886 | debugs(83, 5, "Using chiper suite " << cipher << "."); |
62e76326 | 887 | |
888 | if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { | |
889 | ssl_error = ERR_get_error(); | |
890 | fatalf("Failed to set SSL cipher suite '%s': %s\n", | |
891 | cipher, ERR_error_string(ssl_error, NULL)); | |
892 | } | |
a7ad6e4e | 893 | } |
62e76326 | 894 | |
a7ad6e4e | 895 | if (certfile) { |
bf8fe701 | 896 | debugs(83, 1, "Using certificate in " << certfile); |
62e76326 | 897 | |
898 | if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { | |
899 | ssl_error = ERR_get_error(); | |
900 | fatalf("Failed to acquire SSL certificate '%s': %s\n", | |
901 | certfile, ERR_error_string(ssl_error, NULL)); | |
902 | } | |
903 | ||
bf8fe701 | 904 | debugs(83, 1, "Using private key in " << keyfile); |
307b83b7 | 905 | ssl_ask_password(sslContext, keyfile); |
62e76326 | 906 | |
907 | if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { | |
908 | ssl_error = ERR_get_error(); | |
909 | fatalf("Failed to acquire SSL private key '%s': %s\n", | |
910 | keyfile, ERR_error_string(ssl_error, NULL)); | |
911 | } | |
912 | ||
bf8fe701 | 913 | debugs(83, 5, "Comparing private and public SSL keys."); |
62e76326 | 914 | |
915 | if (!SSL_CTX_check_private_key(sslContext)) { | |
916 | ssl_error = ERR_get_error(); | |
917 | fatalf("SSL private key '%s' does not match public key '%s': %s\n", | |
918 | certfile, keyfile, ERR_error_string(ssl_error, NULL)); | |
919 | } | |
a7ad6e4e | 920 | } |
62e76326 | 921 | |
bf8fe701 | 922 | debugs(83, 9, "Setting RSA key generation callback."); |
f484cdf5 | 923 | SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); |
924 | ||
a7ad6e4e | 925 | if (fl & SSL_FLAG_DONT_VERIFY_PEER) { |
bf8fe701 | 926 | debugs(83, 1, "NOTICE: Peer certificates are not verified for validity!"); |
62e76326 | 927 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); |
a7ad6e4e | 928 | } else { |
bf8fe701 | 929 | debugs(83, 9, "Setting certificate verification callback."); |
62e76326 | 930 | SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb); |
a7ad6e4e | 931 | } |
f484cdf5 | 932 | |
bf8fe701 | 933 | debugs(83, 9, "Setting CA certificate locations."); |
62e76326 | 934 | |
a82a4fe4 | 935 | if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) { |
936 | ssl_error = ERR_get_error(); | |
bf8fe701 | 937 | debugs(83, 1, "Error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL)); |
938 | debugs(83, 1, "continuing anyway..." ); | |
a82a4fe4 | 939 | } |
940 | ||
941 | if (CRLfile) { | |
942 | ssl_load_crl(sslContext, CRLfile); | |
943 | fl |= SSL_FLAG_VERIFY_CRL; | |
944 | } | |
945 | ||
946 | #ifdef X509_V_FLAG_CRL_CHECK | |
947 | if (fl & SSL_FLAG_VERIFY_CRL_ALL) | |
948 | X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); | |
949 | else if (fl & SSL_FLAG_VERIFY_CRL) | |
950 | X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK); | |
951 | ||
952 | #endif | |
62e76326 | 953 | |
a7ad6e4e | 954 | if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && |
62e76326 | 955 | !SSL_CTX_set_default_verify_paths(sslContext)) { |
956 | ssl_error = ERR_get_error(); | |
bf8fe701 | 957 | debugs(83, 1, "Error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL) ); |
958 | debugs(83, 1, "continuing anyway..."); | |
f484cdf5 | 959 | } |
62e76326 | 960 | |
d193a436 | 961 | return sslContext; |
f484cdf5 | 962 | } |
963 | ||
63be0a78 | 964 | /// \ingroup ServerProtocolSSLInternal |
d193a436 | 965 | int |
e6ccf245 | 966 | ssl_read_method(int fd, char *buf, int len) |
f484cdf5 | 967 | { |
6de9e64b | 968 | SSL *ssl = fd_table[fd].ssl; |
79d4ccdf | 969 | int i; |
970 | ||
6de9e64b | 971 | #if DONT_DO_THIS |
972 | ||
973 | if (!SSL_is_init_finished(ssl)) { | |
974 | errno = ENOTCONN; | |
975 | return -1; | |
976 | } | |
79d4ccdf | 977 | |
6de9e64b | 978 | #endif |
979 | ||
980 | i = SSL_read(ssl, buf, len); | |
981 | ||
982 | if (i > 0 && SSL_pending(ssl) > 0) { | |
bf8fe701 | 983 | debugs(83, 2, "SSL FD " << fd << " is pending"); |
62e76326 | 984 | fd_table[fd].flags.read_pending = 1; |
79d4ccdf | 985 | } else |
62e76326 | 986 | fd_table[fd].flags.read_pending = 0; |
79d4ccdf | 987 | |
988 | return i; | |
f484cdf5 | 989 | } |
990 | ||
63be0a78 | 991 | /// \ingroup ServerProtocolSSLInternal |
d193a436 | 992 | int |
e6ccf245 | 993 | ssl_write_method(int fd, const char *buf, int len) |
f484cdf5 | 994 | { |
6de9e64b | 995 | SSL *ssl = fd_table[fd].ssl; |
996 | int i; | |
997 | ||
998 | if (!SSL_is_init_finished(ssl)) { | |
999 | errno = ENOTCONN; | |
1000 | return -1; | |
1001 | } | |
1002 | ||
1003 | i = SSL_write(ssl, buf, len); | |
1004 | ||
1005 | return i; | |
f484cdf5 | 1006 | } |
79d4ccdf | 1007 | |
1008 | void | |
e6ccf245 | 1009 | ssl_shutdown_method(int fd) |
79d4ccdf | 1010 | { |
1011 | SSL *ssl = fd_table[fd].ssl; | |
62e76326 | 1012 | |
79d4ccdf | 1013 | SSL_shutdown(ssl); |
1014 | } | |
a7ad6e4e | 1015 | |
63be0a78 | 1016 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 1017 | static const char * |
1018 | ssl_get_attribute(X509_NAME * name, const char *attribute_name) | |
1019 | { | |
1020 | static char buffer[1024]; | |
1021 | int nid; | |
1022 | ||
1023 | buffer[0] = '\0'; | |
1024 | ||
1025 | if (strcmp(attribute_name, "DN") == 0) { | |
62e76326 | 1026 | X509_NAME_oneline(name, buffer, sizeof(buffer)); |
1027 | goto done; | |
a7ad6e4e | 1028 | } |
62e76326 | 1029 | |
a7ad6e4e | 1030 | nid = OBJ_txt2nid((char *) attribute_name); |
62e76326 | 1031 | |
a7ad6e4e | 1032 | if (nid == 0) { |
bf8fe701 | 1033 | debugs(83, 1, "WARNING: Unknown SSL attribute name '" << attribute_name << "'"); |
62e76326 | 1034 | return NULL; |
a7ad6e4e | 1035 | } |
62e76326 | 1036 | |
a7ad6e4e | 1037 | X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer)); |
62e76326 | 1038 | |
1039 | done: | |
a7ad6e4e | 1040 | return *buffer ? buffer : NULL; |
1041 | } | |
1042 | ||
63be0a78 | 1043 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 1044 | const char * |
1045 | sslGetUserAttribute(SSL * ssl, const char *attribute_name) | |
1046 | { | |
1047 | X509 *cert; | |
1048 | X509_NAME *name; | |
23e6c4ae | 1049 | const char *ret; |
a7ad6e4e | 1050 | |
1051 | if (!ssl) | |
62e76326 | 1052 | return NULL; |
a7ad6e4e | 1053 | |
1054 | cert = SSL_get_peer_certificate(ssl); | |
62e76326 | 1055 | |
a7ad6e4e | 1056 | if (!cert) |
62e76326 | 1057 | return NULL; |
a7ad6e4e | 1058 | |
5a4684b6 | 1059 | name = X509_get_subject_name(cert); |
a7ad6e4e | 1060 | |
23e6c4ae | 1061 | ret = ssl_get_attribute(name, attribute_name); |
1062 | ||
1063 | X509_free(cert); | |
1064 | ||
23e6c4ae | 1065 | return ret; |
a7ad6e4e | 1066 | } |
1067 | ||
63be0a78 | 1068 | /// \ingroup ServerProtocolSSLInternal |
a7ad6e4e | 1069 | const char * |
1070 | sslGetCAAttribute(SSL * ssl, const char *attribute_name) | |
1071 | { | |
1072 | X509 *cert; | |
1073 | X509_NAME *name; | |
23e6c4ae | 1074 | const char *ret; |
a7ad6e4e | 1075 | |
1076 | if (!ssl) | |
62e76326 | 1077 | return NULL; |
a7ad6e4e | 1078 | |
1079 | cert = SSL_get_peer_certificate(ssl); | |
62e76326 | 1080 | |
a7ad6e4e | 1081 | if (!cert) |
62e76326 | 1082 | return NULL; |
a7ad6e4e | 1083 | |
5a4684b6 | 1084 | name = X509_get_issuer_name(cert); |
a7ad6e4e | 1085 | |
23e6c4ae | 1086 | ret = ssl_get_attribute(name, attribute_name); |
1087 | ||
1088 | X509_free(cert); | |
1089 | ||
23e6c4ae | 1090 | return ret; |
a7ad6e4e | 1091 | } |
1092 | ||
a7ad6e4e | 1093 | const char * |
1094 | sslGetUserEmail(SSL * ssl) | |
1095 | { | |
e6ceef10 | 1096 | return sslGetUserAttribute(ssl, "emailAddress"); |
a7ad6e4e | 1097 | } |
4ac9968f | 1098 | |
1099 | const char * | |
1100 | sslGetUserCertificatePEM(SSL *ssl) | |
1101 | { | |
1102 | X509 *cert; | |
1103 | BIO *mem; | |
1104 | static char *str = NULL; | |
1105 | char *ptr; | |
1106 | long len; | |
1107 | ||
1108 | safe_free(str); | |
1109 | ||
1110 | if (!ssl) | |
1111 | return NULL; | |
1112 | ||
1113 | cert = SSL_get_peer_certificate(ssl); | |
1114 | ||
1115 | if (!cert) | |
1116 | return NULL; | |
1117 | ||
1118 | mem = BIO_new(BIO_s_mem()); | |
1119 | ||
1120 | PEM_write_bio_X509(mem, cert); | |
1121 | ||
1122 | ||
1123 | len = BIO_get_mem_data(mem, &ptr); | |
1124 | ||
1125 | str = (char *)xmalloc(len + 1); | |
1126 | ||
1127 | memcpy(str, ptr, len); | |
1128 | ||
1129 | str[len] = '\0'; | |
1130 | ||
1131 | X509_free(cert); | |
1132 | ||
1133 | BIO_free(mem); | |
1134 | ||
1135 | return str; | |
1136 | } | |
3d61c476 | 1137 | |
1138 | const char * | |
1139 | sslGetUserCertificateChainPEM(SSL *ssl) | |
1140 | { | |
1141 | STACK_OF(X509) *chain; | |
1142 | BIO *mem; | |
1143 | static char *str = NULL; | |
1144 | char *ptr; | |
1145 | long len; | |
1146 | int i; | |
1147 | ||
1148 | safe_free(str); | |
1149 | ||
1150 | if (!ssl) | |
1151 | return NULL; | |
1152 | ||
1153 | chain = SSL_get_peer_cert_chain(ssl); | |
1154 | ||
1155 | if (!chain) | |
1156 | return sslGetUserCertificatePEM(ssl); | |
1157 | ||
1158 | mem = BIO_new(BIO_s_mem()); | |
1159 | ||
1160 | for (i = 0; i < sk_X509_num(chain); i++) { | |
1161 | X509 *cert = sk_X509_value(chain, i); | |
1162 | PEM_write_bio_X509(mem, cert); | |
1163 | } | |
1164 | ||
1165 | len = BIO_get_mem_data(mem, &ptr); | |
1166 | ||
1167 | str = (char *)xmalloc(len + 1); | |
1168 | memcpy(str, ptr, len); | |
1169 | str[len] = '\0'; | |
1170 | ||
1171 | BIO_free(mem); | |
1172 | ||
1173 | return str; | |
1174 | } | |
454e8283 | 1175 | |
1176 | #endif /* USE_SSL */ |