]> granicus.if.org Git - apache/blob - modules/ssl/mod_ssl.c
cbb2ea19a4860fde69c829527b2314200726c696
[apache] / modules / ssl / mod_ssl.c
1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  mod_ssl.c
8 **  Apache API interface structures
9 */
10
11 /* ====================================================================
12  * The Apache Software License, Version 1.1
13  *
14  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
15  * reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  *
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
27  *    distribution.
28  *
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.
35  *
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.
40  *
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.
44  *
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
56  * SUCH DAMAGE.
57  * ====================================================================
58  */
59
60 #include "mod_ssl.h"
61 #include "util_md5.h"
62 #include <assert.h>
63
64 /*
65  *  the table of configuration directives we provide
66  */
67
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 }
75
76 static const command_rec ssl_config_cmds[] = {
77
78     /*
79      * Global (main-server) context configuration directives
80      */
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 "
93                 "(`builtin', `...')")
94 #endif
95     SSL_CMD_SRV(RandomSeed, TAKE23,
96                 "SSL Pseudo Random Number Generator (PRNG) seeding source "
97                 "(`startup|connect builtin|file:/path|exec:/path [bytes]')")
98
99     /*
100      * Per-server context configuration directives
101      */
102     SSL_CMD_SRV(Engine, FLAG,
103                 "SSL switch for the protocol engine "
104                 "(`on', `off')")
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)")
124 #else
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)")
131 #endif
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)")
156
157 #ifdef SSL_EXPERIMENTAL_PROXY
158     /* 
159      * Proxy configuration for remote SSL connections
160      */
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 "
169                "(`on' or `off')")
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)")
185 #endif
186
187     /*
188      * Per-directory context configuration directives
189      */
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 "
195                "(no arguments)")
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)")
199
200     AP_END_CMD
201 };
202
203 /*
204  *  the various processing hooks
205  */
206
207 static void ssl_hook_pre_config(
208     apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
209 {
210     /* Register us to handle mod_log_config %c/%x variables */
211     ssl_var_log_config_register(pconf);
212 #if 0 /* XXX */
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);
217 #endif /* -0- */
218 }
219
220 static int ssl_hook_pre_connection(conn_rec *c)
221 {
222     SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
223     apr_table_t *apctx;
224     SSL *ssl;
225     unsigned char *cpVHostID;
226     char *cpVHostMD5;
227
228     /*
229      * Create SSL context
230      */
231     apr_table_setn(c->notes, "ssl", NULL);
232
233     /*
234      * Immediately stop processing if SSL is disabled for this connection
235      */
236     if (sc == NULL || !sc->bEnabled)
237         return DECLINED;
238
239     /*
240      * Remember the connection information for
241      * later access inside callback functions
242      */
243     cpVHostID = (unsigned char *)ssl_util_vhostid(c->pool,c->base_server);
244     ssl_log(c->base_server, SSL_LOG_INFO, "Connection to child %d established "
245             "(server %s, client %s)", c->id, cpVHostID, 
246             c->remote_ip != NULL ? c->remote_ip : "unknown");
247
248     /*
249      * Seed the Pseudo Random Number Generator (PRNG)
250      */
251     ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, "");
252
253     /*
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.
257      */
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");
261         apr_table_setn(c->notes, "ssl", NULL);
262         c->aborted = 1;
263         return DECLINED; /* XXX */
264     }
265     SSL_clear(ssl);
266     cpVHostMD5 = ap_md5(c->pool, cpVHostID);
267     if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5,
268             strlen(cpVHostMD5))) {
269         ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
270                 "Unable to set session id context to `%s'", cpVHostMD5);
271         apr_table_setn(c->notes, "ssl", NULL);
272         c->aborted = 1;
273         return DECLINED; /* XXX */
274     }
275     SSL_set_app_data(ssl, c);
276     apctx = apr_table_make(c->pool, AP_CTX_MAX_ENTRIES);
277     apr_table_setn(apctx, "ssl::request_rec", NULL);
278     apr_table_setn(apctx, "ssl::verify::depth", AP_CTX_NUM2PTR(0));
279     SSL_set_app_data2(ssl, apctx);
280
281     apr_table_setn(c->notes, "ssl", (const char *)ssl);
282
283     /*
284      *  Configure callbacks for SSL connection
285      */
286     SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
287     SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);
288
289     /*
290      * Predefine some client verification results
291      */
292     apr_table_setn(c->notes, "ssl::client::dn", NULL);
293     apr_table_setn(c->notes, "ssl::verify::error", NULL);
294     apr_table_setn(c->notes, "ssl::verify::info", NULL);
295     SSL_set_verify_result(ssl, X509_V_OK);
296
297     /*
298      * We have to manage a I/O timeout ourself, because Apache
299      * does it the first time when reading the request, but we're
300      * working some time before this happens.
301      */
302     ssl_util_setmodconfig(c->base_server, "ssl::handshake::timeout", (void *)FALSE);
303
304     ssl_io_filter_init(c, ssl);
305
306     return APR_SUCCESS;
307 }
308
309 static apr_status_t ssl_abort(SSLFilterRec *pRec, conn_rec *c)
310 {
311     /*
312      * try to gracefully shutdown the connection:
313      * - send an own shutdown message (be gracefully)
314      * - don't wait for peer's shutdown message (deadloop)
315      * - kick away the SSL stuff immediately
316      * - block the socket, so Apache cannot operate any more
317      */
318
319     SSL_set_shutdown(pRec->pssl, SSL_RECEIVED_SHUTDOWN);
320     SSL_smart_shutdown(pRec->pssl);
321     SSL_free(pRec->pssl);
322     pRec->pssl = NULL; /* so filters know we've been shutdown */
323     apr_table_setn(c->notes, "ssl", NULL);
324     c->aborted = 1;
325
326     return APR_EGENERAL;
327 }
328
329 /*
330  * The hook is NOT registered with ap_hook_process_connection. Instead, it is
331  * called manually from the churn () before it tries to read any data.
332  * There is some problem if I accept conn_rec *. Still investigating..
333  * Adv. if conn_rec * can be accepted is we can hook this function using the
334  * ap_hook_process_connection hook.
335  */
336 int ssl_hook_process_connection(SSLFilterRec *pRec)
337 {
338     int n, err;
339     X509 *xs;
340     char *cp = NULL;
341     conn_rec *c = (conn_rec*)SSL_get_app_data (pRec->pssl);
342     SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
343     long verify_result;
344
345     if (!SSL_is_init_finished(pRec->pssl))
346     {
347         if ((n = SSL_accept(pRec->pssl)) <= 0) {
348
349             if ((err = SSL_get_error(pRec->pssl, n)) == SSL_ERROR_ZERO_RETURN) {
350                 /*
351                  * The case where the connection was closed before any data
352                  * was transferred. That's not a real error and can occur
353                  * sporadically with some clients.
354                  */
355                 ssl_log(c->base_server, SSL_LOG_INFO,
356                         "SSL handshake stopped: connection was closed");
357             }
358             else if (err == SSL_ERROR_WANT_READ) {
359                 /*
360                  * This is in addition to what was present earlier. It is 
361                  * borrowed from openssl_state_machine.c [mod_tls].
362                  * TBD.
363                  */
364                 return SSL_ERROR_WANT_READ;
365             }
366             else if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) {
367                 /*
368                  * The case where OpenSSL has recognized a HTTP request:
369                  * This means the client speaks plain HTTP on our HTTPS port.
370                  * Hmmmm...  Punt this out of here after removing our output
371                  * filter.
372                  */
373                 ap_remove_output_filter(pRec->pOutputFilter);
374                 return HTTP_BAD_REQUEST;
375             }
376             else if (ssl_util_getmodconfig_ssl(pRec->pssl, "ssl::handshake::timeout")
377                == (void *)TRUE) {
378                 ssl_log(c->base_server, SSL_LOG_ERROR,
379                         "SSL handshake timed out (client %s, server %s)",
380                         c->remote_ip != NULL ? c->remote_ip : "unknown", 
381                         ssl_util_vhostid(c->pool,c->base_server));
382             }
383             else if ((SSL_get_error(pRec->pssl, n) == SSL_ERROR_SYSCALL) 
384                 && (errno != EINTR)) {
385                 if (errno > 0)
386                     ssl_log(c->base_server,
387                              SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
388                             "SSL handshake interrupted by system "
389                             "[Hint: Stop button pressed in browser?!]");
390                 else
391                     ssl_log(c->base_server,
392                         SSL_LOG_INFO|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
393                         "Spurious SSL handshake interrupt [Hint: "
394                         "Usually just one of those OpenSSL confusions!?]");
395             }
396             else {
397                 /*
398                  * Ok, anything else is a fatal error
399                  */
400                 ssl_log(c->base_server,
401                         SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
402                         "SSL handshake failed (server %s, client %s)",
403                         ssl_util_vhostid(c->pool,c->base_server),
404                         c->remote_ip != NULL ? c->remote_ip : "unknown");
405             }
406             return ssl_abort(pRec, c);
407         }
408
409         /*
410          * Check for failed client authentication
411          */
412         verify_result = SSL_get_verify_result(pRec->pssl);
413
414         if (verify_result != X509_V_OK ||
415             ((cp = (char *)apr_table_get(c->notes,
416                                          "ssl::verify::error")) != NULL))
417         {
418             if (ssl_verify_error_is_optional(verify_result) &&
419                 (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA))
420             {
421                 /* leaving this log message as an error for the moment,
422                  * according to the mod_ssl docs:
423                  * "level optional_no_ca is actually against the idea
424                  *  of authentication (but can be used to establish 
425                  * SSL test pages, etc.)"
426                  * optional_no_ca doesn't appear to work as advertised
427                  * in 1.x
428                  */
429                 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
430                         "SSL client authentication failed, "
431                         "accepting certificate based on "
432                         "\"SSLVerifyClient optional_no_ca\" configuration");
433
434             }
435             else {
436                 const char *verror =
437                     X509_verify_cert_error_string(verify_result);
438                 ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
439                         "SSL client authentication failed: %s",
440                         cp ? cp : verror ? verror : "unknown");
441                 return ssl_abort(pRec, c);
442             }
443         }
444
445         /*
446          * Remember the peer certificate's DN
447          */
448         if ((xs = SSL_get_peer_certificate(pRec->pssl)) != NULL) {
449             cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
450             apr_table_setn(c->notes,"ssl::client::dn",apr_pstrdup(c->pool, cp));
451             free(cp);
452         }
453
454         /*
455          * Make really sure that when a peer certificate
456          * is required we really got one... (be paranoid)
457          */
458         if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE
459             && apr_table_get(c->notes, "ssl::client::dn") == NULL) {
460             ssl_log(c->base_server, SSL_LOG_ERROR,
461                     "No acceptable peer certificate available");
462             return ssl_abort(pRec, c);
463         }
464     }
465     return APR_SUCCESS;
466 }
467
468 static const char *ssl_hook_http_method (const request_rec *r)
469 {
470     SSLSrvConfigRec *sc = mySrvConfig(r->server);
471
472     if (sc->bEnabled == FALSE)
473         return NULL;
474
475     return "https";
476 }
477
478 static apr_port_t ssl_hook_default_port (const request_rec *r)
479 {
480     SSLSrvConfigRec *sc = mySrvConfig(r->server);
481
482     if (sc->bEnabled == FALSE)
483         return 0;
484     return 443;
485 }
486
487 /*
488  *  the module registration phase
489  */
490
491 static void ssl_register_hooks(apr_pool_t *p)
492 {
493     ssl_io_filter_register(p);
494
495     ap_hook_pre_connection(ssl_hook_pre_connection,NULL,NULL, APR_HOOK_MIDDLE);
496     ap_hook_post_config   (ssl_init_Module,        NULL,NULL, APR_HOOK_MIDDLE);
497     ap_hook_http_method   (ssl_hook_http_method,   NULL,NULL, APR_HOOK_MIDDLE);
498     ap_hook_default_port  (ssl_hook_default_port,  NULL,NULL, APR_HOOK_MIDDLE);
499     ap_hook_handler       (ssl_hook_Handler,       NULL,NULL, APR_HOOK_MIDDLE);
500     ap_hook_pre_config    (ssl_hook_pre_config,    NULL,NULL, APR_HOOK_MIDDLE);
501     ap_hook_child_init    (ssl_init_Child,         NULL,NULL, APR_HOOK_MIDDLE);
502     ap_hook_translate_name(ssl_hook_Translate,     NULL,NULL, APR_HOOK_MIDDLE);
503     ap_hook_check_user_id (ssl_hook_UserCheck,     NULL,NULL, APR_HOOK_FIRST);
504     ap_hook_fixups        (ssl_hook_Fixup,         NULL,NULL, APR_HOOK_MIDDLE);
505     ap_hook_access_checker(ssl_hook_Access,        NULL,NULL, APR_HOOK_MIDDLE);
506     ap_hook_auth_checker  (ssl_hook_Auth,          NULL,NULL, APR_HOOK_MIDDLE);
507     ap_hook_post_read_request(ssl_hook_ReadReq,    NULL,NULL, APR_HOOK_MIDDLE);
508
509     ssl_var_register();
510 }
511
512 module AP_MODULE_DECLARE_DATA ssl_module = {
513     STANDARD20_MODULE_STUFF,
514     ssl_config_perdir_create,   /* create per-dir    config structures */
515     ssl_config_perdir_merge,    /* merge  per-dir    config structures */
516     ssl_config_server_create,   /* create per-server config structures */
517     ssl_config_server_merge,    /* merge  per-server config structures */
518     ssl_config_cmds,            /* table of configuration directives   */
519     ssl_register_hooks          /* register hooks */
520 };