]> granicus.if.org Git - apache/blob - modules/ssl/mod_ssl.c
the client cert X509_NAME_oneline() is only used if SSLFakeBasicAuth
[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     SSL *ssl;
224     char *cpVHostMD5;
225     SSLConnRec *sslconn = apr_pcalloc(c->pool, sizeof(*sslconn));
226
227     /*
228      * Create SSL context
229      */
230     myConnConfigSet(c, sslconn);
231     sslconn->log_level = sc->nLogLevel;
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
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");
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         c->aborted = 1;
262         return DECLINED; /* XXX */
263     }
264     SSL_clear(ssl);
265     cpVHostMD5 = ap_md5_binary(c->pool, sc->szVHostID, sc->nVHostID_length);
266     if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5,
267                                     MD5_DIGESTSIZE*2)) {
268         ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
269                 "Unable to set session id context to `%s'", cpVHostMD5);
270         c->aborted = 1;
271         return DECLINED; /* XXX */
272     }
273     SSL_set_app_data(ssl, c);
274     SSL_set_app_data2(ssl, NULL); /* will be request_rec */
275
276     sslconn->ssl = ssl;
277
278     /*
279      *  Configure callbacks for SSL connection
280      */
281     SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
282     SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);
283
284     SSL_set_verify_result(ssl, X509_V_OK);
285
286     ssl_io_filter_init(c, ssl);
287
288     return APR_SUCCESS;
289 }
290
291 static apr_status_t ssl_abort(SSLFilterRec *pRec, conn_rec *c)
292 {
293     SSLConnRec *sslconn = myConnConfig(c);
294     /*
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
300      */
301
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 */
306     sslconn->ssl = NULL;
307     c->aborted = 1;
308
309     return APR_EGENERAL;
310 }
311
312 /*
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.
318  */
319 int ssl_hook_process_connection(SSLFilterRec *pRec)
320 {
321     int n, err;
322     X509 *xs;
323     conn_rec *c = (conn_rec*)SSL_get_app_data (pRec->pssl);
324     SSLConnRec *sslconn = myConnConfig(c);
325     SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
326     long verify_result;
327
328     if (!SSL_is_init_finished(pRec->pssl))
329     {
330         if ((n = SSL_accept(pRec->pssl)) <= 0) {
331
332             if ((err = SSL_get_error(pRec->pssl, n)) == SSL_ERROR_ZERO_RETURN) {
333                 /*
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.
337                  */
338                 ssl_log(c->base_server, SSL_LOG_INFO,
339                         "SSL handshake stopped: connection was closed");
340             }
341             else if (err == SSL_ERROR_WANT_READ) {
342                 /*
343                  * This is in addition to what was present earlier. It is 
344                  * borrowed from openssl_state_machine.c [mod_tls].
345                  * TBD.
346                  */
347                 return SSL_ERROR_WANT_READ;
348             }
349             else if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) {
350                 /*
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
354                  * filter.
355                  */
356                 ap_remove_output_filter(pRec->pOutputFilter);
357                 return HTTP_BAD_REQUEST;
358             }
359             else if ((SSL_get_error(pRec->pssl, n) == SSL_ERROR_SYSCALL) 
360                 && (errno != EINTR)) {
361                 if (errno > 0)
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?!]");
366                 else
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!?]");
371             }
372             else {
373                 /*
374                  * Ok, anything else is a fatal error
375                  */
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");
381             }
382             return ssl_abort(pRec, c);
383         }
384
385         /*
386          * Check for failed client authentication
387          */
388         verify_result = SSL_get_verify_result(pRec->pssl);
389
390         if (verify_result != X509_V_OK ||
391             sslconn->verify_error != NULL)
392         {
393             if (ssl_verify_error_is_optional(verify_result) &&
394                 (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA))
395             {
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
402                  * in 1.x
403                  */
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");
408
409             }
410             else {
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);
418             }
419         }
420
421         /*
422          * Remember the peer certificate's DN
423          */
424         if ((xs = SSL_get_peer_certificate(pRec->pssl)) != NULL) {
425             sslconn->client_cert = xs;
426             sslconn->client_dn = NULL;
427         }
428
429         /*
430          * Make really sure that when a peer certificate
431          * is required we really got one... (be paranoid)
432          */
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);
438         }
439     }
440     return APR_SUCCESS;
441 }
442
443 static const char *ssl_hook_http_method (const request_rec *r)
444 {
445     SSLSrvConfigRec *sc = mySrvConfig(r->server);
446
447     if (sc->bEnabled == FALSE)
448         return NULL;
449
450     return "https";
451 }
452
453 static apr_port_t ssl_hook_default_port (const request_rec *r)
454 {
455     SSLSrvConfigRec *sc = mySrvConfig(r->server);
456
457     if (sc->bEnabled == FALSE)
458         return 0;
459     return 443;
460 }
461
462 /*
463  *  the module registration phase
464  */
465
466 static void ssl_register_hooks(apr_pool_t *p)
467 {
468     ssl_io_filter_register(p);
469
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);
483
484     ssl_var_register();
485 }
486
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 */
495 };