1 /* _ _
2 ** _ __ ___ ___ __| | ___ ___| | mod_ssl
3 ** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
6 ** |_____|
7 ** ssl_engine_ext.c
8 ** Extensions to other Apache parts
9 */
10
11 /* ====================================================================
12 * Copyright (c) 1998-2003 Ralf S. Engelschall. All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
25 *
26 * 3. All advertising materials mentioning features or use of this
27 * software must display the following acknowledgment:
28 * "This product includes software developed by
29 * Ralf S. Engelschall <rse@engelschall.com> for use in the
30 * mod_ssl project (http://www.modssl.org/)."
31 *
32 * 4. The names "mod_ssl" must not be used to endorse or promote
33 * products derived from this software without prior written
34 * permission. For written permission, please contact
35 * rse@engelschall.com.
36 *
37 * 5. Products derived from this software may not be called "mod_ssl"
38 * nor may "mod_ssl" appear in their names without prior
39 * written permission of Ralf S. Engelschall.
40 *
41 * 6. Redistributions of any form whatsoever must retain the following
42 * acknowledgment:
43 * "This product includes software developed by
44 * Ralf S. Engelschall <rse@engelschall.com> for use in the
45 * mod_ssl project (http://www.modssl.org/)."
46 *
47 * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
48 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
51 * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
58 * OF THE POSSIBILITY OF SUCH DAMAGE.
59 * ====================================================================
60 */
61 /* ``Only those who attempt the absurd
62 can achieve the impossible.''
63 -- Unknown */
64 #include "mod_ssl.h"
65
66
67 /* _________________________________________________________________
68 **
69 ** SSL Extensions
70 ** _________________________________________________________________
71 */
72
73 static void ssl_ext_mlc_register(void);
74 static void ssl_ext_mlc_unregister(void);
75 static void ssl_ext_mr_register(void);
76 static void ssl_ext_mr_unregister(void);
77 static void ssl_ext_mp_register(void);
78 static void ssl_ext_mp_unregister(void);
79 static void ssl_ext_ms_register(void);
80 static void ssl_ext_ms_unregister(void);
81
ssl_ext_register(void)82 void ssl_ext_register(void)
83 {
84 ssl_ext_mlc_register();
85 ssl_ext_mr_register();
86 ssl_ext_mp_register();
87 ssl_ext_ms_register();
88 return;
89 }
90
ssl_ext_unregister(void)91 void ssl_ext_unregister(void)
92 {
93 ssl_ext_mlc_unregister();
94 ssl_ext_mr_unregister();
95 ssl_ext_mp_unregister();
96 ssl_ext_ms_unregister();
97 return;
98 }
99
100 /* _________________________________________________________________
101 **
102 ** SSL Extension to mod_log_config
103 ** _________________________________________________________________
104 */
105
106 static char *ssl_ext_mlc_log_c(request_rec *r, char *a);
107 static char *ssl_ext_mlc_log_x(request_rec *r, char *a);
108
109 /*
110 * register us for the mod_log_config function registering phase
111 * to establish %{...}c and to be able to expand %{...}x variables.
112 */
ssl_ext_mlc_register(void)113 static void ssl_ext_mlc_register(void)
114 {
115 ap_hook_register("ap::mod_log_config::log_c",
116 ssl_ext_mlc_log_c, AP_HOOK_NOCTX);
117 ap_hook_register("ap::mod_log_config::log_x",
118 ssl_ext_mlc_log_x, AP_HOOK_NOCTX);
119 return;
120 }
121
ssl_ext_mlc_unregister(void)122 static void ssl_ext_mlc_unregister(void)
123 {
124 ap_hook_unregister("ap::mod_log_config::log_c",
125 ssl_ext_mlc_log_c);
126 ap_hook_unregister("ap::mod_log_config::log_x",
127 ssl_ext_mlc_log_x);
128 return;
129 }
130
131 /*
132 * implement the %{..}c log function
133 * (we are the only function)
134 */
ssl_ext_mlc_log_c(request_rec * r,char * a)135 static char *ssl_ext_mlc_log_c(request_rec *r, char *a)
136 {
137 char *result;
138
139 if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL)
140 return NULL;
141 result = NULL;
142 if (strEQ(a, "version"))
143 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
144 else if (strEQ(a, "cipher"))
145 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
146 else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
147 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
148 else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
149 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
150 else if (strEQ(a, "errcode"))
151 result = "-";
152 else if (strEQ(a, "errstr"))
153 result = ap_ctx_get(r->connection->client->ctx, "ssl::verify::error");
154 if (result != NULL && result[0] == NUL)
155 result = NULL;
156 return result;
157 }
158
159 /*
160 * extend the implementation of the %{..}x log function
161 * (there can be more functions)
162 */
ssl_ext_mlc_log_x(request_rec * r,char * a)163 static char *ssl_ext_mlc_log_x(request_rec *r, char *a)
164 {
165 char *result;
166
167 result = NULL;
168 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL)
169 result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
170 if (result != NULL && result[0] == NUL)
171 result = NULL;
172 return result;
173 }
174
175 /* _________________________________________________________________
176 **
177 ** SSL Extension to mod_rewrite
178 ** _________________________________________________________________
179 */
180
181 static char *ssl_ext_mr_lookup_variable(request_rec *r, char *var);
182
183 /*
184 * register us for the mod_rewrite lookup_variable() function
185 */
ssl_ext_mr_register(void)186 static void ssl_ext_mr_register(void)
187 {
188 ap_hook_register("ap::mod_rewrite::lookup_variable",
189 ssl_ext_mr_lookup_variable, AP_HOOK_NOCTX);
190 return;
191 }
192
ssl_ext_mr_unregister(void)193 static void ssl_ext_mr_unregister(void)
194 {
195 ap_hook_unregister("ap::mod_rewrite::lookup_variable",
196 ssl_ext_mr_lookup_variable);
197 return;
198 }
199
ssl_ext_mr_lookup_variable(request_rec * r,char * var)200 static char *ssl_ext_mr_lookup_variable(request_rec *r, char *var)
201 {
202 char *val;
203
204 val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
205 if (val[0] == NUL)
206 val = NULL;
207 return val;
208 }
209
210 /* _________________________________________________________________
211 **
212 ** SSL Extension to mod_proxy
213 ** _________________________________________________________________
214 */
215
216 static int ssl_ext_mp_canon(request_rec *, char *);
217 static int ssl_ext_mp_handler(request_rec *, void *, char *, char *, int, char *);
218 static int ssl_ext_mp_set_destport(request_rec *);
219 static char *ssl_ext_mp_new_connection(request_rec *, BUFF *, char *);
220 static void ssl_ext_mp_close_connection(void *);
221 static int ssl_ext_mp_write_host_header(request_rec *, BUFF *, char *, int, char *);
222 #ifdef SSL_EXPERIMENTAL_PROXY
223 static void ssl_ext_mp_init(server_rec *, pool *);
224 static int ssl_ext_mp_verify_cb(int, X509_STORE_CTX *);
225 static int ssl_ext_mp_clientcert_cb(SSL *, X509 **, EVP_PKEY **);
226 #endif
227
228 /*
229 * register us ...
230 */
ssl_ext_mp_register(void)231 static void ssl_ext_mp_register(void)
232 {
233 #ifdef SSL_EXPERIMENTAL_PROXY
234 ap_hook_register("ap::mod_proxy::init",
235 ssl_ext_mp_init, AP_HOOK_NOCTX);
236 #endif
237 ap_hook_register("ap::mod_proxy::canon",
238 ssl_ext_mp_canon, AP_HOOK_NOCTX);
239 ap_hook_register("ap::mod_proxy::handler",
240 ssl_ext_mp_handler, AP_HOOK_NOCTX);
241 ap_hook_register("ap::mod_proxy::http::handler::set_destport",
242 ssl_ext_mp_set_destport, AP_HOOK_NOCTX);
243 ap_hook_register("ap::mod_proxy::http::handler::new_connection",
244 ssl_ext_mp_new_connection, AP_HOOK_NOCTX);
245 ap_hook_register("ap::mod_proxy::http::handler::write_host_header",
246 ssl_ext_mp_write_host_header, AP_HOOK_NOCTX);
247 return;
248 }
249
ssl_ext_mp_unregister(void)250 static void ssl_ext_mp_unregister(void)
251 {
252 #ifdef SSL_EXPERIMENTAL_PROXY
253 ap_hook_unregister("ap::mod_proxy::init", ssl_ext_mp_init);
254 #endif
255 ap_hook_unregister("ap::mod_proxy::canon", ssl_ext_mp_canon);
256 ap_hook_unregister("ap::mod_proxy::handler", ssl_ext_mp_handler);
257 ap_hook_unregister("ap::mod_proxy::http::handler::set_destport",
258 ssl_ext_mp_set_destport);
259 ap_hook_unregister("ap::mod_proxy::http::handler::new_connection",
260 ssl_ext_mp_new_connection);
261 ap_hook_unregister("ap::mod_proxy::http::handler::write_host_header",
262 ssl_ext_mp_write_host_header);
263 return;
264 }
265
266 /*
267 * SSL proxy initialization
268 */
269 #ifdef SSL_EXPERIMENTAL_PROXY
ssl_ext_mp_init(server_rec * s,pool * p)270 static void ssl_ext_mp_init(server_rec *s, pool *p)
271 {
272 SSLSrvConfigRec *sc;
273 char *cpVHostID;
274 int nVerify;
275 SSL_CTX *ctx;
276 char *cp;
277 STACK_OF(X509_INFO) *sk;
278
279 /*
280 * Initialize each virtual server
281 */
282 ERR_clear_error();
283 for (; s != NULL; s = s->next) {
284 sc = mySrvConfig(s);
285 cpVHostID = ssl_util_vhostid(p, s);
286
287 if (sc->bProxyVerify == UNSET)
288 sc->bProxyVerify = FALSE;
289
290 /*
291 * Create new SSL context and configure callbacks
292 */
293 if (sc->nProxyProtocol == SSL_PROTOCOL_NONE) {
294 ssl_log(s, SSL_LOG_ERROR,
295 "Init: (%s) No Proxy SSL protocols available [hint: SSLProxyProtocol]",
296 cpVHostID);
297 ssl_die();
298 }
299 cp = ap_pstrcat(p, (sc->nProxyProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""),
300 (sc->nProxyProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""),
301 (sc->nProxyProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL);
302 cp[strlen(cp)-2] = NUL;
303 ssl_log(s, SSL_LOG_TRACE,
304 "Init: (%s) Creating new proxy SSL context (protocols: %s)",
305 cpVHostID, cp);
306 if (sc->nProxyProtocol == SSL_PROTOCOL_SSLV2)
307 ctx = SSL_CTX_new(SSLv2_client_method()); /* only SSLv2 is left */
308 else
309 ctx = SSL_CTX_new(SSLv23_client_method()); /* be more flexible */
310 if (ctx == NULL) {
311 ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
312 "Init: (%s) Unable to create SSL Proxy context", cpVHostID);
313 ssl_die();
314 }
315 sc->pSSLProxyCtx = ctx;
316 SSL_CTX_set_options(ctx, SSL_OP_ALL);
317 if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV2))
318 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
319 if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV3))
320 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
321 if (!(sc->nProxyProtocol & SSL_PROTOCOL_TLSV1))
322 SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
323
324 if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
325 sk = sk_X509_INFO_new_null();
326 if (sc->szProxyClientCertificateFile)
327 SSL_load_CrtAndKeyInfo_file(p, sk, sc->szProxyClientCertificateFile);
328 if (sc->szProxyClientCertificatePath)
329 SSL_load_CrtAndKeyInfo_path(p, sk, sc->szProxyClientCertificatePath);
330 ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL proxy",
331 cpVHostID, sk_X509_INFO_num(sk));
332 if (sk_X509_INFO_num(sk) > 0) {
333 SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
334 sc->skProxyClientCerts = sk;
335 }
336 }
337
338 /*
339 * Calculate OpenSSL verify type for verifying the remote server
340 * certificate. We either verify it against our list of CA's, or don't
341 * bother at all.
342 */
343 nVerify = SSL_VERIFY_NONE;
344 if (sc->bProxyVerify)
345 nVerify |= SSL_VERIFY_PEER;
346 if ( nVerify & SSL_VERIFY_PEER
347 && sc->szProxyCACertificateFile == NULL
348 && sc->szProxyCACertificatePath == NULL) {
349 ssl_log(s, SSL_LOG_ERROR,
350 "Init: (%s) SSLProxyVerify set to On but no CA certificates configured",
351 cpVHostID);
352 ssl_die();
353 }
354 if ( nVerify & SSL_VERIFY_NONE
355 && ( sc->szProxyCACertificateFile != NULL
356 || sc->szProxyCACertificatePath != NULL)) {
357 ssl_log(s, SSL_LOG_WARN,
358 "init: (%s) CA certificates configured but ignored because SSLProxyVerify is Off",
359 cpVHostID);
360 }
361 SSL_CTX_set_verify(ctx, nVerify, ssl_ext_mp_verify_cb);
362
363 /*
364 * Enable session caching. We can safely use the same cache
365 * as used for communicating with the other clients.
366 */
367 SSL_CTX_sess_set_new_cb(sc->pSSLProxyCtx, ssl_callback_NewSessionCacheEntry);
368 SSL_CTX_sess_set_get_cb(sc->pSSLProxyCtx, ssl_callback_GetSessionCacheEntry);
369 SSL_CTX_sess_set_remove_cb(sc->pSSLProxyCtx, ssl_callback_DelSessionCacheEntry);
370
371 /*
372 * Configure SSL Cipher Suite
373 */
374 ssl_log(s, SSL_LOG_TRACE,
375 "Init: (%s) Configuring permitted SSL ciphers for SSL proxy", cpVHostID);
376 if (sc->szProxyCipherSuite != NULL) {
377 if (!SSL_CTX_set_cipher_list(sc->pSSLProxyCtx, sc->szProxyCipherSuite)) {
378 ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
379 "Init: (%s) Unable to configure permitted SSL ciphers for SSL Proxy",
380 cpVHostID);
381 ssl_die();
382 }
383 }
384
385 /*
386 * Configure Client Authentication details
387 */
388 if (sc->szProxyCACertificateFile != NULL || sc->szProxyCACertificatePath != NULL) {
389 ssl_log(s, SSL_LOG_DEBUG,
390 "Init: (%s) Configuring client verification locations for SSL Proxy",
391 cpVHostID);
392 if (!SSL_CTX_load_verify_locations(sc->pSSLProxyCtx,
393 sc->szProxyCACertificateFile,
394 sc->szProxyCACertificatePath)) {
395 ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
396 "Init: (%s) Unable to configure SSL verify locations for SSL proxy",
397 cpVHostID);
398 ssl_die();
399 }
400 }
401 }
402 return;
403 }
404 #endif /* SSL_EXPERIMENTAL_PROXY */
405
ssl_ext_mp_canon(request_rec * r,char * url)406 static int ssl_ext_mp_canon(request_rec *r, char *url)
407 {
408 int rc;
409
410 if (strcEQn(url, "https:", 6)) {
411 rc = OK;
412 ap_hook_call("ap::mod_proxy::http::canon",
413 &rc, r, url+6, "https", DEFAULT_HTTPS_PORT);
414 return rc;
415 }
416 return DECLINED;
417 }
418
ssl_ext_mp_handler(request_rec * r,void * cr,char * url,char * proxyhost,int proxyport,char * protocol)419 static int ssl_ext_mp_handler(
420 request_rec *r, void *cr, char *url, char *proxyhost, int proxyport, char *protocol)
421 {
422 int rc;
423
424 if (strcEQ(protocol, "https")) {
425 ap_ctx_set(r->ctx, "ssl::proxy::enabled", PTRUE);
426 ap_hook_call("ap::mod_proxy::http::handler",
427 &rc, r, cr, url, proxyhost, proxyport);
428 return rc;
429 }
430 else {
431 ap_ctx_set(r->ctx, "ssl::proxy::enabled", PFALSE);
432 }
433 return DECLINED;
434 }
435
ssl_ext_mp_set_destport(request_rec * r)436 static int ssl_ext_mp_set_destport(request_rec *r)
437 {
438 if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PTRUE)
439 return DEFAULT_HTTPS_PORT;
440 else
441 return DEFAULT_HTTP_PORT;
442 }
443
ssl_ext_mp_new_connection(request_rec * r,BUFF * fb,char * peer)444 static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb, char *peer)
445 {
446 #ifndef SSL_EXPERIMENTAL_PROXY
447 SSL_CTX *ssl_ctx;
448 #endif
449 SSL *ssl;
450 char *errmsg;
451 int rc;
452 char *cpVHostID;
453 char *cpVHostMD5;
454 #ifdef SSL_EXPERIMENTAL_PROXY
455 SSLSrvConfigRec *sc;
456 char *cp;
457 #endif
458
459 if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
460 return NULL;
461
462 /*
463 * Find context
464 */
465 #ifdef SSL_EXPERIMENTAL_PROXY
466 sc = mySrvConfig(r->server);
467 #endif
468 cpVHostID = ssl_util_vhostid(r->pool, r->server);
469
470 /*
471 * Create a SSL context and handle
472 */
473 #ifdef SSL_EXPERIMENTAL_PROXY
474 ssl = SSL_new(sc->pSSLProxyCtx);
475 #else
476 ssl_ctx = SSL_CTX_new(SSLv23_client_method());
477 ssl = SSL_new(ssl_ctx);
478 #endif
479 if (ssl == NULL) {
480 errmsg = ap_psprintf(r->pool, "SSL proxy new failed (%s): peer %s: %s",
481 cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
482 ap_ctx_set(fb->ctx, "ssl", NULL);
483 return errmsg;
484 }
485 SSL_clear(ssl);
486 cpVHostMD5 = ap_md5(r->pool, (unsigned char *)cpVHostID);
487 if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) {
488 errmsg = ap_psprintf(r->pool, "Unable to set session id context to `%s': peer %s: %s",
489 cpVHostMD5, peer, ERR_reason_error_string(ERR_get_error()));
490 ap_ctx_set(fb->ctx, "ssl", NULL);
491 return errmsg;
492 }
493 SSL_set_fd(ssl, fb->fd);
494 #ifdef SSL_EXPERIMENTAL_PROXY
495 SSL_set_app_data(ssl, fb->ctx);
496 #endif
497 ap_ctx_set(fb->ctx, "ssl", ssl);
498 #ifdef SSL_EXPERIMENTAL_PROXY
499 ap_ctx_set(fb->ctx, "ssl::proxy::server_rec", r->server);
500 ap_ctx_set(fb->ctx, "ssl::proxy::peer", peer);
501 ap_ctx_set(fb->ctx, "ssl::proxy::servername", cpVHostID);
502 ap_ctx_set(fb->ctx, "ssl::proxy::verifyerror", NULL);
503 #endif
504
505 /*
506 * Give us a chance to gracefully close the connection
507 */
508 ap_register_cleanup(r->pool, (void *)fb,
509 ssl_ext_mp_close_connection, ssl_ext_mp_close_connection);
510
511 /*
512 * Establish the SSL connection
513 */
514 if ((rc = SSL_connect(ssl)) <= 0) {
515 #ifdef SSL_EXPERIMENTAL_PROXY
516 if ((cp = (char *)ap_ctx_get(fb->ctx, "ssl::proxy::verifyerror")) != NULL) {
517 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
518 SSL_smart_shutdown(ssl);
519 SSL_free(ssl);
520 ap_ctx_set(fb->ctx, "ssl", NULL);
521 ap_bsetflag(fb, B_EOF|B_EOUT, 1);
522 return NULL;
523 }
524 #endif
525 errmsg = ap_psprintf(r->pool, "SSL proxy connect failed (%s): peer %s: %s",
526 cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
527 ssl_log(r->server, SSL_LOG_ERROR, "%s", errmsg);
528 SSL_free(ssl);
529 ap_ctx_set(fb->ctx, "ssl", NULL);
530 return errmsg;
531 }
532
533 return NULL;
534 }
535
ssl_ext_mp_close_connection(void * _fb)536 static void ssl_ext_mp_close_connection(void *_fb)
537 {
538 BUFF *fb = _fb;
539 SSL *ssl;
540 #ifndef SSL_EXPERIMENTAL_PROXY
541 SSL_CTX *ctx;
542 #endif
543
544 ssl = ap_ctx_get(fb->ctx, "ssl");
545 if (ssl != NULL) {
546 #ifndef SSL_EXPERIMENTAL_PROXY
547 ctx = SSL_get_SSL_CTX(ssl);
548 #endif
549 SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
550 SSL_smart_shutdown(ssl);
551 SSL_free(ssl);
552 ap_ctx_set(fb->ctx, "ssl", NULL);
553 #ifndef SSL_EXPERIMENTAL_PROXY
554 if (ctx != NULL)
555 SSL_CTX_free(ctx);
556 #endif
557 }
558 return;
559 }
560
ssl_ext_mp_write_host_header(request_rec * r,BUFF * fb,char * host,int port,char * portstr)561 static int ssl_ext_mp_write_host_header(
562 request_rec *r, BUFF *fb, char *host, int port, char *portstr)
563 {
564 if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
565 return DECLINED;
566
567 if (portstr != NULL && port != DEFAULT_HTTPS_PORT) {
568 ap_bvputs(fb, "Host: ", host, ":", portstr, "\r\n", NULL);
569 return OK;
570 }
571 return DECLINED;
572 }
573
574 #ifdef SSL_EXPERIMENTAL_PROXY
575
576 /*
577 * Callback for client certificate stuff.
578 * If the remote site sent us a SSLv3 list of acceptable CA's then trawl the
579 * table of client certs and send the first one that matches.
580 */
ssl_ext_mp_clientcert_cb(SSL * ssl,X509 ** x509,EVP_PKEY ** pkey)581 static int ssl_ext_mp_clientcert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
582 {
583 SSLSrvConfigRec *sc;
584 X509_NAME *xnx;
585 X509_NAME *issuer;
586 X509_INFO *xi;
587 char *peer;
588 char *servername;
589 server_rec *s;
590 ap_ctx *pCtx;
591 STACK_OF(X509_NAME) *sk;
592 STACK_OF(X509_INFO) *pcerts;
593 char *cp;
594 int i, j;
595
596 pCtx = (ap_ctx *)SSL_get_app_data(ssl);
597 s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
598 peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
599 servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
600
601 sc = mySrvConfig(s);
602 pcerts = sc->skProxyClientCerts;
603
604 ssl_log(s, SSL_LOG_DEBUG,
605 "Proxy client certificate callback: (%s) entered", servername);
606
607 if ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <= 0)) {
608 ssl_log(s, SSL_LOG_TRACE,
609 "Proxy client certificate callback: (%s) "
610 "site wanted client certificate but none available",
611 servername);
612 return 0;
613 }
614
615 sk = SSL_get_client_CA_list(ssl);
616
617 if ((sk == NULL) || (sk_X509_NAME_num(sk) <= 0)) {
618 /*
619 * remote site didn't send us a list of acceptable CA certs,
620 * so lets send the first one we came across
621 */
622 xi = sk_X509_INFO_value(pcerts, 0);
623 cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
624 ssl_log(s, SSL_LOG_DEBUG,
625 "SSL Proxy: (%s) no acceptable CA list, sending %s",
626 servername, cp != NULL ? cp : "-unknown-");
627 OPENSSL_free(cp);
628 /* export structures to the caller */
629 *x509 = xi->x509;
630 *pkey = xi->x_pkey->dec_pkey;
631 /* prevent OpenSSL freeing these structures */
632 CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
633 CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
634 return 1;
635 }
636
637 for (i = 0; i < sk_X509_NAME_num(sk); i++) {
638 xnx = sk_X509_NAME_value(sk, i);
639 for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
640 xi = sk_X509_INFO_value(pcerts,j);
641 issuer = X509_get_issuer_name(xi->x509);
642 if (X509_NAME_cmp(issuer, xnx) == 0) {
643 cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
644 ssl_log(s, SSL_LOG_DEBUG, "SSL Proxy: (%s) sending %s",
645 servername, cp != NULL ? cp : "-unknown-");
646 OPENSSL_free(cp);
647 /* export structures to the caller */
648 *x509 = xi->x509;
649 *pkey = xi->x_pkey->dec_pkey;
650 /* prevent OpenSSL freeing these structures */
651 CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
652 CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
653 return 1;
654 }
655 }
656 }
657 ssl_log(s, SSL_LOG_TRACE,
658 "Proxy client certificate callback: (%s) "
659 "no client certificate found!?", servername);
660 return 0;
661 }
662
663 /*
664 * This is the verify callback when we are connecting to a remote SSL server
665 * from the proxy. Information is passed in via the SSL "ctx" app_data
666 * mechanism. We pass in an Apache context in this field, which contains
667 * server_rec of the server making the proxy connection from the
668 * "ssl::proxy::server_rec" context.
669 *
670 * The result of the verification is passed back out to SSLERR via the return
671 * value. We also store the error message in the "proxyverifyfailed" context,
672 * so the caller of SSL_connect() can log a detailed error message.
673 */
ssl_ext_mp_verify_cb(int ok,X509_STORE_CTX * ctx)674 static int ssl_ext_mp_verify_cb(int ok, X509_STORE_CTX *ctx)
675 {
676 SSLSrvConfigRec *sc;
677 X509 *xs;
678 int errnum;
679 int errdepth;
680 char *cp, *cp2;
681 ap_ctx *pCtx;
682 server_rec *s;
683 SSL *ssl;
684 char *peer;
685 char *servername;
686
687 ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx);
688 pCtx = (ap_ctx *)SSL_get_app_data(ssl);
689 s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
690 peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
691 servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
692 sc = mySrvConfig(s);
693
694 /*
695 * Unless stated otherwise by the configuration, we really don't
696 * care if the verification was okay or not, so lets return now
697 * before we do anything involving memory or time.
698 */
699 if (sc->bProxyVerify == FALSE)
700 return ok;
701
702 /*
703 * Get verify ingredients
704 */
705 xs = X509_STORE_CTX_get_current_cert(ctx);
706 errnum = X509_STORE_CTX_get_error(ctx);
707 errdepth = X509_STORE_CTX_get_error_depth(ctx);
708
709 /*
710 * Log verification information
711 */
712 cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
713 cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0);
714 ssl_log(s, SSL_LOG_DEBUG,
715 "SSL Proxy: (%s) Certificate Verification for remote server %s: "
716 "depth: %d, subject: %s, issuer: %s",
717 servername, peer != NULL ? peer : "-unknown-",
718 errdepth, cp != NULL ? cp : "-unknown-",
719 cp2 != NULL ? cp2 : "-unknown");
720 OPENSSL_free(cp);
721 OPENSSL_free(cp2);
722
723 /*
724 * If we already know it's not ok, log the real reason
725 */
726 if (!ok) {
727 ssl_log(s, SSL_LOG_ERROR,
728 "SSL Proxy: (%s) Certificate Verification failed for %s: "
729 "Error (%d): %s", servername,
730 peer != NULL ? peer : "-unknown-",
731 errnum, X509_verify_cert_error_string(errnum));
732 ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
733 (void *)X509_verify_cert_error_string(errnum));
734 return ok;
735 }
736
737 /*
738 * Check the depth of the certificate chain
739 */
740 if (sc->nProxyVerifyDepth > 0) {
741 if (errdepth > sc->nProxyVerifyDepth) {
742 ssl_log(s, SSL_LOG_ERROR,
743 "SSL Proxy: (%s) Certificate Verification failed for %s: "
744 "Certificate Chain too long "
745 "(chain has %d certificates, but maximum allowed are only %d)",
746 servername, peer, errdepth, sc->nProxyVerifyDepth);
747 ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
748 (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
749 ok = FALSE;
750 }
751 }
752
753 /*
754 * And finally signal OpenSSL the (perhaps changed) state
755 */
756 return (ok);
757 }
758
759 #endif /* SSL_EXPERIMENTAL_PROXY */
760
761 /* _________________________________________________________________
762 **
763 ** SSL Extension to mod_status
764 ** _________________________________________________________________
765 */
766
767 static void ssl_ext_ms_display(request_rec *, int, int);
768
ssl_ext_ms_register(void)769 static void ssl_ext_ms_register(void)
770 {
771 ap_hook_register("ap::mod_status::display", ssl_ext_ms_display, AP_HOOK_NOCTX);
772 return;
773 }
774
ssl_ext_ms_unregister(void)775 static void ssl_ext_ms_unregister(void)
776 {
777 ap_hook_unregister("ap::mod_status::display", ssl_ext_ms_display);
778 return;
779 }
780
ssl_ext_ms_display_cb(char * str,void * _r)781 static void ssl_ext_ms_display_cb(char *str, void *_r)
782 {
783 request_rec *r = (request_rec *)_r;
784 if (str != NULL)
785 ap_rputs(str, r);
786 return;
787 }
788
ssl_ext_ms_display(request_rec * r,int no_table_report,int short_report)789 static void ssl_ext_ms_display(request_rec *r, int no_table_report, int short_report)
790 {
791 SSLSrvConfigRec *sc = mySrvConfig(r->server);
792
793 if (sc == NULL)
794 return;
795 if (short_report)
796 return;
797 ap_rputs("<hr>\n", r);
798 ap_rputs("<table cellspacing=0 cellpadding=0>\n", r);
799 ap_rputs("<tr><td bgcolor=\"#000000\">\n", r);
800 ap_rputs("<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">SSL/TLS Session Cache Status:</font></b>\r", r);
801 ap_rputs("</td></tr>\n", r);
802 ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r);
803 ssl_scache_status(r->server, r->pool, ssl_ext_ms_display_cb, r);
804 ap_rputs("</td></tr>\n", r);
805 ap_rputs("</table>\n", r);
806 return;
807 }
808
809