179 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  IXSocketMbedTLS.cpp
 | 
						|
 *  Author: Benjamin Sergeant
 | 
						|
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
						|
 *
 | 
						|
 *  Some code taken from
 | 
						|
 *  https://github.com/rottor12/WsClientLib/blob/master/lib/src/WsClientLib.cpp
 | 
						|
 *  and mini_client.c example from mbedtls
 | 
						|
 */
 | 
						|
 | 
						|
#include "IXSocketMbedTLS.h"
 | 
						|
#include "IXSocketConnect.h"
 | 
						|
#include "IXNetSystem.h"
 | 
						|
#include "IXSocket.h"
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
namespace ix
 | 
						|
{
 | 
						|
    SocketMbedTLS::~SocketMbedTLS()
 | 
						|
    {
 | 
						|
        close();
 | 
						|
    }
 | 
						|
 | 
						|
    bool SocketMbedTLS::init(const std::string& host, std::string& errMsg)
 | 
						|
    {
 | 
						|
        std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
 | 
						|
        mbedtls_ssl_init(&_ssl);
 | 
						|
        mbedtls_ssl_config_init(&_conf);
 | 
						|
        mbedtls_ctr_drbg_init(&_ctr_drbg);
 | 
						|
 | 
						|
        const char *pers = "IXSocketMbedTLS";
 | 
						|
 | 
						|
        mbedtls_entropy_init(&_entropy);
 | 
						|
        if (mbedtls_ctr_drbg_seed(&_ctr_drbg,
 | 
						|
                                  mbedtls_entropy_func,
 | 
						|
                                  &_entropy,
 | 
						|
                                  (const unsigned char *) pers,
 | 
						|
                                  strlen(pers)) != 0)
 | 
						|
        {
 | 
						|
            errMsg = "Setting entropy seed failed";
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (mbedtls_ssl_config_defaults(&_conf,
 | 
						|
                                        MBEDTLS_SSL_IS_CLIENT,
 | 
						|
                                        MBEDTLS_SSL_TRANSPORT_STREAM,
 | 
						|
                                        MBEDTLS_SSL_PRESET_DEFAULT ) != 0)
 | 
						|
        {
 | 
						|
            errMsg = "Setting config default failed";
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        mbedtls_ssl_conf_rng(&_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
 | 
						|
 | 
						|
        // FIXME: cert verification is disabled
 | 
						|
        mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_NONE);
 | 
						|
 | 
						|
        if (mbedtls_ssl_setup(&_ssl, &_conf) != 0)
 | 
						|
        {
 | 
						|
            errMsg = "SSL setup failed";
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
 | 
						|
        {
 | 
						|
            errMsg = "SNI setup failed";
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool SocketMbedTLS::connect(const std::string& host,
 | 
						|
                                int port,
 | 
						|
                                std::string& errMsg,
 | 
						|
                                const CancellationRequest& isCancellationRequested)
 | 
						|
    {
 | 
						|
        {
 | 
						|
            std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
            _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
 | 
						|
            if (_sockfd == -1) return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!init(host, errMsg))
 | 
						|
        {
 | 
						|
            close();
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        mbedtls_ssl_set_bio(&_ssl, &_sockfd, mbedtls_net_send, mbedtls_net_recv, NULL);
 | 
						|
 | 
						|
        int res;
 | 
						|
        do
 | 
						|
        {
 | 
						|
            std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
            res = mbedtls_ssl_handshake(&_ssl);
 | 
						|
        }
 | 
						|
        while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
 | 
						|
 | 
						|
        if (res != 0)
 | 
						|
        {
 | 
						|
            char buf[256];
 | 
						|
            mbedtls_strerror(res, buf, sizeof(buf));
 | 
						|
 | 
						|
            errMsg = "error in handshake : ";
 | 
						|
            errMsg += buf;
 | 
						|
 | 
						|
            close();
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    void SocketMbedTLS::close()
 | 
						|
    {
 | 
						|
        std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
 | 
						|
        mbedtls_ssl_free(&_ssl);
 | 
						|
        mbedtls_ssl_config_free(&_conf);
 | 
						|
        mbedtls_ctr_drbg_free(&_ctr_drbg);
 | 
						|
        mbedtls_entropy_free(&_entropy);
 | 
						|
 | 
						|
        Socket::close();
 | 
						|
    }
 | 
						|
 | 
						|
    ssize_t SocketMbedTLS::send(char* buf, size_t nbyte)
 | 
						|
    {
 | 
						|
        ssize_t sent = 0;
 | 
						|
 | 
						|
        while (nbyte > 0)
 | 
						|
        {
 | 
						|
            std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
 | 
						|
            ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
 | 
						|
 | 
						|
            if (res > 0) {
 | 
						|
                nbyte -= res;
 | 
						|
                sent += res;
 | 
						|
            } else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) {
 | 
						|
                errno = EWOULDBLOCK;
 | 
						|
                return -1;
 | 
						|
            } else {
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return sent;
 | 
						|
    }
 | 
						|
 | 
						|
    ssize_t SocketMbedTLS::send(const std::string& buffer)
 | 
						|
    {
 | 
						|
        return send((char*)&buffer[0], buffer.size());
 | 
						|
    }
 | 
						|
 | 
						|
    ssize_t SocketMbedTLS::recv(void* buf, size_t nbyte)
 | 
						|
    {
 | 
						|
        while (true)
 | 
						|
        {
 | 
						|
            std::lock_guard<std::mutex> lock(_mutex);
 | 
						|
 | 
						|
            ssize_t res = mbedtls_ssl_read(&_ssl, (unsigned char*) buf, (int) nbyte);
 | 
						|
 | 
						|
            if (res > 0)
 | 
						|
            {
 | 
						|
                return res;
 | 
						|
            }
 | 
						|
 | 
						|
            if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
 | 
						|
            {
 | 
						|
                errno = EWOULDBLOCK;
 | 
						|
            }
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
}
 |