2 ** _ __ ___ ___ __| | ___ ___| | mod_ssl
3 ** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
8 ** Apache API interface structures
11 /* ====================================================================
12 * The Apache Software License, Version 1.1
14 * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in
26 * the documentation and/or other materials provided with the
29 * 3. The end-user documentation included with the redistribution,
30 * if any, must include the following acknowledgment:
31 * "This product includes software developed by the
32 * Apache Software Foundation (http://www.apache.org/)."
33 * Alternately, this acknowledgment may appear in the software itself,
34 * if and wherever such third-party acknowledgments normally appear.
36 * 4. The names "Apache" and "Apache Software Foundation" must
37 * not be used to endorse or promote products derived from this
38 * software without prior written permission. For written
39 * permission, please contact apache@apache.org.
41 * 5. Products derived from this software may not be called "Apache",
42 * nor may "Apache" appear in their name, without prior written
43 * permission of the Apache Software Foundation.
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
46 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
49 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * ====================================================================
65 * the table of configuration directives we provide
68 #define SSL_CMD_ALL(name, args, desc) \
69 AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF|OR_AUTHCFG, desc),
70 #define SSL_CMD_SRV(name, args, desc) \
71 AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF, desc),
72 #define SSL_CMD_DIR(name, type, args, desc) \
73 AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, NULL, OR_##type, desc),
74 #define AP_END_CMD { NULL }
76 static const command_rec ssl_config_cmds[] = {
79 * Global (main-server) context configuration directives
81 SSL_CMD_SRV(Mutex, TAKE1,
82 "SSL lock for handling internal mutual exclusions "
83 "(`none', `file:/path/to/file')")
84 SSL_CMD_SRV(PassPhraseDialog, TAKE1,
85 "SSL dialog mechanism for the pass phrase query "
86 "(`builtin', `exec:/path/to/program')")
87 SSL_CMD_SRV(SessionCache, TAKE1,
88 "SSL Session Cache storage "
89 "(`none', `dbm:/path/to/file')")
90 #ifdef SSL_EXPERIMENTAL_ENGINE
91 SSL_CMD_SRV(CryptoDevice, TAKE1,
92 "SSL external Crypto Device usage "
95 SSL_CMD_SRV(RandomSeed, TAKE23,
96 "SSL Pseudo Random Number Generator (PRNG) seeding source "
97 "(`startup|connect builtin|file:/path|exec:/path [bytes]')")
100 * Per-server context configuration directives
102 SSL_CMD_SRV(Engine, FLAG,
103 "SSL switch for the protocol engine "
105 SSL_CMD_ALL(CipherSuite, TAKE1,
106 "Colon-delimited list of permitted SSL Ciphers "
107 "(`XXX:...:XXX' - see manual)")
108 SSL_CMD_SRV(CertificateFile, TAKE1,
109 "SSL Server Certificate file "
110 "(`/path/to/file' - PEM or DER encoded)")
111 SSL_CMD_SRV(CertificateKeyFile, TAKE1,
112 "SSL Server Private Key file "
113 "(`/path/to/file' - PEM or DER encoded)")
114 SSL_CMD_SRV(CertificateChainFile, TAKE1,
115 "SSL Server CA Certificate Chain file "
116 "(`/path/to/file' - PEM encoded)")
117 #ifdef SSL_EXPERIMENTAL_PERDIRCA
118 SSL_CMD_ALL(CACertificatePath, TAKE1,
119 "SSL CA Certificate path "
120 "(`/path/to/dir' - contains PEM encoded files)")
121 SSL_CMD_ALL(CACertificateFile, TAKE1,
122 "SSL CA Certificate file "
123 "(`/path/to/file' - PEM encoded)")
125 SSL_CMD_SRV(CACertificatePath, TAKE1,
126 "SSL CA Certificate path "
127 "(`/path/to/dir' - contains PEM encoded files)")
128 SSL_CMD_SRV(CACertificateFile, TAKE1,
129 "SSL CA Certificate file "
130 "(`/path/to/file' - PEM encoded)")
132 SSL_CMD_SRV(CARevocationPath, TAKE1,
133 "SSL CA Certificate Revocation List (CRL) path "
134 "(`/path/to/dir' - contains PEM encoded files)")
135 SSL_CMD_SRV(CARevocationFile, TAKE1,
136 "SSL CA Certificate Revocation List (CRL) file "
137 "(`/path/to/file' - PEM encoded)")
138 SSL_CMD_ALL(VerifyClient, TAKE1,
139 "SSL Client verify type "
140 "(`none', `optional', `require', `optional_no_ca')")
141 SSL_CMD_ALL(VerifyDepth, TAKE1,
142 "SSL Client verify depth "
143 "(`N' - number of intermediate certificates)")
144 SSL_CMD_SRV(SessionCacheTimeout, TAKE1,
145 "SSL Session Cache object lifetime "
146 "(`N' - number of seconds)")
147 SSL_CMD_SRV(Log, TAKE1,
148 "SSL logfile for SSL-related messages "
149 "(`/path/to/file', `|/path/to/program')")
150 SSL_CMD_SRV(LogLevel, TAKE1,
151 "SSL logfile verbosity level "
152 "(`none', `error', `warn', `info', `debug')")
153 SSL_CMD_SRV(Protocol, RAW_ARGS,
154 "Enable or disable various SSL protocols"
155 "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
157 #ifdef SSL_EXPERIMENTAL_PROXY
159 * Proxy configuration for remote SSL connections
161 SSL_CMD_SRV(ProxyProtocol, RAW_ARGS,
162 "SSL Proxy: enable or disable SSL protocol flavors "
163 "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
164 SSL_CMD_SRV(ProxyCipherSuite, TAKE1,
165 "SSL Proxy: colon-delimited list of permitted SSL ciphers "
166 "(`XXX:...:XXX' - see manual)")
167 SSL_CMD_SRV(ProxyVerify, FLAG,
168 "SSL Proxy: whether to verify the remote certificate "
170 SSL_CMD_SRV(ProxyVerifyDepth, TAKE1,
171 "SSL Proxy: maximum certificate verification depth "
172 "(`N' - number of intermediate certificates)")
173 SSL_CMD_SRV(ProxyCACertificateFile, TAKE1,
174 "SSL Proxy: file containing server certificates "
175 "(`/path/to/file' - PEM encoded certificates)")
176 SSL_CMD_SRV(ProxyCACertificatePath, TAKE1,
177 "SSL Proxy: directory containing server certificates "
178 "(`/path/to/dir' - contains PEM encoded certificates)")
179 SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1,
180 "SSL Proxy: file containing client certificates "
181 "(`/path/to/file' - PEM encoded certificates)")
182 SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
183 "SSL Proxy: directory containing client certificates "
184 "(`/path/to/dir' - contains PEM encoded certificates)")
188 * Per-directory context configuration directives
190 SSL_CMD_DIR(Options, OPTIONS, RAW_ARGS,
191 "Set one or more options to configure the SSL engine"
192 "(`[+-]option[=value] ...' - see manual)")
193 SSL_CMD_DIR(RequireSSL, AUTHCFG, NO_ARGS,
194 "Require the SSL protocol for the per-directory context "
196 SSL_CMD_DIR(Require, AUTHCFG, RAW_ARGS,
197 "Require a boolean expression to evaluate to true for granting access"
198 "(arbitrary complex boolean expression - see manual)")
204 * the various processing hooks
207 static void ssl_hook_pre_config(
208 apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
210 /* Register us to handle mod_log_config %c/%x variables */
211 ssl_var_log_config_register(pconf);
213 /* XXX: Register us to handle mod_proxy extensions that don't exist yet */
214 ssl_ext_proxy_register(pconf);
215 /* XXX: Register us to handle mod_status extensions that don't exist yet */
216 ssl_scache_status_register(pconf);
220 static int ssl_hook_pre_connection(conn_rec *c)
222 SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
225 SSLConnRec *sslconn = apr_pcalloc(c->pool, sizeof(*sslconn));
230 myConnConfigSet(c, sslconn);
231 sslconn->log_level = sc->nLogLevel;
234 * Immediately stop processing if SSL is disabled for this connection
236 if (sc == NULL || !sc->bEnabled)
240 * Remember the connection information for
241 * later access inside callback functions
244 ssl_log(c->base_server, SSL_LOG_INFO, "Connection to child %d established "
245 "(server %s, client %s)", c->id, sc->szVHostID,
246 c->remote_ip != NULL ? c->remote_ip : "unknown");
249 * Seed the Pseudo Random Number Generator (PRNG)
251 ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, "");
254 * Create a new SSL connection with the configured server SSL context and
255 * attach this to the socket. Additionally we register this attachment
256 * so we can detach later.
258 if ((ssl = SSL_new(sc->pSSLCtx)) == NULL) {
259 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
260 "Unable to create a new SSL connection from the SSL context");
262 return DECLINED; /* XXX */
265 cpVHostMD5 = ap_md5_binary(c->pool, sc->szVHostID, sc->nVHostID_length);
266 if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5,
268 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
269 "Unable to set session id context to `%s'", cpVHostMD5);
271 return DECLINED; /* XXX */
273 SSL_set_app_data(ssl, c);
274 SSL_set_app_data2(ssl, NULL); /* will be request_rec */
279 * Configure callbacks for SSL connection
281 SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
282 SSL_set_tmp_dh_callback(ssl, ssl_callback_TmpDH);
284 SSL_set_verify_result(ssl, X509_V_OK);
286 ssl_io_filter_init(c, ssl);
291 static apr_status_t ssl_abort(SSLFilterRec *pRec, conn_rec *c)
293 SSLConnRec *sslconn = myConnConfig(c);
295 * try to gracefully shutdown the connection:
296 * - send an own shutdown message (be gracefully)
297 * - don't wait for peer's shutdown message (deadloop)
298 * - kick away the SSL stuff immediately
299 * - block the socket, so Apache cannot operate any more
302 SSL_set_shutdown(pRec->pssl, SSL_RECEIVED_SHUTDOWN);
303 SSL_smart_shutdown(pRec->pssl);
304 SSL_free(pRec->pssl);
305 pRec->pssl = NULL; /* so filters know we've been shutdown */
313 * The hook is NOT registered with ap_hook_process_connection. Instead, it is
314 * called manually from the churn () before it tries to read any data.
315 * There is some problem if I accept conn_rec *. Still investigating..
316 * Adv. if conn_rec * can be accepted is we can hook this function using the
317 * ap_hook_process_connection hook.
319 int ssl_hook_process_connection(SSLFilterRec *pRec)
323 conn_rec *c = (conn_rec*)SSL_get_app_data (pRec->pssl);
324 SSLConnRec *sslconn = myConnConfig(c);
325 SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
328 if (!SSL_is_init_finished(pRec->pssl))
330 if ((n = SSL_accept(pRec->pssl)) <= 0) {
332 if ((err = SSL_get_error(pRec->pssl, n)) == SSL_ERROR_ZERO_RETURN) {
334 * The case where the connection was closed before any data
335 * was transferred. That's not a real error and can occur
336 * sporadically with some clients.
338 ssl_log(c->base_server, SSL_LOG_INFO,
339 "SSL handshake stopped: connection was closed");
341 else if (err == SSL_ERROR_WANT_READ) {
343 * This is in addition to what was present earlier. It is
344 * borrowed from openssl_state_machine.c [mod_tls].
347 return SSL_ERROR_WANT_READ;
349 else if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) {
351 * The case where OpenSSL has recognized a HTTP request:
352 * This means the client speaks plain HTTP on our HTTPS port.
353 * Hmmmm... Punt this out of here after removing our output
356 ap_remove_output_filter(pRec->pOutputFilter);
357 return HTTP_BAD_REQUEST;
359 else if ((SSL_get_error(pRec->pssl, n) == SSL_ERROR_SYSCALL)
360 && (errno != EINTR)) {
362 ssl_log(c->base_server,
363 SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
364 "SSL handshake interrupted by system "
365 "[Hint: Stop button pressed in browser?!]");
367 ssl_log(c->base_server,
368 SSL_LOG_INFO|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
369 "Spurious SSL handshake interrupt [Hint: "
370 "Usually just one of those OpenSSL confusions!?]");
374 * Ok, anything else is a fatal error
376 ssl_log(c->base_server,
377 SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
378 "SSL handshake failed (server %s, client %s)",
379 ssl_util_vhostid(c->pool,c->base_server),
380 c->remote_ip != NULL ? c->remote_ip : "unknown");
382 return ssl_abort(pRec, c);
386 * Check for failed client authentication
388 verify_result = SSL_get_verify_result(pRec->pssl);
390 if (verify_result != X509_V_OK ||
391 sslconn->verify_error != NULL)
393 if (ssl_verify_error_is_optional(verify_result) &&
394 (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA))
396 /* leaving this log message as an error for the moment,
397 * according to the mod_ssl docs:
398 * "level optional_no_ca is actually against the idea
399 * of authentication (but can be used to establish
400 * SSL test pages, etc.)"
401 * optional_no_ca doesn't appear to work as advertised
404 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
405 "SSL client authentication failed, "
406 "accepting certificate based on "
407 "\"SSLVerifyClient optional_no_ca\" configuration");
411 const char *error = sslconn->verify_error ?
412 sslconn->verify_error :
413 X509_verify_cert_error_string(verify_result);
414 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
415 "SSL client authentication failed: %s",
416 error ? error : "unknown");
417 return ssl_abort(pRec, c);
422 * Remember the peer certificate's DN
424 if ((xs = SSL_get_peer_certificate(pRec->pssl)) != NULL) {
425 sslconn->client_cert = xs;
426 sslconn->client_dn = NULL;
430 * Make really sure that when a peer certificate
431 * is required we really got one... (be paranoid)
433 if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE
434 && sslconn->client_cert == NULL) {
435 ssl_log(c->base_server, SSL_LOG_ERROR,
436 "No acceptable peer certificate available");
437 return ssl_abort(pRec, c);
443 static const char *ssl_hook_http_method (const request_rec *r)
445 SSLSrvConfigRec *sc = mySrvConfig(r->server);
447 if (sc->bEnabled == FALSE)
453 static apr_port_t ssl_hook_default_port (const request_rec *r)
455 SSLSrvConfigRec *sc = mySrvConfig(r->server);
457 if (sc->bEnabled == FALSE)
463 * the module registration phase
466 static void ssl_register_hooks(apr_pool_t *p)
468 ssl_io_filter_register(p);
470 ap_hook_pre_connection(ssl_hook_pre_connection,NULL,NULL, APR_HOOK_MIDDLE);
471 ap_hook_post_config (ssl_init_Module, NULL,NULL, APR_HOOK_MIDDLE);
472 ap_hook_http_method (ssl_hook_http_method, NULL,NULL, APR_HOOK_MIDDLE);
473 ap_hook_default_port (ssl_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE);
474 ap_hook_handler (ssl_hook_Handler, NULL,NULL, APR_HOOK_MIDDLE);
475 ap_hook_pre_config (ssl_hook_pre_config, NULL,NULL, APR_HOOK_MIDDLE);
476 ap_hook_child_init (ssl_init_Child, NULL,NULL, APR_HOOK_MIDDLE);
477 ap_hook_translate_name(ssl_hook_Translate, NULL,NULL, APR_HOOK_MIDDLE);
478 ap_hook_check_user_id (ssl_hook_UserCheck, NULL,NULL, APR_HOOK_FIRST);
479 ap_hook_fixups (ssl_hook_Fixup, NULL,NULL, APR_HOOK_MIDDLE);
480 ap_hook_access_checker(ssl_hook_Access, NULL,NULL, APR_HOOK_MIDDLE);
481 ap_hook_auth_checker (ssl_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE);
482 ap_hook_post_read_request(ssl_hook_ReadReq, NULL,NULL, APR_HOOK_MIDDLE);
487 module AP_MODULE_DECLARE_DATA ssl_module = {
488 STANDARD20_MODULE_STUFF,
489 ssl_config_perdir_create, /* create per-dir config structures */
490 ssl_config_perdir_merge, /* merge per-dir config structures */
491 ssl_config_server_create, /* create per-server config structures */
492 ssl_config_server_merge, /* merge per-server config structures */
493 ssl_config_cmds, /* table of configuration directives */
494 ssl_register_hooks /* register hooks */