Fix MISRA warnings for platform code used by MQTT demos (#337)

In addition to fixing MISRA warnings, code is updated to have complexity <= 8. Also, this adds changes from PR #313, which allows the support of simultaneous connections in the mbedTLS transport wrapper. 

Co-authored-by: Muneeb Ahmed <54290492+muneebahmed10@users.noreply.github.com>
This commit is contained in:
Oscar Michael Abrina
2020-10-13 12:55:26 -07:00
committed by GitHub
co-authored by Muneeb Ahmed
parent 02aafc3a46
commit 5f0bf944cb
13 changed files with 1196 additions and 887 deletions
File diff suppressed because it is too large Load Diff
@@ -18,7 +18,6 @@
* 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.
*
*/
/**
@@ -26,10 +25,14 @@
* @brief Stringification utilities for high-level and low-level codes of mbed TLS.
*/
#ifndef MBEDTLS_ERROR_H_
#define MBEDTLS_ERROR_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Translate an mbed TLS high level code into its string representation.
@@ -40,7 +43,7 @@
*
* @warning The string returned by this function must never be modified.
*/
const char * mbedtls_strerror_highlevel( int errnum );
const char * mbedtls_strerror_highlevel( int32_t errnum );
/**
* @brief Translate an mbed TLS low level code into its string representation,
@@ -51,8 +54,10 @@ const char * mbedtls_strerror_highlevel( int errnum );
*
* @warning The string returned by this function must never be modified.
*/
const char * mbedtls_strerror_lowlevel( int errnum );
const char * mbedtls_strerror_lowlevel( int32_t errnum );
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* ifndef MBEDTLS_ERROR_H_ */
@@ -54,7 +54,7 @@ void * mbedtls_platform_calloc( size_t nmemb,
if( totalSize > 0 )
{
/* Overflow check. */
if( totalSize / size == nmemb )
if( ( totalSize / size ) == nmemb )
{
pBuffer = pvPortMalloc( totalSize );
@@ -33,7 +33,7 @@
#include "retry_utils.h"
#define _MILLISECONDS_PER_SECOND ( 1000U ) /**< @brief Milliseconds per second. */
#define MILLISECONDS_PER_SECOND ( 1000U ) /**< @brief Milliseconds per second. */
extern UBaseType_t uxRand( void );
@@ -42,17 +42,17 @@ extern UBaseType_t uxRand( void );
RetryUtilsStatus_t RetryUtils_BackoffAndSleep( RetryUtilsParams_t * pRetryParams )
{
RetryUtilsStatus_t status = RetryUtilsRetriesExhausted;
int32_t backOffDelayMs = 0;
uint32_t backOffDelayMs = 0;
/* If pRetryParams->maxRetryAttempts is set to 0, try forever. */
if( ( pRetryParams->attemptsDone < pRetryParams->maxRetryAttempts ) ||
( 0 == pRetryParams->maxRetryAttempts ) )
( 0U == pRetryParams->maxRetryAttempts ) )
{
/* Choose a random value for back-off time between 0 and the max jitter value. */
backOffDelayMs = uxRand() % pRetryParams->nextJitterMax;
/* Wait for backoff time to expire for the next retry. */
vTaskDelay( pdMS_TO_TICKS( backOffDelayMs * _MILLISECONDS_PER_SECOND ) );
vTaskDelay( pdMS_TO_TICKS( backOffDelayMs * MILLISECONDS_PER_SECOND ) );
/* Increment backoff counts. */
pRetryParams->attemptsDone++;
@@ -30,6 +30,7 @@
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DNS.h"
/**************************************************/
/******* DO NOT CHANGE the following order ********/
@@ -70,12 +70,14 @@
*/
typedef struct SSLContext
{
mbedtls_ssl_config config; /**< @brief SSL connection configuration. */
mbedtls_ssl_context context; /**< @brief SSL connection context */
mbedtls_x509_crt_profile certProfile; /**< @brief Certificate security profile for this connection. */
mbedtls_x509_crt rootCa; /**< @brief Root CA certificate context. */
mbedtls_x509_crt clientCert; /**< @brief Client certificate context. */
mbedtls_pk_context privKey; /**< @brief Client private key context. */
mbedtls_ssl_config config; /**< @brief SSL connection configuration. */
mbedtls_ssl_context context; /**< @brief SSL connection context */
mbedtls_x509_crt_profile certProfile; /**< @brief Certificate security profile for this connection. */
mbedtls_x509_crt rootCa; /**< @brief Root CA certificate context. */
mbedtls_x509_crt clientCert; /**< @brief Client certificate context. */
mbedtls_pk_context privKey; /**< @brief Client private key context. */
mbedtls_entropy_context entropyContext; /**< @brief Entropy context for random number generation. */
mbedtls_ctr_drbg_context ctrDrgbContext; /**< @brief CTR DRBG context for random number generation. */
} SSLContext_t;
/**
@@ -94,31 +96,26 @@ struct NetworkContext
typedef struct NetworkCredentials
{
/**
* @brief Set this to a non-NULL value to use ALPN.
*
* This string must be NULL-terminated.
* @brief To use ALPN, set this to a NULL-terminated list of supported
* protocols in decreasing order of preference.
*
* See [this link]
* (https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/)
* for more information.
*/
const char * pAlpnProtos;
const char ** pAlpnProtos;
/**
* @brief Disable server name indication (SNI) for a TLS session.
*/
BaseType_t disableSni;
const unsigned char * pRootCa; /**< @brief String representing a trusted server root certificate. */
size_t rootCaSize; /**< @brief Size associated with #IotNetworkCredentials.pRootCa. */
const unsigned char * pClientCert; /**< @brief String representing the client certificate. */
size_t clientCertSize; /**< @brief Size associated with #IotNetworkCredentials.pClientCert. */
const unsigned char * pPrivateKey; /**< @brief String representing the client certificate's private key. */
size_t privateKeySize; /**< @brief Size associated with #IotNetworkCredentials.pPrivateKey. */
const unsigned char * pUserName; /**< @brief String representing the username for MQTT. */
size_t userNameSize; /**< @brief Size associated with #IotNetworkCredentials.pUserName. */
const unsigned char * pPassword; /**< @brief String representing the password for MQTT. */
size_t passwordSize; /**< @brief Size associated with #IotNetworkCredentials.pPassword. */
const uint8_t * pRootCa; /**< @brief String representing a trusted server root certificate. */
size_t rootCaSize; /**< @brief Size associated with #NetworkCredentials.pRootCa. */
const uint8_t * pClientCert; /**< @brief String representing the client certificate. */
size_t clientCertSize; /**< @brief Size associated with #NetworkCredentials.pClientCert. */
const uint8_t * pPrivateKey; /**< @brief String representing the client certificate's private key. */
size_t privateKeySize; /**< @brief Size associated with #NetworkCredentials.pPrivateKey. */
} NetworkCredentials_t;
/**
@@ -109,15 +109,14 @@ struct NetworkContext
typedef struct NetworkCredentials
{
/**
* @brief Set this to a non-NULL value to use ALPN.
*
* This string must be NULL-terminated.
* @brief To use ALPN, set this to a NULL-terminated list of supported
* protocols in decreasing order of preference.
*
* See [this link]
* (https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/)
* for more information.
*/
const char * pAlpnProtos;
const char ** pAlpnProtos;
/**
* @brief Disable server name indication (SNI) for a TLS session.
@@ -125,11 +124,11 @@ typedef struct NetworkCredentials
BaseType_t disableSni;
const unsigned char * pRootCa; /**< @brief String representing a trusted server root certificate. */
size_t rootCaSize; /**< @brief Size associated with #IotNetworkCredentials.pRootCa. */
size_t rootCaSize; /**< @brief Size associated with #NetworkCredentials.pRootCa. */
const unsigned char * pUserName; /**< @brief String representing the username for MQTT. */
size_t userNameSize; /**< @brief Size associated with #IotNetworkCredentials.pUserName. */
size_t userNameSize; /**< @brief Size associated with #NetworkCredentials.pUserName. */
const unsigned char * pPassword; /**< @brief String representing the password for MQTT. */
size_t passwordSize; /**< @brief Size associated with #IotNetworkCredentials.pPassword. */
size_t passwordSize; /**< @brief Size associated with #NetworkCredentials.pPassword. */
} NetworkCredentials_t;
/**
@@ -70,11 +70,11 @@ BaseType_t Sockets_Connect( Socket_t * pTcpSocket,
/* Connection parameters. */
serverAddress.sin_family = FREERTOS_AF_INET;
serverAddress.sin_port = FreeRTOS_htons( port );
serverAddress.sin_addr = FreeRTOS_gethostbyname( pHostName );
serverAddress.sin_addr = ( uint32_t ) FreeRTOS_gethostbyname( pHostName );
serverAddress.sin_len = ( uint8_t ) sizeof( serverAddress );
/* Check for errors from DNS lookup. */
if( serverAddress.sin_addr == 0 )
if( serverAddress.sin_addr == 0U )
{
LogError( ( "Failed to connect to server: DNS resolution failed: Hostname=%s.",
pHostName ) );
@@ -124,7 +124,7 @@ BaseType_t Sockets_Connect( Socket_t * pTcpSocket,
{
if( tcpSocket != FREERTOS_INVALID_SOCKET )
{
FreeRTOS_closesocket( tcpSocket );
( void ) FreeRTOS_closesocket( tcpSocket );
}
}
else
@@ -131,9 +131,9 @@ static TlsTransportStatus_t initMbedtls( void );
*
* @return Zero on success.
*/
static int generateRandomBytes( void * pvCtx,
unsigned char * pucRandom,
size_t xRandomLength );
static int32_t generateRandomBytes( void * pvCtx,
unsigned char * pucRandom,
size_t xRandomLength );
/**
* @brief Helper for reading the specified certificate object, if present,
@@ -175,16 +175,16 @@ static CK_RV initializeClientKeys( SSLContext_t * pxCtx );
*
* @return Zero on success.
*/
static int privateKeySigningCallback( void * pvContext,
mbedtls_md_type_t xMdAlg,
const unsigned char * pucHash,
size_t xHashLen,
unsigned char * pucSig,
size_t * pxSigLen,
int ( * piRng )( void *,
unsigned char *,
size_t ),
void * pvRng );
static int32_t privateKeySigningCallback( void * pvContext,
mbedtls_md_type_t xMdAlg,
const unsigned char * pucHash,
size_t xHashLen,
unsigned char * pucSig,
size_t * pxSigLen,
int32_t ( * piRng )( void *,
unsigned char *,
size_t ),
void * pvRng );
/*-----------------------------------------------------------*/
@@ -222,7 +222,7 @@ static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext,
const NetworkCredentials_t * pNetworkCredentials )
{
TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS;
int mbedtlsError = 0;
int32_t mbedtlsError = 0;
CK_RV xResult = CKR_OK;
configASSERT( pNetworkContext != NULL );
@@ -319,9 +319,9 @@ static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext,
}
else
{
mbedtls_ssl_conf_own_cert( &( pNetworkContext->sslContext.config ),
&( pNetworkContext->sslContext.clientCert ),
&( pNetworkContext->sslContext.privKey ) );
( void ) mbedtls_ssl_conf_own_cert( &( pNetworkContext->sslContext.config ),
&( pNetworkContext->sslContext.clientCert ),
&( pNetworkContext->sslContext.privKey ) );
}
}
}
@@ -331,7 +331,7 @@ static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext,
/* Include an application protocol list in the TLS ClientHello
* message. */
mbedtlsError = mbedtls_ssl_conf_alpn_protocols( &( pNetworkContext->sslContext.config ),
( const char ** ) &( pNetworkCredentials->pAlpnProtos ) );
pNetworkCredentials->pAlpnProtos );
if( mbedtlsError != 0 )
{
@@ -360,8 +360,14 @@ static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext,
else
{
/* Set the underlying IO for the TLS connection. */
/* MISRA Rule 11.2 flags the following line for casting the second
* parameter to void *. This rule is suppressed because
* #mbedtls_ssl_set_bio requires the second parameter as void *.
*/
/* coverity[misra_c_2012_rule_11_2_violation] */
mbedtls_ssl_set_bio( &( pNetworkContext->sslContext.context ),
pNetworkContext->tcpSocket,
( void * ) pNetworkContext->tcpSocket,
mbedtls_platform_send,
mbedtls_platform_recv,
NULL );
@@ -441,9 +447,9 @@ static TlsTransportStatus_t initMbedtls( void )
/*-----------------------------------------------------------*/
static int generateRandomBytes( void * pvCtx,
unsigned char * pucRandom,
size_t xRandomLength )
static int32_t generateRandomBytes( void * pvCtx,
unsigned char * pucRandom,
size_t xRandomLength )
{
/* Must cast from void pointer to conform to mbed TLS API. */
SSLContext_t * pxCtx = ( SSLContext_t * ) pvCtx;
@@ -645,19 +651,19 @@ static CK_RV initializeClientKeys( SSLContext_t * pxCtx )
/*-----------------------------------------------------------*/
static int privateKeySigningCallback( void * pvContext,
mbedtls_md_type_t xMdAlg,
const unsigned char * pucHash,
size_t xHashLen,
unsigned char * pucSig,
size_t * pxSigLen,
int ( * piRng )( void *,
unsigned char *,
size_t ),
void * pvRng )
static int32_t privateKeySigningCallback( void * pvContext,
mbedtls_md_type_t xMdAlg,
const unsigned char * pucHash,
size_t xHashLen,
unsigned char * pucSig,
size_t * pxSigLen,
int32_t ( * piRng )( void *,
unsigned char *,
size_t ),
void * pvRng )
{
CK_RV xResult = CKR_OK;
int lFinalResult = 0;
int32_t lFinalResult = 0;
SSLContext_t * pxTLSContext = ( SSLContext_t * ) pvContext;
CK_MECHANISM xMech = { 0 };
CK_BYTE xToBeSigned[ 256 ];
@@ -766,6 +772,10 @@ TlsTransportStatus_t TLS_FreeRTOS_Connect( NetworkContext_t * pNetworkContext,
LogError( ( "pRootCa cannot be NULL." ) );
returnStatus = TLS_TRANSPORT_INVALID_PARAMETER;
}
else
{
/* Empty else for MISRA 15.7 compliance. */
}
/* Establish a TCP connection with the server. */
if( returnStatus == TLS_TRANSPORT_SUCCESS )
@@ -800,9 +810,10 @@ TlsTransportStatus_t TLS_FreeRTOS_Connect( NetworkContext_t * pNetworkContext,
/* Clean up on failure. */
if( returnStatus != TLS_TRANSPORT_SUCCESS )
{
if( pNetworkContext->tcpSocket != FREERTOS_INVALID_SOCKET )
if( ( pNetworkContext != NULL ) &&
( pNetworkContext->tcpSocket != FREERTOS_INVALID_SOCKET ) )
{
FreeRTOS_closesocket( pNetworkContext->tcpSocket );
( void ) FreeRTOS_closesocket( pNetworkContext->tcpSocket );
}
}
else
@@ -128,7 +128,7 @@
*
* // If pRetryParams->maxRetryAttempts is set to 0, try forever.
* if( ( pRetryParams->attemptsDone < pRetryParams->maxRetryAttempts ) ||
* ( 0 == pRetryParams->maxRetryAttempts ) )
* ( 0U == pRetryParams->maxRetryAttempts ) )
* {
* // Choose a random value for back-off time between 0 and the max jitter value.
* backOffDelay = rand() % pRetryParams->nextJitterMax;
@@ -19,6 +19,11 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file transport_interface.h
* @brief Transport interface definitions to send and receive data over the
* network.
*/
#ifndef TRANSPORT_INTERFACE_H_
#define TRANSPORT_INTERFACE_H_
@@ -26,14 +31,131 @@
#include <stddef.h>
/**
* @brief The NetworkContext is an incomplete type. An implementation of this
* interface must define NetworkContext as per the requirements. This context
* is passed into the network interface functions.
* @transportpage
* @brief The transport interface definition.
*
* @transportsectionoverview
*
* The transport interface is a set of APIs that must be implemented using an
* external transport layer protocol. The transport interface is defined in
* @ref transport_interface.h. This interface allows protocols like MQTT and
* HTTP to send and receive data over the transport layer. This
* interface does not handle connection and disconnection to the server of
* interest. The connection, disconnection, and other transport settings, like
* timeout and TLS setup, must be handled in the user application.
* <br>
*
* The functions that must be implemented are:<br>
* - [Transport Receive](@ref TransportRecv_t)
* - [Transport Send](@ref TransportSend_t)
*
* Each of the functions above take in an opaque context @ref NetworkContext_t.
* The functions above and the context are also grouped together in the
* @ref TransportInterface_t structure:<br><br>
* @snippet this define_transportinterface
* <br>
*
* @transportsectionimplementation
*
* The following steps give guidance on implementing the transport interface:
*
* -# Implementing @ref NetworkContext_t<br><br>
* @snippet this define_networkcontext
* <br>
* @ref NetworkContext_t is the incomplete type <b>struct NetworkContext</b>.
* The implemented struct NetworkContext must contain all of the information
* that is needed to receive and send data with the @ref TransportRecv_t
* and the @ref TransportSend_t implementations.<br>
* In the case of TLS over TCP, struct NetworkContext is typically implemented
* with the TCP socket context and a TLS context.<br><br>
* <b>Example code:</b>
* @code{c}
* struct NetworkContext
* {
* struct MyTCPSocketContext tcpSocketContext;
* struct MyTLSContext tlsContext;
* };
* @endcode
* <br>
* -# Implementing @ref TransportRecv_t<br><br>
* @snippet this define_transportrecv
* <br>
* This function is expected to populate a buffer, with bytes received from the
* transport, and return the number of bytes placed in the buffer.
* In the case of TLS over TCP, @ref TransportRecv_t is typically implemented by
* calling the TLS layer function to receive data. In case of plaintext TCP
* without TLS, it is typically implemented by calling the TCP layer receive
* function. @ref TransportRecv_t may be invoked multiple times by the protocol
* library, if fewer bytes than were requested to receive are returned.
* <br><br>
* <b>Example code:</b>
* @code{c}
* int32_t myNetworkRecvImplementation( const NetworkContext_t * pNetworkContext,
* void * pBuffer,
* size_t bytesToRecv )
* {
* int32_t bytesReceived = 0;
* bytesReceived = TLSRecv( pNetworkContext->tlsContext,
* pBuffer,
* bytesToRecv,
* MY_SOCKET_TIMEOUT );
* if( bytesReceived < 0 )
* {
* // Handle socket error.
* }
* // Handle other cases.
*
* return bytesReceived;
* }
* @endcode
* <br>
* -# Implementing @ref TransportSend_t<br><br>
* @snippet this define_transportsend
* <br>
* This function is expected to send the bytes, in the given buffer over the
* transport, and return the number of bytes sent.
* In the case of TLS over TCP, @ref TransportSend_t is typically implemented by
* calling the TLS layer function to send data. In case of plaintext TCP
* without TLS, it is typically implemented by calling the TCP layer send
* function. @ref TransportSend_t may be invoked multiple times by the protocol
* library, if fewer bytes than were requested to send are returned.
* <br><br>
* <b>Example code:</b>
* @code{c}
* int32_t myNetworkSendImplementation( const NetworkContext_t * pNetworkContext,
* const void * pBuffer,
* size_t bytesToSend )
* {
* int32_t bytesSent = 0;
* bytesSent = TLSSend( pNetworkContext->tlsContext,
* pBuffer,
* bytesToSend,
* MY_SOCKET_TIMEOUT );
* if( bytesSent < 0 )
* {
* // Handle socket error.
* }
* // Handle other cases.
*
* return bytesSent;
* }
* @endcode
*/
struct NetworkContext;
typedef struct NetworkContext NetworkContext_t;
/**
* @transportstruct
* @typedef NetworkContext_t
* @brief The NetworkContext is an incomplete type. An implementation of this
* interface must define struct NetworkContext for the system requirements.
* This context is passed into the network interface functions.
*/
/* @[define_networkcontext] */
struct NetworkContext;
typedef struct NetworkContext NetworkContext_t;
/* @[define_networkcontext] */
/**
* @transportcallback
* @brief Transport interface for receiving data on the network.
*
* @param[in] pNetworkContext Implementation-defined network context.
@@ -42,11 +164,14 @@ typedef struct NetworkContext NetworkContext_t;
*
* @return The number of bytes received or a negative error code.
*/
typedef int32_t ( * TransportRecv_t )( NetworkContext_t * pNetworkContext,
/* @[define_transportrecv] */
typedef int32_t ( * TransportRecv_t )( const NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv );
/* @[define_transportrecv] */
/**
* @transportcallback
* @brief Transport interface for sending data over the network.
*
* @param[in] pNetworkContext Implementation-defined network context.
@@ -55,18 +180,23 @@ typedef int32_t ( * TransportRecv_t )( NetworkContext_t * pNetworkContext,
*
* @return The number of bytes sent or a negative error code.
*/
typedef int32_t ( * TransportSend_t )( NetworkContext_t * pNetworkContext,
/* @[define_transportsend] */
typedef int32_t ( * TransportSend_t )( const NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToSend );
/* @[define_transportsend] */
/**
* @transportstruct
* @brief The transport layer interface.
*/
/* @[define_transportinterface] */
typedef struct TransportInterface
{
TransportRecv_t recv; /**< Transport receive interface. */
TransportSend_t send; /**< Transport send interface. */
NetworkContext_t * pNetworkContext; /**< Implementation-defined network context. */
} TransportInterface_t;
/* @[define_transportinterface] */
#endif /* ifndef TRANSPORT_INTERFACE_H_ */