2021-01-21 00:01:27 +01:00
/**
* @ file HTTPS_Client . c
* @ brief Used to download the OTA image from the server
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* Additional Infos : Connects via HTTPS and HTTPS Basic Auth to the Server .
* Downloads the image in segments
*/
2021-01-20 20:55:33 +01:00
# include "HTTPS_Client.h"
2021-01-16 00:23:02 +01:00
static const char * TAG = " https_client " ;
2021-01-20 21:40:51 +01:00
//HTTP GET data
2021-01-16 00:23:02 +01:00
static const char * REQUEST = " GET " CONFIG_OTA_HTTPS_URL " HTTP/1.1 \r \n "
" Host: " CONFIG_OTA_HTTPS_SERVER_COMMON_NAME " \r \n "
" User-Agent: esp-idf/1.0 esp32 \r \n "
" Authorization: Basic " CONFIG_OTA_HTTPS_AUTH " \r \n "
" \r \n " ;
static HTTPS_Client_t sHTTPS_ClientConfig ;
2021-01-20 22:39:18 +01:00
https_client_ret_t https_clientInitEmbedTLS ( void ) ;
https_client_ret_t errHTTPSClientConnectToServer ( void ) ;
https_client_ret_t errHTTPSClientValidateServer ( void ) ;
https_client_ret_t errHTTPSClientSendRequest ( void ) ;
2021-01-16 00:23:02 +01:00
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientInitialize ( void )
* @ brief Initialize the client
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* Initialize embedTLS
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientInitialize ( void )
2021-01-16 00:23:02 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
i32RetHTTPClient = https_clientInitEmbedTLS ( ) ;
2021-01-18 17:38:08 +01:00
if ( i32RetHTTPClient = = HTTPS_CLIENT_ERROR_INIT_EMBEDTLS )
2021-01-17 23:27:01 +01:00
{
ESP_LOGE ( TAG , " Unable to initialize EmbedTLS " ) ;
i32RetHTTPClient = HTTPS_CLIENT_ERROR ;
}
2021-01-16 00:23:02 +01:00
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientRetrieveData ( char * const cpu8Data , const uint32_t * const cpcu32DataLenght , uint32_t * pu32BytesRead )
* @ brief receive a image segment from server
* @ param cpu8Data data buffer
* @ param cpcu32DataLenght desired byte amount
2021-01-21 11:11:37 +01:00
* @ param pu32BytesRead actual received byte amount
2021-01-21 00:01:27 +01:00
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* Read segement and handle all events like EOF or timeout
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientRetrieveData ( char * const cpu8Data , const uint32_t * const cpcu32DataLenght , uint32_t * pu32BytesRead )
2021-01-16 00:23:02 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
int32_t i32RetRetrieveData = ESP_OK ;
bool bRetriveData = true ;
2021-01-20 22:39:18 +01:00
bzero ( cpu8Data , * cpcu32DataLenght ) ;
( * pu32BytesRead ) = 0U ;
2021-01-16 00:23:02 +01:00
while ( bRetriveData )
{
2021-01-18 17:38:08 +01:00
mbedtls_ssl_conf_read_timeout ( & sHTTPS_ClientConfig . conf , HTTPS_READ_TIMEOUT ) ; //set timeout
2021-01-17 23:27:01 +01:00
//Reading HTTP response
2021-01-20 22:39:18 +01:00
i32RetRetrieveData = mbedtls_ssl_read ( & sHTTPS_ClientConfig . ssl , ( unsigned char * ) ( cpu8Data + ( * pu32BytesRead ) ) , ( ( * cpcu32DataLenght ) - ( * pu32BytesRead ) ) ) ;
2021-01-17 23:27:01 +01:00
if ( i32RetRetrieveData > 0 )
{
//Data received
* pu32BytesRead = * pu32BytesRead + i32RetRetrieveData ;
2021-01-20 22:39:18 +01:00
if ( * cpcu32DataLenght > 0 )
2021-01-17 23:27:01 +01:00
{
//buffer not full yet --> read some more
bRetriveData = true ;
}
else
{
//buffer full --> stop reading
bRetriveData = false ;
}
}
if ( i32RetRetrieveData = = 0 )
{
//all data read --> stop reading
bRetriveData = false ;
pu32BytesRead = 0 ;
}
2021-01-18 17:38:08 +01:00
if ( i32RetRetrieveData = = MBEDTLS_ERR_SSL_TIMEOUT )
{
//timeout --> stop reading
bRetriveData = false ;
}
2021-01-17 23:27:01 +01:00
if ( i32RetRetrieveData = = MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY )
{
//connection is going to be closed
i32RetHTTPClient = HTTPS_CLIENT_ERROR ;
bRetriveData = false ;
}
2021-01-16 00:23:02 +01:00
}
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientReset ( void )
* @ brief reset client for next receive of image
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* reset session
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientReset ( void )
2021-01-18 12:49:52 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
2021-01-16 00:23:02 +01:00
i32RetHTTPClient = mbedtls_ssl_close_notify ( & sHTTPS_ClientConfig . ssl ) ; //close session
if ( i32RetHTTPClient ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
ESP_LOGE ( TAG , " mbedtls_ssl_close_notify returned 0x%x " , i32RetHTTPClient ) ;
}
2021-01-16 00:23:02 +01:00
mbedtls_ssl_session_reset ( & sHTTPS_ClientConfig . ssl ) ; //reset embedssl
mbedtls_net_free ( & sHTTPS_ClientConfig . server_fd ) ; //free ram
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t https_clientInitEmbedTLS ( void )
* @ brief init embedTLS
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* attach certs for tls
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t https_clientInitEmbedTLS ( void )
2021-01-17 23:27:01 +01:00
{
2021-01-16 00:23:02 +01:00
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
int32_t i32RetEmbedTLS = ESP_OK ;
2021-01-18 12:49:52 +01:00
static bool bAlreadySetup = false ;
2021-01-16 00:23:02 +01:00
mbedtls_ssl_init ( & sHTTPS_ClientConfig . ssl ) ;
mbedtls_x509_crt_init ( & sHTTPS_ClientConfig . cacert ) ;
mbedtls_ctr_drbg_init ( & sHTTPS_ClientConfig . ctr_drbg ) ;
mbedtls_ssl_config_init ( & sHTTPS_ClientConfig . conf ) ;
mbedtls_entropy_init ( & sHTTPS_ClientConfig . entropy ) ;
i32RetEmbedTLS = mbedtls_ctr_drbg_seed ( & sHTTPS_ClientConfig . ctr_drbg , mbedtls_entropy_func , & sHTTPS_ClientConfig . entropy , NULL , 0 ) ;
if ( i32RetEmbedTLS ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
ESP_LOGE ( TAG , " mbedtls_ctr_drbg_seed returned %d " , i32RetEmbedTLS ) ;
}
2021-01-16 00:23:02 +01:00
if ( i32RetEmbedTLS = = ESP_OK )
{
2021-01-17 23:27:01 +01:00
//Attaching the certificate bundle
i32RetEmbedTLS = esp_crt_bundle_attach ( & sHTTPS_ClientConfig . conf ) ;
if ( i32RetEmbedTLS ! = ESP_OK )
{
ESP_LOGE ( TAG , " esp_crt_bundle_attach returned 0x%x \n \n " , i32RetEmbedTLS ) ;
}
2021-01-16 00:23:02 +01:00
}
if ( i32RetEmbedTLS = = ESP_OK )
{
2021-01-17 23:27:01 +01:00
//Setting hostname for TLS session.
i32RetEmbedTLS = mbedtls_ssl_set_hostname ( & sHTTPS_ClientConfig . ssl , CONFIG_OTA_HTTPS_SERVER_COMMON_NAME ) ;
// Hostname set here should match CN in server certificate
if ( i32RetEmbedTLS ! = ESP_OK )
{
ESP_LOGE ( TAG , " mbedtls_ssl_set_hostname returned 0x%x " , i32RetEmbedTLS ) ;
}
2021-01-16 00:23:02 +01:00
}
if ( i32RetEmbedTLS = = ESP_OK )
{
2021-01-17 23:27:01 +01:00
//Setting up the SSL/TLS structure
i32RetEmbedTLS = mbedtls_ssl_config_defaults ( & sHTTPS_ClientConfig . conf ,
MBEDTLS_SSL_IS_CLIENT ,
MBEDTLS_SSL_TRANSPORT_STREAM ,
MBEDTLS_SSL_PRESET_DEFAULT ) ;
if ( i32RetEmbedTLS ! = ESP_OK )
{
ESP_LOGE ( TAG , " mbedtls_ssl_config_defaults returned %d " , i32RetEmbedTLS ) ;
}
2021-01-16 00:23:02 +01:00
}
if ( i32RetEmbedTLS = = ESP_OK )
{
2021-01-17 23:27:01 +01:00
mbedtls_ssl_conf_authmode ( & sHTTPS_ClientConfig . conf , MBEDTLS_SSL_VERIFY_REQUIRED ) ;
mbedtls_ssl_conf_ca_chain ( & sHTTPS_ClientConfig . conf , & sHTTPS_ClientConfig . cacert , NULL ) ;
mbedtls_ssl_conf_rng ( & sHTTPS_ClientConfig . conf , mbedtls_ctr_drbg_random , & sHTTPS_ClientConfig . ctr_drbg ) ;
2021-01-18 12:49:52 +01:00
if ( bAlreadySetup = = false ) //check if mbedtls_ssl_setup was called before
2021-01-17 23:27:01 +01:00
{
2021-01-18 12:49:52 +01:00
i32RetEmbedTLS = mbedtls_ssl_setup ( & sHTTPS_ClientConfig . ssl , & sHTTPS_ClientConfig . conf ) ; //call this only once
if ( i32RetEmbedTLS ! = ESP_OK )
{
2021-01-21 00:01:27 +01:00
ESP_LOGE ( TAG , " mbedtls_ssl_setup returned 0x%x \n " , i32RetEmbedTLS ) ;
2021-01-18 12:49:52 +01:00
}
else
{
bAlreadySetup = true ;
}
2021-01-17 23:27:01 +01:00
}
2021-01-16 00:23:02 +01:00
}
if ( i32RetEmbedTLS = = ESP_OK )
2021-01-17 23:27:01 +01:00
{
mbedtls_net_init ( & sHTTPS_ClientConfig . server_fd ) ;
}
2021-01-16 00:23:02 +01:00
if ( i32RetEmbedTLS ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_EMBEDTLS ;
}
2021-01-16 00:23:02 +01:00
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientConnectToServer ( void )
* @ brief connect to server
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* open TLS session
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientConnectToServer ( void )
2021-01-16 00:23:02 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
int32_t i32RetServerConnect = ESP_OK ;
//Connecting to server
i32RetServerConnect = mbedtls_net_connect ( & sHTTPS_ClientConfig . server_fd , CONFIG_OTA_HTTPS_SERVER_COMMON_NAME , CONFIG_OTA_HTTPS_SERVER_PORT , MBEDTLS_NET_PROTO_TCP ) ;
if ( i32RetServerConnect ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
ESP_LOGE ( TAG , " mbedtls_net_connect returned %x " , i32RetServerConnect ) ;
}
2021-01-16 00:23:02 +01:00
if ( i32RetServerConnect = = ESP_OK )
{
2021-01-18 17:38:08 +01:00
mbedtls_ssl_set_bio ( & sHTTPS_ClientConfig . ssl , & sHTTPS_ClientConfig . server_fd , mbedtls_net_send , mbedtls_net_recv , mbedtls_net_recv_timeout ) ;
2021-01-17 23:27:01 +01:00
//Performing the SSL/TLS handshake
while ( ( i32RetServerConnect = mbedtls_ssl_handshake ( & sHTTPS_ClientConfig . ssl ) ) ! = 0 )
{
if ( ( i32RetServerConnect ! = MBEDTLS_ERR_SSL_WANT_READ ) & & ( i32RetServerConnect ! = MBEDTLS_ERR_SSL_WANT_WRITE ) )
{
ESP_LOGE ( TAG , " mbedtls_ssl_handshake returned 0x%x " , i32RetServerConnect ) ;
}
}
2021-01-16 00:23:02 +01:00
}
if ( i32RetServerConnect ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER ;
}
2021-01-16 00:23:02 +01:00
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientValidateServer ( void )
* @ brief validate server
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* check CDN and cert
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientValidateServer ( void )
2021-01-16 00:23:02 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
int32_t i32RetValidateServer = ESP_OK ;
//Verifying peer X.509 certificate
if ( ( i32RetValidateServer = mbedtls_ssl_get_verify_result ( & sHTTPS_ClientConfig . ssl ) ) ! = 0 )
2021-01-17 23:27:01 +01:00
{
ESP_LOGE ( TAG , " Failed to verify peer certificate! " ) ;
}
2021-01-16 00:23:02 +01:00
if ( i32RetValidateServer ! = ESP_OK )
2021-01-17 23:27:01 +01:00
{
i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER ;
}
2021-01-16 00:23:02 +01:00
return i32RetHTTPClient ;
}
2021-01-21 00:01:27 +01:00
/**
* @ fn https_client_ret_t errHTTPSClientSendRequest ( void )
* @ brief send request to server
* @ param void
* @ return HTTPS_Client error code
* @ author Hendrik Schutter
* @ date 20.01 .2021
*
* send HTTP GET request
*/
2021-01-20 22:39:18 +01:00
https_client_ret_t errHTTPSClientSendRequest ( void )
2021-01-16 00:23:02 +01:00
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK ;
int32_t i32RetSendRequest = ESP_OK ;
uint32_t u32WrittenBytes = 0 ;
bool bWrite = true ; //flag to stop loop
//Writing HTTP request
while ( ( u32WrittenBytes < strlen ( REQUEST ) ) & & bWrite )
{
2021-01-17 23:27:01 +01:00
i32RetSendRequest = mbedtls_ssl_write ( & sHTTPS_ClientConfig . ssl ,
( const unsigned char * ) REQUEST + u32WrittenBytes ,
strlen ( REQUEST ) - u32WrittenBytes ) ;
if ( i32RetSendRequest > = 0 )
{
//bytes written
u32WrittenBytes + = i32RetSendRequest ;
}
else if ( i32RetSendRequest ! = MBEDTLS_ERR_SSL_WANT_WRITE & & i32RetSendRequest ! = MBEDTLS_ERR_SSL_WANT_READ )
{
ESP_LOGE ( TAG , " mbedtls_ssl_write returned 0x%x " , i32RetSendRequest ) ;
bWrite = false ;
}
2021-01-16 00:23:02 +01:00
}
if ( bWrite = = false )
2021-01-17 23:27:01 +01:00
{
i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST ;
}
2021-01-16 00:23:02 +01:00
return i32RetHTTPClient ;
}