未调用SSL_CTX_set_tlsext_servername_callback回调函数

我正在编写一个https服务器,我需要在使用SNI的ssl_accept()之前从客户端获取主机名。 我使用SSL_CTX_set_tlsext_servername_callback()来接收主机名,但根本不会调用回调。 这是我的代码的一部分

// Server Name Indication callback from OpenSSL static int serverNameCallback(SSL *ssl, int *ad, void *arg) { if (ssl == NULL) return SSL_TLSEXT_ERR_NOACK; const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); printf("ServerName: %s\n", servername); } int main() { //some code const SSL_METHOD *method; SSL_CTX *ctx; method = SSLv3_server_method(); ctx = SSL_CTX_new(method); if ( ctx == NULL ) { printf("SSL_ctx_new() error\n"); } int ret = SSL_CTX_set_tlsext_servername_callback(ctx, serverNameCallback); } 

我正在编写一个https服务器,我需要在使用SNI的ssl_accept()之前从客户端获取主机名。

您不需要调用SSL_CTX_set_tlsext_servername_callback 。 OpenSSL库将在握手期间为您调用它。

SSLv2和SSLv3客户端不会调用您的SNI回调。 那是因为SNI是TLS扩展。

如果客户端是Windows XP(或类似的不使用带有TLS的扩展),则将调用您的SNI回调,但servername将为NULL 。 在这种情况下,您应该使用默认服务器上下文。

如果客户端使用TLS并发送服务器名称,则将调用您的SNI回调。 在回调中,您应该(1)确定默认证书和上下文是否正常。 如果没有问题,则返回SSL_TLSEXT_ERR_OK 。 (2)如果您可以提供更合适的证书,则使用SSL_set_SSL_CTX交换新上下文并返回SSL_TLSEXT_ERR_OK

如果遇到错误(如NULL servername ),则应返回SSL_TLSEXT_ERR_NOACK 。 您还可以返回另外两个错误代码。 两者都是致命的,IIRC。

回调的实现细节在使用SNI在一个框中服务多个域时给出。

SSL握手在ssl_accept内完成。 服务器名称在握手中传输。 因此,回调只能在ssl_accept中调用,而不能在之前调用。