Не удается обработать указание имени сервера с библиотекой openssl с сервера - PullRequest
1 голос
/ 19 июня 2019

Я удалил некоторые сокеты на стороне сервера Windows в c и хочу добавить указание имени сервера sni для поддержки sni

, но обратный вызов servername никогда не вызывался и не может получить имя сервера, есть ли какие-либо предложения?

Я определил некоторые функции для инициализации ssl перед основной функцией:

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);
}

и вот моя основная функция:

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, ClientSocket);
    //added this line for handling server name
    SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
    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;
}

В функции do while, которую я пытался вызвать

const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);

но ничего не нашел.Я знаю, что рукопожатие clienthello находится в первых байтах, полученных из сокета.

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

И я получаю 219 байтов данных.Мне нужно обработать имя сервера и найти его, загрузить файл сертификата и выполнять непрерывную работу, и, возможно, после этого продолжать работать с более высоким уровнем в классе c # sslstream.Любое предложение?

...