Skip to content
Snippets Groups Projects
HTTPSRequest.cpp 4.27 KiB
Newer Older
#include "HTTPSRequest.h"
#include <errno.h>
#include <iostream>
#include <string.h>

// PolarSSL internal state
mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;

HTTPSRequest::HTTPSRequest(const std::shared_ptr<URL> u) {
	if (!initTLS())
	{
		printf("failed to start TLS!");
		return;
	}
    uri = u;
    version = Version::HTTP10;
    method = Method::GET;
    userAgent = "NetRunner/0.1 PolarSSL/2.5.1";
}

bool HTTPSRequest::sendRequest(std::function<void(const HTTPResponse&)> responseCallback) const {
    std::string response;
	std::string document = uri->path;
	std::string host = uri->host;
	std::string port = std::to_string(uri->port);
    char buffer[512];
	int ret;
	unsigned flags;

	if(mbedtls_net_connect(&server_fd, host.c_str(),port.c_str(), MBEDTLS_NET_PROTO_TCP) != 0 )
	{
		return false;
	}

	if (mbedtls_ssl_config_defaults(&conf,MBEDTLS_SSL_IS_CLIENT,MBEDTLS_SSL_TRANSPORT_STREAM,MBEDTLS_SSL_PRESET_DEFAULT) != 0)
	{
		return false;
	}
	
	mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
	mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
	mbedtls_ssl_conf_ca_chain( &conf, &cacert, nullptr );
    
	if( mbedtls_ssl_setup( &ssl, &conf ) != 0 )
    {
        return false;
	}
	if(mbedtls_ssl_set_hostname( &ssl, uri->host.c_str() ) != 0 )
	{
		return false;
	}

	mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, nullptr );

	int state = mbedtls_ssl_handshake( &ssl );
    while(state != 0)
    {
        if( state != MBEDTLS_ERR_SSL_WANT_READ && state != MBEDTLS_ERR_SSL_WANT_WRITE )
        {
            printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", -state );
			return false;
        }
	}

	if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 )
	{
		printf("Invalid server cert!");
		return false;
	}

	const std::string request = methodToString(method) + std::string(" ") + document + std::string(" ") + versionToString(version) + std::string("\r\nHost: ") + host + std::string("\r\nUser-Agent: ") + userAgent + std::string("\r\n\r\n");
	
    while( ( state = mbedtls_ssl_write( &ssl, reinterpret_cast<const unsigned char*>(request.c_str()), request.length() ) ) <= 0 )
    {
        if( state != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
        {
            printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", state );
			return false;
        }
	}

	do
    {
        ret = mbedtls_ssl_read( &ssl, reinterpret_cast<unsigned char *>(buffer), 512 );
		if (ret <= 0)
			break;
		else
			response += std::string(buffer, static_cast<unsigned int>(ret));
    }
while( ret != 0 );

	// clean up after the request
	mbedtls_ssl_close_notify( &ssl );
    responseCallback(HTTPResponse(response));
	mbedtls_net_free( &server_fd );
    mbedtls_x509_crt_free( &cacert );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );
    return true;
}

const std::string HTTPSRequest::versionToString(const Version ver) const {
    switch (ver) {
        case Version::HTTP10:
            return "HTTP/1.0";
        default:
            return "ERROR";
    }
}

const std::string HTTPSRequest::methodToString(const Method meth) const {
    switch (meth) {
        case Method::GET:
            return "GET";
        case Method::POST:
            return "POST";
        default:
            return "ERROR";
    }
}

bool HTTPSRequest::initTLS()
{
	mbedtls_net_init( &server_fd );
	mbedtls_ssl_init( &ssl );
	mbedtls_ssl_config_init( &conf );
	mbedtls_x509_crt_init( &cacert );
	mbedtls_ctr_drbg_init( &ctr_drbg );

	const char *seed = "netrunner_ssl_seed$%?rvx86_despair^^%$#@";
	mbedtls_entropy_init( &entropy );
	if(mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, reinterpret_cast<const unsigned char*>(seed), strlen(seed) ) != 0 )
	{
		return false;
	}

	int ret = mbedtls_x509_crt_parse_file( &cacert, "ca-bundle.crt");
    if( ret < 0 )
    {
        printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
		return false;
    }
	return true;