Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSL3_READ_BYTES:tlsv1 alert internal error, secure sockets, OpenSSL, C++, getting HTTPS page

I want to write a simple application, which grabs the content of the HTTPS page: https://httpbin.org/html.

I know how to access its insecure (HTTP) version (http://httpbin.org/html), I just need to send a request using sockets:

std::stringstream ss;
ss << "GET /html HTTP/1.1" << "\r\n"
<< "Host: httpbin.org\r\n"
<< "Connection: close"
<< "\r\n\r\n";
std::string request = ss.str();

// socket creation, connect

send(sock, request.c_str(), request.size(), 0);

And it works. However, when using secure sockets (#include <openssl/ssl.h>) I got the following error: error:14094438:SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error when trying result = SSL_connect(ssl);

Here's the code:

#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <iostream>
#include <sstream>

int main(int argc, char **argv)
{
    int    sock;
    char   buff[1024];

    struct sockaddr_in  address;
    struct hostent     *host = NULL;

    std::string servername = "httpbin.org";

    if (!inet_aton(servername.c_str(), &address.sin_addr))
        if (host = gethostbyname(servername.c_str()))
            address.sin_addr = *(struct in_addr*)host->h_addr;
        else
            return -1;

    address.sin_port   = htons(443);
    address.sin_family = AF_INET;

    std::stringstream ss;
    ss << "GET /html HTTP/1.1" << "\r\n"
    << "Host: httpbin.org\r\n"
    << "Connection: close"
    << "\r\n\r\n";
    std::string request = ss.str();


    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1)
    {
        if (connect(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) != -1)
        {
            SSL_library_init();
            OpenSSL_add_all_algorithms();
            SSL_load_error_strings();
            SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_method());
            if (!ctx)
                return -1;

            int result = -1;
            SSL *ssl = SSL_new(ctx);
            SSL_set_fd(ssl, sock);
            result = SSL_connect(ssl);

            if (result == 0)
            {
                long error = ERR_get_error();
                const char* error_str = ERR_error_string(error, NULL);
                printf("%s\n", error_str);
                return 0;
            }

            SSL_write(ssl, request.c_str(), request.size());
            SSL_read(ssl, buff, 1024);
            printf("%s\n", buff);
            memset(buff, 0, 1024);

            SSL_free(ssl);
            SSL_CTX_free(ctx);
            close(sock);
        }
    }

    return 0;
}
like image 359
Katie Avatar asked Mar 10 '23 03:03

Katie


1 Answers

... SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error when trying result = SSL_connect(ssl);

This means that the server sends a TLSv1 alert back probably because it does not like the information send by the client in the handshake (ClientHello). This might be because the client only offers ciphers which the server does not supports, that the client uses a protocol version not supported or very often also because the server requires the TLS SNI extension to determine which certificate to provide to the client. Testing with other tools indicates that this is actually the case. The problem thus can be solved in your code by using the SNI extension:

SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);

// ADD THIS
SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (void*)servername.c_str());

result = SSL_connect(ssl);
like image 125
Steffen Ullrich Avatar answered Mar 11 '23 18:03

Steffen Ullrich