C для выполнения HTTPS-запросов с openssl - PullRequest
0 голосов
/ 26 мая 2020

Я новичок в языке C и пытаюсь выполнить простой запрос SSL GET с OpenSSL в Linux Ubuntu 18.04. Я нашел это в Simple C Пример выполнения HTTP POST и использования ответа

#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#define HOST "www.google.com"
#define PORT "443"

int main() {

    //
    //  Initialize the variables
    //
    BIO* bio;
    SSL* ssl;
    SSL_CTX* ctx;

    //
    //   Registers the SSL/TLS ciphers and digests.
    //
    //   Basically start the security layer.
    //
    SSL_library_init();

    //
    //  Creates a new SSL_CTX object as a framework to establish TLS/SSL
    //  or DTLS enabled connections
    //
    ctx = SSL_CTX_new(SSLv23_client_method());

    //
    //  -> Error check
    //
    if (ctx == NULL)
    {
        printf("Ctx is null\n");
    }

    //
    //   Creates a new BIO chain consisting of an SSL BIO
    //
    bio = BIO_new_ssl_connect(ctx);

    //
    //  Use the variable from the beginning of the file to create a 
    //  string that contains the URL to the site that you want to connect
    //  to while also specifying the port.
    //
    BIO_set_conn_hostname(bio, HOST ":" PORT);

    //
    //   Attempts to connect the supplied BIO
    //
    if(BIO_do_connect(bio) <= 0)
    {
        printf("Failed connection\n");
        return 1;
    }
    else
    {
        printf("Connected\n");
    }

    //
    //  The bare minimum to make a HTTP request.
    //
    char* write_buf = "GET / HTTP/1.1\r\n"
                      "Host: " HOST "\r\n"
                      "Connection: close\r\n"
                      "\r\n";

    //
    //   Attempts to write len bytes from buf to BIO
    //
    if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
    {
        //
        //  Handle failed writes here
        //
        if(!BIO_should_retry(bio))
        {
            // Not worth implementing, but worth knowing.
        }

        //
        //  -> Let us know about the failed writes
        //
        printf("Failed write\n");
    }

    //
    //  Variables used to read the response from the server
    //
    int size;
    char buf[1024];

    //
    //  Read the response message
    //
    for(;;)
    {
        //
        //  Get chunks of the response 1023 at the time.
        //
        size = BIO_read(bio, buf, 1023);

        //
        //  If no more data, then exit the loop
        //
        if(size <= 0)
        {
            break;
        }

        //
        //  Terminate the string with a 0, to let know C when the string 
        //  ends.
        //
        buf[size] = 0;

        //
        //  ->  Print out the response
        //
        printf("%s", buf);
    }

    //
    //  Clean after ourselves
    //
    BIO_free_all(bio);
    SSL_CTX_free(ctx);

    return 0;
}

Этот код работает хорошо, но с некоторыми сайтами, например ghostbin. co , не удается установить соединение ... в чем причина? Я компилирую код, используя gcc test.c -o test -lssl -lcrypto. Я использую OpenSSL 1.1.1 11 сентября 2018 г.

1 Ответ

0 голосов
/ 26 мая 2020

Почти всегда, когда процедура OpenSSL возвращает сообщение об ошибке, вы можете и должны получить дополнительную информацию из стека ошибок; см. https://www.openssl.org/docs/faq.html#PROG8 и страницы руководства, например
https://www.openssl.org/docs/manmaster/man3/ERR_print_errors.html
https://www.openssl.org/docs/manmaster/man3/ERR_get_error.html
https://www.openssl.org/docs/manmaster/man3/ERR_error_string.html
https://www.openssl.org/docs/manmaster/man3/ERR_load_crypto_strings.html

Однако в этом случае он сообщит вам только, что сервер прервал рукопожатие, отправив предупреждение 40, которое является одним из менее информативных кодов предупреждений в SSL. / TLS. Требуются небольшие знания и поиск ghostbin.co на CloudFlare, что требует, чтобы соединения использовали указание имени сервера, также известное как SNI - это верно для многих серверов SSL / TLS в этом столетии (начиная с IPv4 верхнего уровня). вытяжка), особенно те, которые используются совместно как служба CDN или общий хостинг. API OpenSSL позволяет клиенту отправлять SNI, но только с использованием объекта SSL для каждого соединения, а не SSL_CTX, а с (довольно старым и довольно скрипучим) BIO_ssl объект SSL скрыт, поэтому вам нужно BIO_get_ssl(bio,&sslptr) а затем SSL_set_tlsext_host_name(sslptr,name) (хотя я заметил, что на странице руководства неверно указано значение const; на самом деле это макрос, который использует SSL_ctrl, который принимает определенно неконстантный указатель).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...