Reputation: 3707
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;
}
Upvotes: 7
Views: 37445
Reputation: 11
In case it is ever useful to anyone, I had the same error (irregularly ) in my C++ program and it was driving me mad:
error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version I tried all combinations of OpenSSL, different TLS versions etc, etc.
In the end, I found the Ping I had implemented ( to check the socket was still up ) was being called while another thread's SSL_read / SSL_write() was active on the same SSL object.
Upvotes: 1
Reputation: 1868
This error is generated for a handshake failure, which is caused by a miss-match between what the client offers and what the server accepts.
For some situations, openssl will do a pretty good job of negotiating a working set between the client and server. For other situations, it's a hard failure and you will need to ammend your code. I have seen this error generated due to:
Protocol and cipher missmatch
SSL_set_min_proto_version()
SSL_set_max_proto_version()
SSL_set_cipher_list()
SNI required by the server but not offered by the client
SSL_set_tlsext_host_name()
Reused session offered by client but sessions not implemented on server
SSL_set_session()
Upvotes: 0
Reputation: 123461
...
SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error
when tryingresult = 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);
Upvotes: 6