version 1.1.1.1, 2013/10/14 10:32:47
|
version 1.1.1.2, 2014/06/15 20:20:06
|
Line 112 static int network_ssl_servername_callback(SSL *ssl, i
|
Line 112 static int network_ssl_servername_callback(SSL *ssl, i
|
config_patch_connection(srv, con, COMP_HTTP_SCHEME); |
config_patch_connection(srv, con, COMP_HTTP_SCHEME); |
config_patch_connection(srv, con, COMP_HTTP_HOST); |
config_patch_connection(srv, con, COMP_HTTP_HOST); |
|
|
if (NULL == con->conf.ssl_ctx) { | if (NULL == con->conf.ssl_pemfile_x509 || NULL == con->conf.ssl_pemfile_pkey) { |
/* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */ | /* x509/pkey available <=> pemfile was set <=> pemfile got patched: so this should never happen, unless you nest $SERVER["socket"] */ |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
"null SSL_CTX for TLS server name", con->tlsext_server_name); | "no certificate/private key for TLS server name", con->tlsext_server_name); |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
} |
} |
|
|
/* switch to new SSL_CTX in reaction to a client's server_name extension */ | /* first set certificate! setting private key checks whether certificate matches it */ |
if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) { | if (!SSL_use_certificate(ssl, con->conf.ssl_pemfile_x509)) { |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", | log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:", |
"failed to set SSL_CTX for TLS server name", con->tlsext_server_name); | "failed to set certificate for TLS server name", con->tlsext_server_name, |
| ERR_error_string(ERR_get_error(), NULL)); |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
} |
} |
|
|
|
if (!SSL_use_PrivateKey(ssl, con->conf.ssl_pemfile_pkey)) { |
|
log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:", |
|
"failed to set private key for TLS server name", con->tlsext_server_name, |
|
ERR_error_string(ERR_get_error(), NULL)); |
|
return SSL_TLSEXT_ERR_ALERT_FATAL; |
|
} |
|
|
|
if (con->conf.ssl_verifyclient) { |
|
if (NULL == con->conf.ssl_ca_file_cert_names) { |
|
log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:", |
|
"can't verify client without ssl.ca-file for TLS server name", con->tlsext_server_name, |
|
ERR_error_string(ERR_get_error(), NULL)); |
|
return SSL_TLSEXT_ERR_ALERT_FATAL; |
|
} |
|
|
|
SSL_set_client_CA_list(ssl, SSL_dup_CA_list(con->conf.ssl_ca_file_cert_names)); |
|
/* forcing verification here is really not that useful - a client could just connect without SNI */ |
|
SSL_set_verify( |
|
ssl, |
|
SSL_VERIFY_PEER | (con->conf.ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), |
|
NULL |
|
); |
|
SSL_set_verify_depth(ssl, con->conf.ssl_verifyclient_depth); |
|
} |
|
|
return SSL_TLSEXT_ERR_OK; |
return SSL_TLSEXT_ERR_OK; |
} |
} |
#endif |
#endif |
Line 224 static int network_server_init(server *srv, buffer *ho
|
Line 250 static int network_server_init(server *srv, buffer *ho
|
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); |
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); |
goto error_free_socket; |
goto error_free_socket; |
} |
} |
srv_socket->use_ipv6 = 1; |
|
} |
} |
#endif |
#endif |
|
|
Line 236 static int network_server_init(server *srv, buffer *ho
|
Line 261 static int network_server_init(server *srv, buffer *ho
|
} |
} |
} |
} |
|
|
#ifdef FD_CLOEXEC |
|
/* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */ |
/* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */ |
fcntl(srv_socket->fd, F_SETFD, FD_CLOEXEC); | fd_close_on_exec(srv_socket->fd); |
#endif | |
|
|
/* */ |
/* */ |
srv->cur_fds = srv_socket->fd; |
srv->cur_fds = srv_socket->fd; |
Line 326 static int network_server_init(server *srv, buffer *ho
|
Line 349 static int network_server_init(server *srv, buffer *ho
|
|
|
break; |
break; |
case AF_UNIX: |
case AF_UNIX: |
|
{ |
|
size_t hostlen = strlen(host) + 1; |
|
if (hostlen > sizeof(srv_socket->addr.un.sun_path)) { |
|
log_error_write(srv, __FILE__, __LINE__, "sS", "unix socket filename too long:", host); |
|
goto error_free_socket; |
|
} |
|
memcpy(srv_socket->addr.un.sun_path, host, hostlen); |
|
} |
srv_socket->addr.un.sun_family = AF_UNIX; |
srv_socket->addr.un.sun_family = AF_UNIX; |
strcpy(srv_socket->addr.un.sun_path, host); |
|
|
|
#ifdef SUN_LEN |
#ifdef SUN_LEN |
addr_len = SUN_LEN(&srv_socket->addr.un); |
addr_len = SUN_LEN(&srv_socket->addr.un); |
#else |
#else |
/* stevens says: */ |
/* stevens says: */ |
addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family); | addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family); |
#endif |
#endif |
|
|
/* check if the socket exists and try to connect to it. */ |
/* check if the socket exists and try to connect to it. */ |
Line 428 static int network_server_init(server *srv, buffer *ho
|
Line 458 static int network_server_init(server *srv, buffer *ho
|
if (srv->srv_sockets.size == 0) { |
if (srv->srv_sockets.size == 0) { |
srv->srv_sockets.size = 4; |
srv->srv_sockets.size = 4; |
srv->srv_sockets.used = 0; |
srv->srv_sockets.used = 0; |
srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket)); | srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*)); |
} else if (srv->srv_sockets.used == srv->srv_sockets.size) { |
} else if (srv->srv_sockets.used == srv->srv_sockets.size) { |
srv->srv_sockets.size += 4; |
srv->srv_sockets.size += 4; |
srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket)); | srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*)); |
} |
} |
|
|
srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket; |
srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket; |
Line 492 typedef enum {
|
Line 522 typedef enum {
|
NETWORK_BACKEND_SOLARIS_SENDFILEV |
NETWORK_BACKEND_SOLARIS_SENDFILEV |
} network_backend_t; |
} network_backend_t; |
|
|
|
#ifdef USE_OPENSSL |
|
static X509* x509_load_pem_file(server *srv, const char *file) { |
|
BIO *in; |
|
X509 *x = NULL; |
|
|
|
in = BIO_new(BIO_s_file()); |
|
if (NULL == in) { |
|
log_error_write(srv, __FILE__, __LINE__, "S", "SSL: BIO_new(BIO_s_file()) failed"); |
|
goto error; |
|
} |
|
|
|
if (BIO_read_filename(in,file) <= 0) { |
|
log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed"); |
|
goto error; |
|
} |
|
x = PEM_read_bio_X509(in, NULL, NULL, NULL); |
|
|
|
if (NULL == x) { |
|
log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read X509 certificate from '", file,"'"); |
|
goto error; |
|
} |
|
|
|
BIO_free(in); |
|
return x; |
|
|
|
error: |
|
if (NULL != in) BIO_free(in); |
|
return NULL; |
|
} |
|
|
|
static EVP_PKEY* evp_pkey_load_pem_file(server *srv, const char *file) { |
|
BIO *in; |
|
EVP_PKEY *x = NULL; |
|
|
|
in=BIO_new(BIO_s_file()); |
|
if (NULL == in) { |
|
log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BIO_new(BIO_s_file()) failed"); |
|
goto error; |
|
} |
|
|
|
if (BIO_read_filename(in,file) <= 0) { |
|
log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed"); |
|
goto error; |
|
} |
|
x = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); |
|
|
|
if (NULL == x) { |
|
log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read private key from '", file,"'"); |
|
goto error; |
|
} |
|
|
|
BIO_free(in); |
|
return x; |
|
|
|
error: |
|
if (NULL != in) BIO_free(in); |
|
return NULL; |
|
} |
|
|
|
static int network_openssl_load_pemfile(server *srv, size_t ndx) { |
|
specific_config *s = srv->config_storage[ndx]; |
|
|
|
#ifdef OPENSSL_NO_TLSEXT |
|
{ |
|
data_config *dc = (data_config *)srv->config_context->data[ndx]; |
|
if ((ndx > 0 && (COMP_SERVER_SOCKET != dc->comp || dc->cond != CONFIG_COND_EQ)) |
|
|| !s->ssl_enabled) { |
|
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", |
|
"ssl.pemfile only works in SSL socket binding context as openssl version does not support TLS extensions"); |
|
return -1; |
|
} |
|
} |
|
#endif |
|
|
|
if (NULL == (s->ssl_pemfile_x509 = x509_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1; |
|
if (NULL == (s->ssl_pemfile_pkey = evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1; |
|
|
|
if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) { |
|
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; |
|
} |
|
|
|
return 0; |
|
} |
|
#endif |
|
|
int network_init(server *srv) { |
int network_init(server *srv) { |
buffer *b; |
buffer *b; |
size_t i; | size_t i, j; |
network_backend_t backend; |
network_backend_t backend; |
|
|
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL |
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL |
Line 581 int network_init(server *srv) {
|
Line 700 int network_init(server *srv) {
|
long ssloptions = |
long ssloptions = |
SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION; |
SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION; |
|
|
if (buffer_is_empty(s->ssl_pemfile)) continue; | if (buffer_is_empty(s->ssl_pemfile) && buffer_is_empty(s->ssl_ca_file)) continue; |
|
|
#ifdef OPENSSL_NO_TLSEXT |
|
{ |
|
data_config *dc = (data_config *)srv->config_context->data[i]; |
|
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) { |
if (srv->ssl_is_init == 0) { |
SSL_load_error_strings(); |
SSL_load_error_strings(); |
SSL_library_init(); |
SSL_library_init(); |
Line 607 int network_init(server *srv) {
|
Line 715 int network_init(server *srv) {
|
} |
} |
} |
} |
|
|
|
if (!buffer_is_empty(s->ssl_pemfile)) { |
|
#ifdef OPENSSL_NO_TLSEXT |
|
data_config *dc = (data_config *)srv->config_context->data[i]; |
|
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 (network_openssl_load_pemfile(srv, i)) return -1; |
|
} |
|
|
|
|
|
if (!buffer_is_empty(s->ssl_ca_file)) { |
|
s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr); |
|
if (NULL == s->ssl_ca_file_cert_names) { |
|
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
|
ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file); |
|
} |
|
} |
|
|
|
if (buffer_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue; |
|
|
if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) { |
if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) { |
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", |
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", |
ERR_error_string(ERR_get_error(), NULL)); |
ERR_error_string(ERR_get_error(), NULL)); |
return -1; |
return -1; |
} |
} |
|
|
|
/* completely useless identifier; required for client cert verification to work with sessions */ |
|
if (0 == SSL_CTX_set_session_id_context(s->ssl_ctx, (const unsigned char*) CONST_STR_LEN("lighttpd"))) { |
|
log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:", |
|
"failed to set session context", |
|
ERR_error_string(ERR_get_error(), NULL)); |
|
return -1; |
|
} |
|
|
if (s->ssl_empty_fragments) { |
if (s->ssl_empty_fragments) { |
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS |
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS |
ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; |
ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; |
Line 722 int network_init(server *srv) {
|
Line 861 int network_init(server *srv) {
|
#endif |
#endif |
#endif |
#endif |
|
|
if (!buffer_is_empty(s->ssl_ca_file)) { | /* load all ssl.ca-files specified in the config into each SSL_CTX to be prepared for SNI */ |
if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) { | for (j = 0; j < srv->config_context->used; j++) { |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", | specific_config *s1 = srv->config_storage[j]; |
ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file); | |
return -1; | if (!buffer_is_empty(s1->ssl_ca_file)) { |
} | if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) { |
if (s->ssl_verifyclient) { | |
STACK_OF(X509_NAME) *certs = SSL_load_client_CA_file(s->ssl_ca_file->ptr); | |
if (!certs) { | |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file); | ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file); |
} | |
if (SSL_CTX_set_session_id_context(s->ssl_ctx, (void*) &srv, sizeof(srv)) != 1) { | |
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", | |
ERR_error_string(ERR_get_error(), NULL)); | |
return -1; |
return -1; |
} |
} |
SSL_CTX_set_client_CA_list(s->ssl_ctx, certs); | } |
SSL_CTX_set_verify( | } |
s->ssl_ctx, | |
SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), | if (s->ssl_verifyclient) { |
NULL | if (NULL == s->ssl_ca_file_cert_names) { |
| log_error_write(srv, __FILE__, __LINE__, "s", |
| "SSL: You specified ssl.verifyclient.activate but no ca_file" |
); |
); |
SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth); | return -1; |
} |
} |
} else if (s->ssl_verifyclient) { | SSL_CTX_set_client_CA_list(s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names)); |
log_error_write( | SSL_CTX_set_verify( |
srv, __FILE__, __LINE__, "s", | s->ssl_ctx, |
"SSL: You specified ssl.verifyclient.activate but no ca_file" | SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), |
| NULL |
); |
); |
|
SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth); |
} |
} |
|
|
if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) { | if (SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509) < 0) { |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); |
ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); |
return -1; |
return -1; |
} |
} |
|
|
if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) { | if (SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey) < 0) { |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", |
ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); |
ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); |
return -1; |
return -1; |
Line 794 int network_init(server *srv) {
|
Line 930 int network_init(server *srv) {
|
buffer_append_long(b, srv->srvconf.port); |
buffer_append_long(b, srv->srvconf.port); |
|
|
if (0 != network_server_init(srv, b, srv->config_storage[0])) { |
if (0 != network_server_init(srv, b, srv->config_storage[0])) { |
|
buffer_free(b); |
return -1; |
return -1; |
} |
} |
buffer_free(b); |
buffer_free(b); |
Line 857 int network_init(server *srv) {
|
Line 994 int network_init(server *srv) {
|
for (i = 1; i < srv->config_context->used; i++) { |
for (i = 1; i < srv->config_context->used; i++) { |
data_config *dc = (data_config *)srv->config_context->data[i]; |
data_config *dc = (data_config *)srv->config_context->data[i]; |
specific_config *s = srv->config_storage[i]; |
specific_config *s = srv->config_storage[i]; |
size_t j; |
|
|
|
/* not our stage */ |
/* not our stage */ |
if (COMP_SERVER_SOCKET != dc->comp) continue; |
if (COMP_SERVER_SOCKET != dc->comp) continue; |