|
@@ -63,6 +63,34 @@ socket_fail( conn_t *conn )
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
+static void ATTR_PRINTFLIKE(1, 2)
|
|
|
|
+print_ssl_errors( const char *fmt, ... )
|
|
|
|
+{
|
|
|
|
+ char *action;
|
|
|
|
+ va_list va;
|
|
|
|
+ ulong err;
|
|
|
|
+
|
|
|
|
+ va_start( va, fmt );
|
|
|
|
+ nfvasprintf( &action, fmt, va );
|
|
|
|
+ va_end( va );
|
|
|
|
+ while ((err = ERR_get_error()))
|
|
|
|
+ error( "Error while %s: %s\n", action, ERR_error_string( err, 0 ) );
|
|
|
|
+ free( action );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+print_ssl_socket_errors( const char *func, conn_t *conn )
|
|
|
|
+{
|
|
|
|
+ ulong err;
|
|
|
|
+ int num = 0;
|
|
|
|
+
|
|
|
|
+ while ((err = ERR_get_error())) {
|
|
|
|
+ error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) );
|
|
|
|
+ num++;
|
|
|
|
+ }
|
|
|
|
+ return num;
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
ssl_return( const char *func, conn_t *conn, int ret )
|
|
ssl_return( const char *func, conn_t *conn, int ret )
|
|
{
|
|
{
|
|
@@ -76,20 +104,20 @@ ssl_return( const char *func, conn_t *conn, int ret )
|
|
FALLTHROUGH
|
|
FALLTHROUGH
|
|
case SSL_ERROR_WANT_READ:
|
|
case SSL_ERROR_WANT_READ:
|
|
return 0;
|
|
return 0;
|
|
- case SSL_ERROR_SYSCALL:
|
|
|
|
case SSL_ERROR_SSL:
|
|
case SSL_ERROR_SSL:
|
|
- if (!(err = ERR_get_error())) {
|
|
|
|
- if (ret == 0) {
|
|
|
|
|
|
+ print_ssl_socket_errors( func, conn );
|
|
|
|
+ break;
|
|
|
|
+ case SSL_ERROR_SYSCALL:
|
|
|
|
+ if (print_ssl_socket_errors( func, conn ))
|
|
|
|
+ break;
|
|
|
|
+ if (ret == 0) {
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
- /* Callers take the short path out, so signal higher layers from here. */
|
|
|
|
- conn->state = SCK_EOF;
|
|
|
|
- conn->read_callback( conn->callback_aux );
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- sys_error( "Socket error: secure %s %s", func, conn->name );
|
|
|
|
- } else {
|
|
|
|
- error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) );
|
|
|
|
|
|
+ /* Callers take the short path out, so signal higher layers from here. */
|
|
|
|
+ conn->state = SCK_EOF;
|
|
|
|
+ conn->read_callback( conn->callback_aux );
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
+ sys_error( "Socket error: secure %s %s", func, conn->name );
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err );
|
|
error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err );
|
|
@@ -176,22 +204,29 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock )
|
|
|
|
|
|
trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs;
|
|
trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs;
|
|
for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
|
|
for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
|
|
- if (!X509_cmp( cert, X509_OBJECT_get0_X509( sk_X509_OBJECT_value( trusted, i ) ) ))
|
|
|
|
|
|
+ if (!X509_cmp( cert, X509_OBJECT_get0_X509( sk_X509_OBJECT_value( trusted, i ) ) )) {
|
|
|
|
+ X509_free( cert );
|
|
return 0;
|
|
return 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
err = SSL_get_verify_result( sock->ssl );
|
|
err = SSL_get_verify_result( sock->ssl );
|
|
if (err != X509_V_OK) {
|
|
if (err != X509_V_OK) {
|
|
error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) );
|
|
error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) );
|
|
|
|
+ X509_free( cert );
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
if (!conf->host) {
|
|
if (!conf->host) {
|
|
error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name );
|
|
error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name );
|
|
|
|
+ X509_free( cert );
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
- return verify_hostname( cert, conf->host );
|
|
|
|
|
|
+ int ret = verify_hostname( cert, conf->host );
|
|
|
|
+
|
|
|
|
+ X509_free( cert );
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
@@ -203,7 +238,15 @@ init_ssl_ctx( const server_conf_t *conf )
|
|
if (conf->SSLContext)
|
|
if (conf->SSLContext)
|
|
return conf->ssl_ctx_valid;
|
|
return conf->ssl_ctx_valid;
|
|
|
|
|
|
- mconf->SSLContext = SSL_CTX_new( SSLv23_client_method() );
|
|
|
|
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
|
|
+ const SSL_METHOD *method = TLS_client_method();
|
|
|
|
+#else
|
|
|
|
+ const SSL_METHOD *method = SSLv23_client_method();
|
|
|
|
+#endif
|
|
|
|
+ if (!(mconf->SSLContext = SSL_CTX_new( method ))) {
|
|
|
|
+ print_ssl_errors( "initializing SSL context" );
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
if (!(conf->ssl_versions & SSLv3))
|
|
if (!(conf->ssl_versions & SSLv3))
|
|
options |= SSL_OP_NO_SSLv3;
|
|
options |= SSL_OP_NO_SSLv3;
|
|
@@ -221,25 +264,24 @@ init_ssl_ctx( const server_conf_t *conf )
|
|
SSL_CTX_set_options( mconf->SSLContext, options );
|
|
SSL_CTX_set_options( mconf->SSLContext, options );
|
|
|
|
|
|
if (conf->cert_file && !SSL_CTX_load_verify_locations( mconf->SSLContext, conf->cert_file, 0 )) {
|
|
if (conf->cert_file && !SSL_CTX_load_verify_locations( mconf->SSLContext, conf->cert_file, 0 )) {
|
|
- error( "Error while loading certificate file '%s': %s\n",
|
|
|
|
- conf->cert_file, ERR_error_string( ERR_get_error(), 0 ) );
|
|
|
|
|
|
+ print_ssl_errors( "loading certificate file '%s'", conf->cert_file );
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup( X509_STORE_get0_objects( SSL_CTX_get_cert_store( mconf->SSLContext ) ) );
|
|
mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup( X509_STORE_get0_objects( SSL_CTX_get_cert_store( mconf->SSLContext ) ) );
|
|
- if (mconf->system_certs && !SSL_CTX_set_default_verify_paths( mconf->SSLContext ))
|
|
|
|
- warn( "Warning: Unable to load default certificate files: %s\n",
|
|
|
|
- ERR_error_string( ERR_get_error(), 0 ) );
|
|
|
|
|
|
+ if (mconf->system_certs && !SSL_CTX_set_default_verify_paths( mconf->SSLContext )) {
|
|
|
|
+ ulong err;
|
|
|
|
+ while ((err = ERR_get_error()))
|
|
|
|
+ warn( "Warning: Unable to load default certificate files: %s\n", ERR_error_string( err, 0 ) );
|
|
|
|
+ }
|
|
|
|
|
|
SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL );
|
|
SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL );
|
|
|
|
|
|
if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) {
|
|
if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) {
|
|
- error( "Error while loading client certificate file '%s': %s\n",
|
|
|
|
- conf->client_certfile, ERR_error_string( ERR_get_error(), 0 ) );
|
|
|
|
|
|
+ print_ssl_errors( "loading client certificate file '%s'", conf->client_certfile );
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) {
|
|
if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) {
|
|
- error( "Error while loading client private key '%s': %s\n",
|
|
|
|
- conf->client_keyfile, ERR_error_string( ERR_get_error(), 0 ) );
|
|
|
|
|
|
+ print_ssl_errors( "loading client private key '%s'", conf->client_keyfile );
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -270,10 +312,21 @@ socket_start_tls( conn_t *conn, void (*cb)( int ok, void *aux ) )
|
|
}
|
|
}
|
|
|
|
|
|
init_wakeup( &conn->ssl_fake, ssl_fake_cb, conn );
|
|
init_wakeup( &conn->ssl_fake, ssl_fake_cb, conn );
|
|
- conn->ssl = SSL_new( ((server_conf_t *)conn->conf)->SSLContext );
|
|
|
|
- if (ssl_return( "set server name", conn, SSL_set_tlsext_host_name( conn->ssl, conn->conf->host ) ) < 0)
|
|
|
|
|
|
+ if (!(conn->ssl = SSL_new( ((server_conf_t *)conn->conf)->SSLContext ))) {
|
|
|
|
+ print_ssl_errors( "initializing SSL connection" );
|
|
|
|
+ start_tls_p3( conn, 0 );
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (!SSL_set_tlsext_host_name( conn->ssl, conn->conf->host )) {
|
|
|
|
+ print_ssl_errors( "setting SSL server host name" );
|
|
|
|
+ start_tls_p3( conn, 0 );
|
|
return;
|
|
return;
|
|
- SSL_set_fd( conn->ssl, conn->fd );
|
|
|
|
|
|
+ }
|
|
|
|
+ if (!SSL_set_fd( conn->ssl, conn->fd )) {
|
|
|
|
+ print_ssl_errors( "setting SSL socket fd" );
|
|
|
|
+ start_tls_p3( conn, 0 );
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER );
|
|
SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER );
|
|
socket_expect_read( conn, 1 );
|
|
socket_expect_read( conn, 1 );
|
|
conn->state = SCK_STARTTLS;
|
|
conn->state = SCK_STARTTLS;
|
|
@@ -545,8 +598,10 @@ static void
|
|
socket_connected( conn_t *conn )
|
|
socket_connected( conn_t *conn )
|
|
{
|
|
{
|
|
#ifdef HAVE_IPV6
|
|
#ifdef HAVE_IPV6
|
|
- freeaddrinfo( conn->addrs );
|
|
|
|
- conn->addrs = 0;
|
|
|
|
|
|
+ if (conn->addrs) {
|
|
|
|
+ freeaddrinfo( conn->addrs );
|
|
|
|
+ conn->addrs = 0;
|
|
|
|
+ }
|
|
#endif
|
|
#endif
|
|
conf_notifier( &conn->notify, 0, POLLIN );
|
|
conf_notifier( &conn->notify, 0, POLLIN );
|
|
socket_expect_read( conn, 0 );
|
|
socket_expect_read( conn, 0 );
|