2014-03-24 143 views
3

我正在寫一個HTTPS服務器,我需要從使用SNI的ssl_accept()之前的客戶端獲取主機名。我正在使用SSL_CTX_set_tlsext_servername_callback()來接收主機名,但回調根本不會被調用。這裏是我的部分代碼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); 
} 

回答

1

SSL握手在ssl_accept中完成。服務器名稱在握手中傳輸。所以回調只能在ssl_accept中調用,而不能在之前調用。

4

我正在寫一個HTTPS服務器,我需要在使用SNI的ssl_accept()之前從客戶端獲取主機名。

你不叫SSL_CTX_set_tlsext_servername_callback。 OpenSSL庫將在握手期間爲您調用它。

您的SNI回調是而不是需要SSLv2和SSLv3客戶端。這是因爲SNI是TLS的延伸。

如果客戶端是Windows XP(或類似的不使用擴展名與TLS),那麼您的SNI回調將被調用,但servername將爲NULL。在這種情況下,您應該使用默認的服務器上下文。

如果客戶端使用TLS併發送服務器名稱,則將調用您的SNI回調。在回調中,您應該(1)確定默認證書和上下文是否正常。如果確定,則返回SSL_TLSEXT_ERR_OK。 (2)如果您可以提供更合適的證書,則使用SSL_set_SSL_CTX在新的上下文中交換並返回SSL_TLSEXT_ERR_OK

如果您遇到錯誤(如NULLservername),那麼您應該返回SSL_TLSEXT_ERR_NOACK。還有兩個其他錯誤代碼可以返回。 IIRC對這個連接都是致命的。

回調的實現細節在Serving multiple domains in one box with SNI處給出。

+0

非常感謝:))) – Omeriko