C使用openssl执行HTTPS请求 [英] C to perform HTTPS requests with openssl

查看:130
本文介绍了C使用openssl执行HTTPS请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C语言的新手,我试图在Linux Ubuntu 18.04中使用OpenSSL进行简单的SSL GET请求.我在 Simple C中找到了这个HTTP POST并使用响应的示例

I am new to C language and I am trying to perfom a simple SSL GET request with OpenSSL in Linux Ubuntu 18.04. I have this I found at Simple C example of doing an HTTP POST and consuming the response

#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 2018年9月11日

This code works well, but with some sites e.g. ghostbin.co, the connection fails... what is causing this? I compile the code using gcc test.c -o test -lssl -lcrypto. I'm using OpenSSL 1.1.1 11 Sep 2018

推荐答案

几乎总是在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

Almost always when an OpenSSL routine returns an error indication you can and should get additional information from the error stack; see https://www.openssl.org/docs/faq.html#PROG8 and the man pages e.g.
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来告诉您服务器中止了握手,警报40是SSL/TLS中信息较少的警报代码之一.它需要一点知识,然后才能在CloudFlare上找到ghostbin.co,这要求连接使用服务器名称指示aka SNI -本世纪许多SSL/TLS服务器(自顶层IPv4耗尽以来)都是如此,尤其是那些像CDN服务或共享主机那样共享的服务器.OpenSSL API确实允许客户端发送SNI,但仅使用按连接的SSL对象而不是SSL_CTX,并且使用(相当陈旧且非常笨拙的)BIO_ssl可以隐藏SSL对象,因此您需要BIO_get_ssl(bio,& sslptr),然后 SSL_set_tlsext_host_name(sslptr,name) (尽管我注意到手册页的const错误;这实际上是使用 SSL_ctrl 的宏,该宏肯定带有非const指针).

However in this case it will only tell you that the server aborted the handshake by sending alert 40, which is one of the less informative alert codes in SSL/TLS. It takes a little knowledge and looking to find ghostbin.co is on CloudFlare, which requires that connections use Server Name Indication aka SNI -- this is true of many SSL/TLS servers this century (since the toplevel IPv4 exhaust) especially those that are shared like a CDN service or shared hosting. The OpenSSL API does allow a client to send SNI, but only using the per-connection SSL object not the SSL_CTX, and with the (quite old and rather creaky) BIO_ssl the SSL object is hidden, so you'll need to BIO_get_ssl(bio,&sslptr) and then SSL_set_tlsext_host_name(sslptr,name) (although I notice the man page gets the const wrong; this is really a macro that uses SSL_ctrl which takes a definitely non-const pointer).

这篇关于C使用openssl执行HTTPS请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆