summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-10-14 14:07:32 +0000
committerstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-10-14 14:07:32 +0000
commit9c0cac1b66fb27abbd9025d63edac62d1a595c27 (patch)
tree2290161790ec55701f1ae1bb8c8b6e93140a85e2
parentaba63f984a93c9bce0712a85e3236a4b2b394a00 (diff)
downloadlighttpd-9c0cac1b66fb27abbd9025d63edac62d1a595c27.tar.gz
Add TLS servername indication (SNI) support (fixes #386, thx Peter Colberg <peter@colberg.org>)
* This patch may "break" some configs, if they do stupid things. Like setting ssl.pemfile to a not existing file in a "non-socket/non-ssl" block. Fix them! :) From: Peter Colberg <peter@colberg.org> git-svn-id: svn://svn.lighttpd.net/lighttpd/trunk@2649 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--NEWS1
-rw-r--r--src/base.h3
-rw-r--r--src/configfile-glue.c4
-rw-r--r--src/configfile.c2
-rw-r--r--src/connections.c3
-rw-r--r--src/iosocket.c8
-rw-r--r--src/iosocket.h4
-rw-r--r--src/network.c199
-rw-r--r--src/server.c3
-rw-r--r--tests/bug-06.conf2
-rw-r--r--tests/bug-12.conf2
-rw-r--r--tests/default.conf2
-rw-r--r--tests/fastcgi-10.conf2
13 files changed, 160 insertions, 75 deletions
diff --git a/NEWS b/NEWS
index 3330bab8..756ba7d6 100644
--- a/NEWS
+++ b/NEWS
@@ -143,6 +143,7 @@ NEWS
* Set tm.tm_isdst = 0 before mktime() (fixes #2047)
* Allow chunkqueue_skip to skip all types of chunks
* Use linux-epoll by default if available (fixes #2021)
+ * Add TLS servername indication (SNI) support (fixes #386, thx Peter Colberg <peter@colberg.org>)
- 1.5.0-r19.. -
* -F option added for spawn-fcgi
diff --git a/src/base.h b/src/base.h
index 88b3451d..7363ae0a 100644
--- a/src/base.h
+++ b/src/base.h
@@ -38,6 +38,9 @@
#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
# define USE_OPENSSL
# include <openssl/ssl.h>
+# if ! defined OPENSSL_NO_TLSEXT && ! defined SSL_CTRL_SET_TLSEXT_HOSTNAME
+# define OPENSSL_NO_TLSEXT
+# endif
#endif
#ifdef HAVE_SYS_INOTIFY_H
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 8c6efd8a..a2ac07ab 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -305,6 +305,10 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
default:
break;
}
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ } else if (!buffer_is_empty(con->sock->tlsext_server_name)) {
+ l = con->sock->tlsext_server_name;
+#endif
} else {
l = srv->empty_string;
}
diff --git a/src/configfile.c b/src/configfile.c
index 1c6fb3a4..fe4a0a9a 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -312,6 +312,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(is_ssl);
PATCH(ssl_pemfile);
+ PATCH(ssl_ctx);
PATCH(ssl_ca_file);
PATCH(ssl_cipher_list);
PATCH(ssl_use_sslv2);
@@ -366,6 +367,7 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(use_xattr);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
PATCH(ssl_pemfile);
+ PATCH(ssl_ctx);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
PATCH(ssl_ca_file);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
diff --git a/src/connections.c b/src/connections.c
index 6642ce0f..840d2639 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -959,6 +959,9 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
return NULL;
}
+#ifndef OPENSSL_NO_TLSEXT
+ SSL_set_app_data(con->sock->ssl, con);
+#endif
SSL_set_accept_state(con->sock->ssl);
con->conf.is_ssl=1;
diff --git a/src/iosocket.c b/src/iosocket.c
index 1eb3848f..25d477ff 100644
--- a/src/iosocket.c
+++ b/src/iosocket.c
@@ -13,6 +13,10 @@ iosocket *iosocket_init(void) {
sock->type = IOSOCKET_TYPE_SOCKET;
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ sock->tlsext_server_name = buffer_init();
+#endif
+
return sock;
}
@@ -32,5 +36,9 @@ void iosocket_free(iosocket *sock) {
}
}
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ buffer_free(sock->tlsext_server_name);
+#endif
+
free(sock);
}
diff --git a/src/iosocket.h b/src/iosocket.h
index c1d6cb69..a11dbfe0 100644
--- a/src/iosocket.h
+++ b/src/iosocket.h
@@ -19,6 +19,7 @@
#endif
#include "settings.h"
+#include "buffer.h"
typedef enum {
IOSOCKET_TYPE_UNSET,
@@ -35,6 +36,9 @@ typedef struct {
#ifdef USE_OPENSSL
SSL *ssl;
+#ifndef OPENSSL_NO_TLSEXT
+ buffer *tlsext_server_name;
+#endif
#endif
iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
diff --git a/src/network.c b/src/network.c
index 1c98c564..f6e99cee 100644
--- a/src/network.c
+++ b/src/network.c
@@ -230,6 +230,44 @@ handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
return HANDLER_GO_ON;
}
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) {
+ const char *servername;
+ connection *con = (connection *) SSL_get_app_data(ssl);
+
+ UNUSED(al);
+
+ buffer_copy_string(con->uri.scheme, "https");
+
+ if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to get TLS server name");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ buffer_copy_string(con->sock->tlsext_server_name, servername);
+ buffer_to_lower(con->sock->tlsext_server_name);
+
+ config_patch_connection(srv, con, COMP_SERVER_SOCKET);
+ config_patch_connection(srv, con, COMP_HTTP_SCHEME);
+ config_patch_connection(srv, con, COMP_HTTP_HOST);
+
+ if (NULL == con->conf.ssl_ctx) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "null SSL_CTX for TLS server name", con->sock->tlsext_server_name);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ /* switch to new SSL_CTX in reaction to a client's server_name extension */
+ if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "failed to set SSL_CTX for TLS server name", con->sock->tlsext_server_name);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
static int network_server_init(server *srv, buffer *host_token, specific_config *s) {
int val;
socklen_t addr_len;
@@ -479,74 +517,10 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
if (s->is_ssl) {
#ifdef USE_OPENSSL
- if (srv->ssl_is_init == 0) {
- SSL_load_error_strings();
- SSL_library_init();
- srv->ssl_is_init = 1;
-
- if (0 == RAND_status()) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "not enough entropy in the pool");
- goto error_free_socket;
- }
- }
-
- if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- goto error_free_socket;
- }
-
- if (!s->ssl_use_sslv2) {
- /* disable SSLv2 */
- if (SSL_OP_NO_SSLv2 != SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- goto error_free_socket;
- }
- }
-
- if (!buffer_is_empty(s->ssl_cipher_list)) {
- if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- goto error_free_socket;
- }
- }
-
- if (buffer_is_empty(s->ssl_pemfile)) {
+ if (NULL == (srv_socket->ssl_ctx = s->ssl_ctx)) {
log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
goto error_free_socket;
}
-
- if (!buffer_is_empty(s->ssl_ca_file)) {
- if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
- goto error_free_socket;
- }
- }
-
- if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- goto error_free_socket;
- }
-
- if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- goto error_free_socket;
- }
-
- if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
- log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
- "Private key does not match the certificate public key, reason:",
- ERR_error_string(ERR_get_error(), NULL),
- s->ssl_pemfile);
- goto error_free_socket;
- }
- srv_socket->ssl_ctx = s->ssl_ctx;
#else
buffer_free(srv_socket->srv_token);
@@ -617,12 +591,6 @@ int network_close(server *srv) {
}
}
- if (srv_socket->is_ssl) {
-#ifdef USE_OPENSSL
- SSL_CTX_free(srv_socket->ssl_ctx);
-#endif
- }
-
iosocket_free(srv_socket->sock);
buffer_free(srv_socket->srv_token);
@@ -643,6 +611,95 @@ int network_init(server *srv) {
size_t i;
const network_backend_info_t *backend;
+#ifdef USE_OPENSSL
+ /* load SSL certificates */
+ for (i = 0; i < srv->config_context->used; i++) {
+ specific_config *s = srv->config_storage[i];
+
+ if (buffer_is_empty(s->ssl_pemfile)) continue;
+
+#ifdef OPENSSL_NO_TLSEXT
+ if (COMP_HTTP_HOST == dc->comp) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
+ return -1;
+ }
+#endif
+
+ if (srv->ssl_is_init == 0) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ srv->ssl_is_init = 1;
+
+ if (0 == RAND_status()) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "not enough entropy in the pool");
+ return -1;
+ }
+ }
+
+ if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (!s->ssl_use_sslv2) {
+ /* disable SSLv2 */
+ if (SSL_OP_NO_SSLv2 != SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!buffer_is_empty(s->ssl_cipher_list)) {
+ if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!buffer_is_empty(s->ssl_ca_file)) {
+ if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
+ return -1;
+ }
+ }
+
+ if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
+ "Private key does not match the certificate public key, reason:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile);
+ return -1;
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+ if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||
+ !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to initialize TLS servername callback, openssl library does not support TLS servername extension");
+ return -1;
+ }
+#endif
+ }
+#endif
+
b = buffer_init();
buffer_copy_string_buffer(b, srv->srvconf.bindhost);
diff --git a/src/server.c b/src/server.c
index 4df1f17e..262f222f 100644
--- a/src/server.c
+++ b/src/server.c
@@ -338,6 +338,9 @@ static void server_free(server *srv) {
buffer_free(s->errorfile_prefix);
array_free(s->mimetypes);
buffer_free(s->ssl_cipher_list);
+#ifdef USE_OPENSSL
+ SSL_CTX_free(s->ssl_ctx);
+#endif
free(s);
}
diff --git a/tests/bug-06.conf b/tests/bug-06.conf
index 4d0837e2..93a298eb 100644
--- a/tests/bug-06.conf
+++ b/tests/bug-06.conf
@@ -92,7 +92,7 @@ $PHYSICAL["existing-path"] =~ "\.php$" {
}
ssl.engine = "disable"
-ssl.pemfile = "server.pem"
+# ssl.pemfile = "server.pem"
auth.backend = "plain"
auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
diff --git a/tests/bug-12.conf b/tests/bug-12.conf
index 04199396..1be96902 100644
--- a/tests/bug-12.conf
+++ b/tests/bug-12.conf
@@ -94,7 +94,7 @@ $PHYSICAL["existing-path"] =~ "\.php$" {
}
ssl.engine = "disable"
-ssl.pemfile = "server.pem"
+# ssl.pemfile = "server.pem"
auth.backend = "plain"
auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
diff --git a/tests/default.conf b/tests/default.conf
index d43211c5..1eefc6cb 100644
--- a/tests/default.conf
+++ b/tests/default.conf
@@ -69,7 +69,7 @@ userdir.include-user = ( "jan" )
userdir.path = "/"
ssl.engine = "disable"
-ssl.pemfile = "server.pem"
+# ssl.pemfile = "server.pem"
auth.backend = "plain"
auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
diff --git a/tests/fastcgi-10.conf b/tests/fastcgi-10.conf
index 24b4c456..1ed841b1 100644
--- a/tests/fastcgi-10.conf
+++ b/tests/fastcgi-10.conf
@@ -73,7 +73,7 @@ $PHYSICAL["existing-path"] =~ "\.php$" {
}
ssl.engine = "disable"
-ssl.pemfile = "server.pem"
+# ssl.pemfile = "server.pem"
auth.backend = "plain"
auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"