How to handle servername indication with openssl library from server

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

How to handle servername indication with openssl library from server

OpenSSL - User mailing list
I've develepted some windows server side socket in c
and want to add sni server name indication to support sni

but servername callback never called and cant get servername
is there any suggestion?

I've defined some functions for initializing ssl before main function:

    void init_openssl()
    {
        SSL_load_error_strings();
        OpenSSL_add_ssl_algorithms();
    }
    
    SSL_CTX *create_context()
    {
        const SSL_METHOD *method;
        SSL_CTX *ctx;
    
        //method = SSLv23_server_method();
        method = TLSv1_1_server_method();
    
        ctx = SSL_CTX_new(method);
        if (!ctx) {
            perror("Unable to create SSL context");
            ERR_print_errors_fp(stderr);
            exit(EXIT_FAILURE);
        }
    
        return ctx;
    }
    
    void configure_context(SSL_CTX *ctx)
    {
        
        SSL_CTX_set_ecdh_auto(ctx, 1);
    
        /* Set the key and cert */
        if (SSL_CTX_use_certificate_file(ctx, "somesite.cer", SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stderr);
    
            exit(EXIT_FAILURE);
        }
    
        if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stderr);
    
            exit(EXIT_FAILURE);
        }
    }
    
    static int ssl_servername_cb(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);
    }
    

and here is my main function:

    int main()
    {
    
    SSL_CTX *ctx;
    
        init_openssl();
        ctx = create_context();
    
        configure_context(ctx);
        
        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
        
    
    
        WSADATA wsaData;
        int iResult;
    
        SOCKET ListenSocket = INVALID_SOCKET;
        SOCKET ClientSocket = INVALID_SOCKET;
    
        struct addrinfo *result = NULL;
        struct addrinfo hints;
    
        int iSendResult;
        char recvbuf[DEFAULT_BUFLEN];
        int recvbuflen = DEFAULT_BUFLEN;
    
        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != 0) {
            printf("WSAStartup failed with error: %d\n", iResult);
            return 1;
        }
    
        ZeroMemory(&hints, sizeof(hints));
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_PASSIVE;
    
        // Resolve the server address and port
        //iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
        iResult = getaddrinfo("192.168.200.1", DEFAULT_PORT, &hints, &result);
        //iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
        
        if (iResult != 0) {
            printf("getaddrinfo failed with error: %d\n", iResult);
            WSACleanup();
            return 1;
        }
    
        // Create a SOCKET for connecting to server    
        ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
        if (ListenSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return 1;
        }
    
        // Setup the TCP listening socket    
        iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            printf("bind failed with error: %d\n", WSAGetLastError());
            freeaddrinfo(result);
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        freeaddrinfo(result);
    
        iResult = listen(ListenSocket, SOMAXCONN);
        if (iResult == SOCKET_ERROR) {
            printf("listen failed with error: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        // Accept a client socket        
        ClientSocket = accept(ListenSocket, NULL, NULL);    
        SSL *ssl;
        
        if (ClientSocket == INVALID_SOCKET) {
            printf("accept failed with error: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        // No longer need server socket
        closesocket(ListenSocket);
    
        // Receive until the peer shuts down the connection
        do {
            
            ssl = SSL_new(ctx);
            SSL_set_fd(ssl, ListenSocket);
            //int rr = SSL_accept(ssl);
    
            iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
            
            //int type=SSL_get_servername_type(ssl);
            //const char[] x=SSL_get_servername(ssl, type);
            //const char *zx= SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
            
            if (iResult > 0) {
                printf("Bytes received: %d\n", iResult);
    
                // Echo the buffer back to the sender
                iSendResult = send(ClientSocket, recvbuf, iResult, 0);
                if (iSendResult == SOCKET_ERROR) {
                    printf("send failed with error: %d\n", WSAGetLastError());
                    closesocket(ClientSocket);
                    WSACleanup();
                    return 1;
                }
                printf("Bytes sent: %d\n", iSendResult);
            }
            else if (iResult == 0)
                printf("Connection closing...\n");
            else {
                printf("recv failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
    
        } while (iResult > 0);
    
    return 0;
    }

In do while function I've tried to call

    const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
but didn't find anything.
I know that clienthello handshake is in first bytes that is received from socket.

    iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);

And I receive 219 bytes of data. I need to handle servername and find it, and load certificate file and do continuous job, and maybe after that keep going with higher level in c# sslstream class.
Any suggestion?

Reply | Threaded
Open this post in threaded view
|

Re: How to handle servername indication with openssl library from server

Skip Carter
if this is a C++ program, be sure to use C linkage for the callback e.g.

extern "C" {
    static int ssl_servername_cb(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);
    }

}

That is all I can think of.

-- 
Dr Everett (Skip) Carter [hidden email]
Taygeta Scientific Inc 607 Charles Ave Seaside CA 93955 831-641-0645 x103

signature.asc (673 bytes) Download Attachment