diff --git a/src/kernel/Communicator.h b/src/kernel/Communicator.h index 4d0d6c40..1a75d6da 100644 --- a/src/kernel/Communicator.h +++ b/src/kernel/Communicator.h @@ -56,6 +56,8 @@ protected: this->ssl_connect_timeout = ssl_connect_timeout; } + SSL_CTX *get_ssl_ctx() const { return this->ssl_ctx; } + private: virtual int create_connect_fd() { @@ -181,6 +183,8 @@ protected: this->ssl_accept_timeout = ssl_accept_timeout; } + SSL_CTX *get_ssl_ctx() const { return this->ssl_ctx; } + private: virtual CommSession *new_session(long long seq, CommConnection *conn) = 0; virtual void handle_stop(int error) { } diff --git a/src/manager/WFGlobal.cc b/src/manager/WFGlobal.cc index 9df198c6..b5cc0972 100644 --- a/src/manager/WFGlobal.cc +++ b/src/manager/WFGlobal.cc @@ -173,7 +173,7 @@ public: } SSL_CTX *get_ssl_client_ctx() { return ssl_client_ctx_; } - SSL_CTX *get_ssl_server_ctx() { return ssl_server_ctx_; } + SSL_CTX *new_ssl_server_ctx() { return SSL_CTX_new(SSLv23_server_method()); } private: __SSLManager() @@ -189,14 +189,11 @@ private: ssl_client_ctx_ = SSL_CTX_new(SSLv23_client_method()); assert(ssl_client_ctx_ != NULL); - ssl_server_ctx_ = SSL_CTX_new(SSLv23_server_method()); - assert(ssl_server_ctx_ != NULL); } ~__SSLManager() { SSL_CTX_free(ssl_client_ctx_); - SSL_CTX_free(ssl_server_ctx_); #if OPENSSL_VERSION_NUMBER < 0x10100000L //free ssl to avoid memory leak @@ -224,7 +221,6 @@ private: private: SSL_CTX *ssl_client_ctx_; - SSL_CTX *ssl_server_ctx_; }; class IOServer : public IOService @@ -559,9 +555,9 @@ SSL_CTX *WFGlobal::get_ssl_client_ctx() return __SSLManager::get_instance()->get_ssl_client_ctx(); } -SSL_CTX *WFGlobal::get_ssl_server_ctx() +SSL_CTX *WFGlobal::new_ssl_server_ctx() { - return __SSLManager::get_instance()->get_ssl_server_ctx(); + return __SSLManager::get_instance()->new_ssl_server_ctx(); } ExecQueue *WFGlobal::get_exec_queue(const std::string& queue_name) diff --git a/src/manager/WFGlobal.h b/src/manager/WFGlobal.h index 37ddaa67..6ad04bbc 100644 --- a/src/manager/WFGlobal.h +++ b/src/manager/WFGlobal.h @@ -111,7 +111,7 @@ public: static DNSCache *get_dns_cache(); static RouteManager *get_route_manager(); static SSL_CTX *get_ssl_client_ctx(); - static SSL_CTX *get_ssl_server_ctx(); + static SSL_CTX *new_ssl_server_ctx(); static ExecQueue *get_exec_queue(const std::string& queue_name); static Executor *get_compute_executor(); static IOService *get_io_service(); diff --git a/src/server/WFServer.cc b/src/server/WFServer.cc index 775cdfcc..8ffec86d 100644 --- a/src/server/WFServer.cc +++ b/src/server/WFServer.cc @@ -49,6 +49,42 @@ private: std::atomic *conn_count; }; +long WFServerBase::ssl_ctx_callback(SSL *ssl, int *al, void *arg) +{ + WFServerBase *server = (WFServerBase *)arg; + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + SSL_CTX *ssl_ctx = server->get_server_ssl_ctx(servername); + + if (!ssl_ctx) + return SSL_TLSEXT_ERR_NOACK; + + if (ssl_ctx != server->get_ssl_ctx()) + SSL_set_SSL_CTX(ssl, ssl_ctx); + + return SSL_TLSEXT_ERR_OK; +} + +int WFServerBase::init_ssl_ctx(const char *cert_file, const char *key_file) +{ + SSL_CTX *ssl_ctx = WFGlobal::new_ssl_server_ctx(); + + if (!ssl_ctx) + return -1; + + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); + if (SSL_CTX_use_certificate_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) > 0 && + SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) > 0 && + SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ssl_ctx_callback) > 0 && + SSL_CTX_set_tlsext_servername_arg(ssl_ctx, this) > 0) + { + this->set_ssl(ssl_ctx, this->params.ssl_accept_timeout); + return 0; + } + + SSL_CTX_free(ssl_ctx); + return -1; +} + int WFServerBase::init(const struct sockaddr *bind_addr, socklen_t addrlen, const char *cert_file, const char *key_file) { @@ -65,17 +101,11 @@ int WFServerBase::init(const struct sockaddr *bind_addr, socklen_t addrlen, if (key_file && cert_file) { - SSL_CTX *ssl_ctx = WFGlobal::get_ssl_server_ctx(); - - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); - if (SSL_CTX_use_certificate_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) <= 0 || - SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) <= 0) + if (this->init_ssl_ctx(cert_file, key_file) < 0) { this->deinit(); return -1; } - - this->set_ssl(ssl_ctx, params.ssl_accept_timeout); } this->scheduler = WFGlobal::get_scheduler(); @@ -131,12 +161,17 @@ void WFServerBase::handle_unbound() int WFServerBase::start(const struct sockaddr *bind_addr, socklen_t addrlen, const char *cert_file, const char *key_file) { + SSL_CTX *ssl_ctx; + if (this->init(bind_addr, addrlen, cert_file, key_file) >= 0) { if (this->scheduler->bind(this) >= 0) return 0; + ssl_ctx = this->get_ssl_ctx(); this->deinit(); + if (ssl_ctx) + SSL_CTX_free(ssl_ctx); } return -1; @@ -225,6 +260,7 @@ void WFServerBase::shutdown() void WFServerBase::wait_finish() { + SSL_CTX *ssl_ctx = this->get_ssl_ctx(); std::unique_lock lock(this->mutex); while (!this->unbind_finish) @@ -233,5 +269,7 @@ void WFServerBase::wait_finish() this->deinit(); this->unbind_finish = false; lock.unlock(); + if (ssl_ctx) + SSL_CTX_free(ssl_ctx); } diff --git a/src/server/WFServer.h b/src/server/WFServer.h index aeeaec6c..ef2aea94 100644 --- a/src/server/WFServer.h +++ b/src/server/WFServer.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -144,6 +145,15 @@ public: public: size_t get_conn_count() const { return this->conn_count; } +private: + /* Override this function to implement server that supports TLS SNI. + * "servername" will be NULL if client does not set a host name. + * Returning NULL to indicate that servername is not supported. */ + virtual SSL_CTX *get_server_ssl_ctx(const char *servername) + { + return this->get_ssl_ctx(); + } + protected: WFServerParams params; @@ -153,6 +163,8 @@ protected: private: int init(const struct sockaddr *bind_addr, socklen_t addrlen, const char *cert_file, const char *key_file); + int init_ssl_ctx(const char *cert_file, const char *key_file); + static long ssl_ctx_callback(SSL *ssl, int *al, void *arg); virtual int create_listen_fd(); virtual void handle_unbound();