diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/Application-Protocols/network_transport/using_mbedtls/using_wolfSSL/using_wolfSSL.c')
-rw-r--r-- | FreeRTOS-Plus/Source/Application-Protocols/network_transport/using_mbedtls/using_wolfSSL/using_wolfSSL.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Source/Application-Protocols/network_transport/using_mbedtls/using_wolfSSL/using_wolfSSL.c b/FreeRTOS-Plus/Source/Application-Protocols/network_transport/using_mbedtls/using_wolfSSL/using_wolfSSL.c new file mode 100644 index 000000000..6c651f623 --- /dev/null +++ b/FreeRTOS-Plus/Source/Application-Protocols/network_transport/using_mbedtls/using_wolfSSL/using_wolfSSL.c @@ -0,0 +1,536 @@ +/* + * FreeRTOS V202107.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/** + * @file using_wolfSSL.c + * @brief TLS transport interface implementations. This implementation uses + * wolfSSL. + */ + +/* Standard includes. */ +#include <string.h> + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* TLS transport header. */ +#include "using_wolfSSL.h" + +/* FreeRTOS Socket wrapper include. */ +#include "sockets_wrapper.h" + + +/* wolfSSL user settings header */ +#include "user_settings.h" + +/* Demo Specific configs. */ +#include "demo_config.h" + +/** + * @brief Initialize the TLS structures in a network connection. + * + * @param[in] pSslContext The SSL context to initialize. + */ +static void sslContextInit( SSLContext_t * pSslContext ); + +/** + * @brief Free the TLS structures in a network connection. + * + * @param[in] pSslContext The SSL context to free. + */ +static void sslContextFree( SSLContext_t * pSslContext ); + +/** + * @brief Set up TLS on a TCP connection. + * + * @param[in] pNetworkContext Network context. + * @param[in] pHostName Remote host name, used for server name indication. + * @param[in] pNetworkCredentials TLS setup parameters. + * + * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INSUFFICIENT_MEMORY, #TLS_TRANSPORT_INVALID_CREDENTIALS, + * #TLS_TRANSPORT_HANDSHAKE_FAILED, or #TLS_TRANSPORT_INTERNAL_ERROR. + */ +static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext, + const char * pHostName, + const NetworkCredentials_t * pNetworkCredentials ); + +/** + * @brief Initialize TLS component. + * + * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INSUFFICIENT_MEMORY, or #TLS_TRANSPORT_INTERNAL_ERROR. + */ +static TlsTransportStatus_t initTLS( void ); + +/* + * @brief Receive date from the socket passed as the context + * + * @param[in] ssl WOLFSSL object. + * @param[in] buf Buffer for received data + * @param[in] sz Size to receive + * @param[in] context Socket to be received from + * + * @return received size( > 0 ), #WOLFSSL_CBIO_ERR_CONN_CLOSE, #WOLFSSL_CBIO_ERR_WANT_READ. + */ +static int wolfSSL_IORecvGlue( WOLFSSL * ssl, + char * buf, + int sz, + void * context ); + +/* + * @brief Send date to the socket passed as the context + * + * @param[in] ssl WOLFSSL object. + * @param[in] buf Buffer for data to be sent + * @param[in] sz Size to send + * @param[in] context Socket to be sent to + * + * @return received size( > 0 ), #WOLFSSL_CBIO_ERR_CONN_CLOSE, #WOLFSSL_CBIO_ERR_WANT_WRITE. + */ +static int wolfSSL_IOSendGlue( WOLFSSL * ssl, + char * buf, + int sz, + void * context ); + +/* + * @brief Load credentials from file/buffer + * + * @param[in] pNetCtx NetworkContext_t + * @param[in] pNetCred NetworkCredentials_t + * + * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INVALID_CREDENTIALS. + */ +static TlsTransportStatus_t loadCredentials( NetworkContext_t * pNetCtx, + const NetworkCredentials_t * pNetCred ); + +/*-----------------------------------------------------------*/ +static int wolfSSL_IORecvGlue( WOLFSSL * ssl, + char * buf, + int sz, + void * context ) +{ + ( void ) ssl; /* to prevent unused warning*/ + BaseType_t read = 0; + + Socket_t xSocket = ( Socket_t ) context; + + + read = FreeRTOS_recv( xSocket, ( void * ) buf, ( size_t ) sz, 0 ); + + if( ( read == 0 ) || + ( read == -pdFREERTOS_ERRNO_EWOULDBLOCK ) ) + { + read = WOLFSSL_CBIO_ERR_WANT_READ; + } + else if( read == -pdFREERTOS_ERRNO_ENOTCONN ) + { + read = WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else + { + /* do nothing */ + } + + return ( int ) read; +} +/*-----------------------------------------------------------*/ + +static int wolfSSL_IOSendGlue( WOLFSSL * ssl, + char * buf, + int sz, + void * context ) +{ + ( void ) ssl; /* to prevent unused warning*/ + Socket_t xSocket = ( Socket_t ) context; + BaseType_t sent = FreeRTOS_send( xSocket, ( void * ) buf, ( size_t ) sz, 0 ); + + if( sent == -pdFREERTOS_ERRNO_EWOULDBLOCK ) + { + sent = WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if( sent == -pdFREERTOS_ERRNO_ENOTCONN ) + { + sent = WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else + { + /* do nothing */ + } + + return ( int ) sent; +} + +/*-----------------------------------------------------------*/ +static TlsTransportStatus_t initTLS( void ) +{ + /* initialize wolfSSL */ + wolfSSL_Init(); + + #ifdef DEBUG_WOLFSSL + wolfSSL_Debugging_ON(); + #endif + + return TLS_TRANSPORT_SUCCESS; +} + +/*-----------------------------------------------------------*/ +static TlsTransportStatus_t loadCredentials( NetworkContext_t * pNetCtx, + const NetworkCredentials_t * pNetCred ) +{ + TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS; + + configASSERT( pNetCtx != NULL ); + configASSERT( pNetCred != NULL ); + + #if defined( democonfigCREDENTIALS_IN_BUFFER ) + if( wolfSSL_CTX_load_verify_buffer( pNetCtx->sslContext.ctx, + ( const byte * ) ( pNetCred->pRootCa ), ( long ) ( pNetCred->rootCaSize ), + SSL_FILETYPE_PEM ) == SSL_SUCCESS ) + { + if( wolfSSL_CTX_use_certificate_buffer( pNetCtx->sslContext.ctx, + ( const byte * ) ( pNetCred->pClientCert ), ( long ) ( pNetCred->clientCertSize ), + SSL_FILETYPE_PEM ) == SSL_SUCCESS ) + { + if( wolfSSL_CTX_use_PrivateKey_buffer( pNetCtx->sslContext.ctx, + ( const byte * ) ( pNetCred->pPrivateKey ), ( long ) ( pNetCred->privateKeySize ), + SSL_FILETYPE_PEM ) == SSL_SUCCESS ) + { + returnStatus = TLS_TRANSPORT_SUCCESS; + } + else + { + LogError( ( "Failed to load client-private-key from buffer" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + } + else + { + LogError( ( "Failed to load client-certificate from buffer" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + } + else + { + LogError( ( "Failed to load ca-certificate from buffer" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + + return returnStatus; + #else /* if defined( democonfigCREDENTIALS_IN_BUFFER ) */ + if( wolfSSL_CTX_load_verify_locations( pNetCtx->sslContext.ctx, + ( const char * ) ( pNetCred->pRootCa ), NULL ) == SSL_SUCCESS ) + { + if( wolfSSL_CTX_use_certificate_file( pNetCtx->sslContext.ctx, + ( const char * ) ( pNetCred->pClientCert ), SSL_FILETYPE_PEM ) + == SSL_SUCCESS ) + { + if( wolfSSL_CTX_use_PrivateKey_file( pNetCtx->sslContext.ctx, + ( const char * ) ( pNetCred->pPrivateKey ), SSL_FILETYPE_PEM ) + == SSL_SUCCESS ) + { + returnStatus = TLS_TRANSPORT_SUCCESS; + } + else + { + LogError( ( "Failed to load client-private-key file" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + } + else + { + LogError( ( "Failed to load client-certificate file" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + } + else + { + LogError( ( "Failed to load ca-certificate file" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + return returnStatus; + #endif /* if defined( democonfigCREDENTIALS_IN_BUFFER ) */ +} + +/*-----------------------------------------------------------*/ + +static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetCtx, + const char * pHostName, + const NetworkCredentials_t * pNetCred ) +{ + TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS; + Socket_t xSocket = { 0 }; + + configASSERT( pNetCtx != NULL ); + configASSERT( pHostName != NULL ); + configASSERT( pNetCred != NULL ); + configASSERT( pNetCred->pRootCa != NULL ); + configASSERT( pNetCtx->tcpSocket != NULL ); + + if( pNetCtx->sslContext.ctx == NULL ) + { + /* Attempt to create a context that uses the TLS 1.3 or 1.2 */ + pNetCtx->sslContext.ctx = + wolfSSL_CTX_new( wolfSSLv23_client_method_ex( NULL ) ); + } + + if( pNetCtx->sslContext.ctx != NULL ) + { + /* load credentials from file */ + if( loadCredentials( pNetCtx, pNetCred ) == TLS_TRANSPORT_SUCCESS ) + { + /* create a ssl object */ + pNetCtx->sslContext.ssl = + wolfSSL_new( pNetCtx->sslContext.ctx ); + + if( pNetCtx->sslContext.ssl != NULL ) + { + xSocket = pNetCtx->tcpSocket; + + /* set Recv/Send glue functions to the WOLFSSL object */ + wolfSSL_SSLSetIORecv( pNetCtx->sslContext.ssl, + wolfSSL_IORecvGlue ); + wolfSSL_SSLSetIOSend( pNetCtx->sslContext.ssl, + wolfSSL_IOSendGlue ); + + /* set socket as a context of read/send glue funcs */ + wolfSSL_SetIOReadCtx( pNetCtx->sslContext.ssl, xSocket ); + wolfSSL_SetIOWriteCtx( pNetCtx->sslContext.ssl, xSocket ); + + /* let wolfSSL perform tls handshake */ + if( wolfSSL_connect( pNetCtx->sslContext.ssl ) + == SSL_SUCCESS ) + { + returnStatus = TLS_TRANSPORT_SUCCESS; + } + else + { + wolfSSL_shutdown( pNetCtx->sslContext.ssl ); + wolfSSL_free( pNetCtx->sslContext.ssl ); + pNetCtx->sslContext.ssl = NULL; + wolfSSL_CTX_free( pNetCtx->sslContext.ctx ); + pNetCtx->sslContext.ctx = NULL; + + LogError( ( "Failed to establish a TLS connection" ) ); + returnStatus = TLS_TRANSPORT_HANDSHAKE_FAILED; + } + } + else + { + wolfSSL_CTX_free( pNetCtx->sslContext.ctx ); + pNetCtx->sslContext.ctx = NULL; + + LogError( ( "Failed to create wolfSSL object" ) ); + returnStatus = TLS_TRANSPORT_INTERNAL_ERROR; + } + } + else + { + wolfSSL_CTX_free( pNetCtx->sslContext.ctx ); + pNetCtx->sslContext.ctx = NULL; + + LogError( ( "Failed to load credentials" ) ); + returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS; + } + } + else + { + LogError( ( "Failed to create a wolfSSL_CTX" ) ); + returnStatus = TLS_TRANSPORT_CONNECT_FAILURE; + } + + return returnStatus; +} + +/*-----------------------------------------------------------*/ + + +/*-----------------------------------------------------------*/ + +TlsTransportStatus_t TLS_FreeRTOS_Connect( NetworkContext_t * pNetworkContext, + const char * pHostName, + uint16_t port, + const NetworkCredentials_t * pNetworkCredentials, + uint32_t receiveTimeoutMs, + uint32_t sendTimeoutMs ) +{ + TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS; + BaseType_t socketStatus = 0; + + + if( ( pNetworkContext == NULL ) || + ( pHostName == NULL ) || + ( pNetworkCredentials == NULL ) ) + { + LogError( ( "Invalid input parameter(s): Arguments cannot be NULL. pNetworkContext=%p, " + "pHostName=%p, pNetworkCredentials=%p.", + pNetworkContext, + pHostName, + pNetworkCredentials ) ); + returnStatus = TLS_TRANSPORT_INVALID_PARAMETER; + } + else if( ( pNetworkCredentials->pRootCa == NULL ) ) + { + LogError( ( "pRootCa cannot be NULL." ) ); + returnStatus = TLS_TRANSPORT_INVALID_PARAMETER; + } + + /* Establish a TCP connection with the server. */ + if( returnStatus == TLS_TRANSPORT_SUCCESS ) + { + socketStatus = Sockets_Connect( &( pNetworkContext->tcpSocket ), + pHostName, + port, + receiveTimeoutMs, + sendTimeoutMs ); + + if( socketStatus != 0 ) + { + LogError( ( "Failed to connect to %s with error %d.", + pHostName, + socketStatus ) ); + returnStatus = TLS_TRANSPORT_CONNECT_FAILURE; + } + } + + /* Initialize tls. */ + if( returnStatus == TLS_TRANSPORT_SUCCESS ) + { + returnStatus = initTLS(); + } + + /* Perform TLS handshake. */ + if( returnStatus == TLS_TRANSPORT_SUCCESS ) + { + returnStatus = tlsSetup( pNetworkContext, pHostName, pNetworkCredentials ); + } + + /* Clean up on failure. */ + if( returnStatus != TLS_TRANSPORT_SUCCESS ) + { + if( pNetworkContext->tcpSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_closesocket( pNetworkContext->tcpSocket ); + } + } + else + { + LogInfo( ( "(Network connection %p) Connection to %s established.", + pNetworkContext, + pHostName ) ); + } + + return returnStatus; +} + +/*-----------------------------------------------------------*/ + +void TLS_FreeRTOS_Disconnect( NetworkContext_t * pNetworkContext ) +{ + WOLFSSL * pSsl = pNetworkContext->sslContext.ssl; + WOLFSSL_CTX * pCtx = NULL; + + /* shutdown an active TLS connection */ + wolfSSL_shutdown( pSsl ); + + /* cleanup WOLFSSL object */ + wolfSSL_free( pSsl ); + pNetworkContext->sslContext.ssl = NULL; + + /* Call socket shutdown function to close connection. */ + Sockets_Disconnect( pNetworkContext->tcpSocket ); + + /* free WOLFSSL_CTX object*/ + pCtx = pNetworkContext->sslContext.ctx; + + wolfSSL_CTX_free( pCtx ); + pNetworkContext->sslContext.ctx = NULL; + + wolfSSL_Cleanup(); +} + +/*-----------------------------------------------------------*/ + +int32_t TLS_FreeRTOS_recv( NetworkContext_t * pNetworkContext, + void * pBuffer, + size_t bytesToRecv ) +{ + int32_t tlsStatus = 0; + int iResult = 0; + WOLFSSL * pSsl = pNetworkContext->sslContext.ssl; + + iResult = wolfSSL_read( pSsl, pBuffer, bytesToRecv ); + + if( iResult > 0 ) + { + tlsStatus = iResult; + } + else if( wolfSSL_want_read( pSsl ) == 1 ) + { + tlsStatus = 0; + } + else + { + tlsStatus = wolfSSL_state( pSsl ); + LogError( ( "Error from wolfSSL_read %d : %s ", + iResult, wolfSSL_ERR_reason_error_string( tlsStatus ) ) ); + } + + return tlsStatus; +} + +/*-----------------------------------------------------------*/ + +int32_t TLS_FreeRTOS_send( NetworkContext_t * pNetworkContext, + const void * pBuffer, + size_t bytesToSend ) +{ + int32_t tlsStatus = 0; + int iResult = 0; + WOLFSSL * pSsl = pNetworkContext->sslContext.ssl; + + iResult = wolfSSL_write( pSsl, pBuffer, bytesToSend ); + + if( iResult > 0 ) + { + tlsStatus = iResult; + } + else if( wolfSSL_want_write( pSsl ) == 1 ) + { + tlsStatus = 0; + } + else + { + tlsStatus = wolfSSL_state( pSsl ); + LogError( ( "Error from wolfSL_write %d : %s ", + iResult, wolfSSL_ERR_reason_error_string( tlsStatus ) ) ); + } + + return tlsStatus; +} +/*-----------------------------------------------------------*/ |