blob: a016b19fb921795e37df2eda602950b8912e6f51 [file] [log] [blame]
/*
* FreeRTOS TLS V1.1.7
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#if defined(SSS_USE_FTR_FILE)
#include "fsl_sss_ftr.h"
#endif
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "FreeRTOSIPConfig.h"
#include "iot_tls.h"
#include "iot_crypto.h"
#include "iot_pkcs11_config.h"
#include "iot_pkcs11.h"
#include "task.h"
#if SSS_HAVE_ALT_A71CH
# include "ax_mbedtls.h"
#endif
#if SSS_HAVE_ALT_SSS
# include "ex_sss.h"
# include "sss_mbedtls.h"
#endif
#include "aws_clientcredential_keys.h"
#include "iot_default_root_certificates.h"
#include "iot_pki_utils.h"
/* mbedTLS includes. */
#include "mbedtls/platform.h"
#include "mbedtls/net.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
#include "mbedtls/sha256.h"
#include "mbedtls/pk.h"
#include "mbedtls/pk_internal.h"
#include "mbedtls/debug.h"
#ifdef MBEDTLS_DEBUG_C
#define tlsDEBUG_VERBOSE 1
#endif
/* C runtime includes. */
#include <string.h>
#include <time.h>
#include <stdio.h>
#if SSS_HAVE_SSS
#include <ex_sss_boot.h>
extern ex_sss_boot_ctx_t* pex_sss_demo_boot_ctx;
extern ex_sss_cloud_ctx_t *pex_sss_demo_tls_ctx;
/* To overwrite the default curve list in ssl config */
extern int mbedtls_ssl_set_curve_list(mbedtls_ssl_config *conf, uint32_t keyIndex);
#endif
/**
* @brief Internal context structure.
*
* @param[in] pcDestination Server location, can be a DNS name or IP address.
* @param[in] pcServerCertificate Server X.509 certificate in PEM format to trust.
* @param[in] ulServerCertificateLength Length in bytes of the server certificate.
* @param[in] xNetworkRecv Callback for receiving data on an open TCP socket.
* @param[in] xNetworkSend Callback for sending data on an open TCP socket.
* @param[in] pvCallerContext Opaque pointer provided by caller for above callbacks.
* @param[out] xTLSCHandshakeSuccessful Indicates whether TLS handshake was successfully completed.
* @param[out] xMbedSslCtx Connection context for mbedTLS.
* @param[out] xMbedSslConfig Configuration context for mbedTLS.
* @param[out] xMbedX509CA Server certificate context for mbedTLS.
* @param[out] xMbedX509Cli Client certificate context for mbedTLS.
* @param[out] mbedPkAltCtx RSA crypto implementation context for mbedTLS.
* @param[out] pxP11FunctionList PKCS#11 function list structure.
* @param[out] xP11Session PKCS#11 session context.
* @param[out] xP11PrivateKey PKCS#11 private key context.
*/
typedef struct TLSContext
{
const char * pcDestination;
const char * pcServerCertificate;
uint32_t ulServerCertificateLength;
const char ** ppcAlpnProtocols;
uint32_t ulAlpnProtocolsCount;
NetworkRecv_t xNetworkRecv;
NetworkSend_t xNetworkSend;
void * pvCallerContext;
BaseType_t xTLSHandshakeSuccessful;
/* mbedTLS. */
mbedtls_ssl_context xMbedSslCtx;
mbedtls_ssl_config xMbedSslConfig;
mbedtls_x509_crt xMbedX509CA;
mbedtls_x509_crt xMbedX509Cli;
mbedtls_pk_context xMbedPkCtx;
mbedtls_pk_info_t xMbedPkInfo;
/* PKCS#11. */
CK_FUNCTION_LIST_PTR pxP11FunctionList;
CK_SESSION_HANDLE xP11Session;
CK_OBJECT_HANDLE xP11PrivateKey;
CK_KEY_TYPE xKeyType;
} TLSContext_t;
#define TLS_PRINT( X ) vLoggingPrintf X
/*-----------------------------------------------------------*/
/*
* Helper routines.
*/
/**
* @brief TLS internal context rundown helper routine.
*
* @param[in] pvContext Caller context.
*/
static void prvFreeContext( TLSContext_t * pxCtx )
{
if( NULL != pxCtx )
{
/* Cleanup mbedTLS. */
mbedtls_ssl_close_notify( &pxCtx->xMbedSslCtx ); /*lint !e534 The error is already taken care of inside mbedtls_ssl_close_notify*/
mbedtls_ssl_free( &pxCtx->xMbedSslCtx );
mbedtls_ssl_config_free( &pxCtx->xMbedSslConfig );
/* Cleanup PKCS#11. */
if( ( NULL != pxCtx->pxP11FunctionList ) &&
( NULL != pxCtx->pxP11FunctionList->C_CloseSession ) )
{
pxCtx->pxP11FunctionList->C_CloseSession( pxCtx->xP11Session ); /*lint !e534 This function always return CKR_OK. */
}
pxCtx->xTLSHandshakeSuccessful = pdFALSE;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Network send callback shim.
*
* @param[in] pvContext Caller context.
* @param[in] pucData Byte buffer to send.
* @param[in] xDataLength Length of byte buffer to send.
*
* @return Number of bytes sent, or a negative value on error.
*/
static int prvNetworkSend( void * pvContext,
const unsigned char * pucData,
size_t xDataLength )
{
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
return ( int ) pxCtx->xNetworkSend( pxCtx->pvCallerContext, pucData, xDataLength );
}
/*-----------------------------------------------------------*/
/**
* @brief Network receive callback shim.
*
* @param[in] pvContext Caller context.
* @param[out] pucReceiveBuffer Byte buffer to receive into.
* @param[in] xReceiveLength Length of byte buffer for receive.
*
* @return Number of bytes received, or a negative value on error.
*/
static int prvNetworkRecv( void * pvContext,
unsigned char * pucReceiveBuffer,
size_t xReceiveLength )
{
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
return ( int ) pxCtx->xNetworkRecv( pxCtx->pvCallerContext, pucReceiveBuffer, xReceiveLength );
}
/*-----------------------------------------------------------*/
/**
* @brief Callback that wraps PKCS#11 for pseudo-random number generation.
*
* @param[in] pvCtx Caller context.
* @param[in] pucRandom Byte array to fill with random data.
* @param[in] xRandomLength Length of byte array.
*
* @return Zero on success.
*/
static int prvGenerateRandomBytes( void * pvCtx,
unsigned char * pucRandom,
size_t xRandomLength )
{
TLSContext_t * pxCtx = ( TLSContext_t * ) pvCtx; /*lint !e9087 !e9079 Allow casting void* to other types. */
BaseType_t xResult;
xResult = pxCtx->pxP11FunctionList->C_GenerateRandom( pxCtx->xP11Session, pucRandom, xRandomLength );
if( xResult != CKR_OK )
{
TLS_PRINT( ( "ERROR: Failed to generate random bytes %d \r\n", xResult ) );
xResult = TLS_ERROR_RNG;
}
return xResult;
}
/*-----------------------------------------------------------*/
/**
* @brief Callback that enforces a worst-case expiration check on TLS server
* certificates.
*
* @param[in] pvCtx Caller context.
* @param[in] pxCertificate Certificate to check.
* @param[in] lPathCount Location of this certificate in the chain.
* @param[in] pulFlags Verification status flags.
*
* @return Zero on success.
*/
static int prvCheckCertificate( void * pvCtx,
mbedtls_x509_crt * pxCertificate,
int lPathCount,
uint32_t * pulFlags )
{
int lCompilationYear = 0;
#define tlsCOMPILER_DATE_STRING_MONTH_LENGTH 4
#define tlsDATE_STRING_FIELD_COUNT 3
char cCompilationMonth[ tlsCOMPILER_DATE_STRING_MONTH_LENGTH ];
int lCompilationMonth = 0;
int lCompilationDay = 0;
const char cMonths[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
/* Unreferenced parameters. */
( void ) ( pvCtx );
( void ) ( lPathCount );
/* Parse the date string fields. */
if( tlsDATE_STRING_FIELD_COUNT == sscanf( __DATE__,
"%3s %d %d",
cCompilationMonth,
&lCompilationDay,
&lCompilationYear ) )
{
cCompilationMonth[ tlsCOMPILER_DATE_STRING_MONTH_LENGTH - 1 ] = '\0';
/* Check for server expiration. First check the year. */
if( pxCertificate->valid_to.year < lCompilationYear )
{
*pulFlags |= MBEDTLS_X509_BADCERT_EXPIRED;
}
else if( pxCertificate->valid_to.year == lCompilationYear )
{
/* Convert the month. */
lCompilationMonth =
( ( strstr( cMonths, cCompilationMonth ) - cMonths ) /
( tlsCOMPILER_DATE_STRING_MONTH_LENGTH - 1 ) ) + 1;
/* Check the month. */
if( pxCertificate->valid_to.mon < lCompilationMonth )
{
*pulFlags |= MBEDTLS_X509_BADCERT_EXPIRED;
}
else if( pxCertificate->valid_to.mon == lCompilationMonth )
{
/* Check the day. */
if( pxCertificate->valid_to.day < lCompilationDay )
{
*pulFlags |= MBEDTLS_X509_BADCERT_EXPIRED;
}
}
}
}
else
{
*pulFlags |= MBEDTLS_X509_BADCERT_EXPIRED;
}
return 0;
}
/*-----------------------------------------------------------*/
/**
* @brief Sign a cryptographic hash with the private key.
*
* @param[in] pvContext Crypto context.
* @param[in] xMdAlg Unused.
* @param[in] pucHash Length in bytes of hash to be signed.
* @param[in] uiHashLen Byte array of hash to be signed.
* @param[out] pucSig RSA signature bytes.
* @param[in] pxSigLen Length in bytes of signature buffer.
* @param[in] piRng Unused.
* @param[in] pvRng Unused.
*
* @return Zero on success.
*/
static int prvPrivateKeySigningCallback( 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 ), /*lint !e955 This parameter is unused. */
void * pvRng )
{
CK_RV xResult = CKR_OK;
int lFinalResult = 0;
TLSContext_t * pxTLSContext = ( TLSContext_t * ) pvContext;
CK_MECHANISM xMech = { 0 };
CK_BYTE xToBeSigned[ 256 ];
CK_ULONG xToBeSignedLen = sizeof( xToBeSigned );
/* Unreferenced parameters. */
( void ) ( piRng );
( void ) ( pvRng );
( void ) ( xMdAlg );
/* Sanity check buffer length. */
if( xHashLen > sizeof( xToBeSigned ) )
{
xResult = CKR_ARGUMENTS_BAD;
}
/* Format the hash data to be signed. */
if( CKK_RSA == pxTLSContext->xKeyType )
{
xMech.mechanism = CKM_RSA_PKCS;
/* mbedTLS expects hashed data without padding, but PKCS #11 C_Sign function performs a hash
* & sign if hash algorithm is specified. This helper function applies padding
* indicating data was hashed with SHA-256 while still allowing pre-hashed data to
* be provided. */
xResult = vAppendSHA256AlgorithmIdentifierSequence( ( uint8_t * ) pucHash, xToBeSigned );
xToBeSignedLen = pkcs11RSA_SIGNATURE_INPUT_LENGTH;
}
else if( CKK_EC == pxTLSContext->xKeyType )
{
xMech.mechanism = CKM_ECDSA;
memcpy( xToBeSigned, pucHash, xHashLen );
xToBeSignedLen = xHashLen;
}
else
{
xResult = CKR_ARGUMENTS_BAD;
}
if( CKR_OK == xResult )
{
/* Use the PKCS#11 module to sign. */
xResult = pxTLSContext->pxP11FunctionList->C_SignInit( pxTLSContext->xP11Session,
&xMech,
pxTLSContext->xP11PrivateKey );
}
if( CKR_OK == xResult )
{
*pxSigLen = sizeof( xToBeSigned );
xResult = pxTLSContext->pxP11FunctionList->C_Sign( ( CK_SESSION_HANDLE ) pxTLSContext->xP11Session,
xToBeSigned,
xToBeSignedLen,
pucSig,
( CK_ULONG_PTR ) pxSigLen );
}
if( ( xResult == CKR_OK ) && ( CKK_EC == pxTLSContext->xKeyType ) )
{
/* PKCS #11 for P256 returns a 64-byte signature with 32 bytes for R and 32 bytes for S.
* This must be converted to an ASN.1 encoded array. */
if( *pxSigLen != pkcs11ECDSA_P256_SIGNATURE_LENGTH )
{
xResult = CKR_FUNCTION_FAILED;
}
if( xResult == CKR_OK )
{
PKI_pkcs11SignatureTombedTLSSignature( pucSig, pxSigLen );
}
}
if( xResult != CKR_OK )
{
TLS_PRINT( ( "ERROR: Failure in signing callback: %d \r\n", xResult ) );
lFinalResult = TLS_ERROR_SIGN;
}
return lFinalResult;
}
/*-----------------------------------------------------------*/
/**
* @brief Helper for reading the specified certificate object, if present,
* out of storage, into RAM, and then into an mbedTLS certificate context
* object.
*
* @param[in] pxTlsContext Caller TLS context.
* @param[in] pcLabelName PKCS #11 certificate object label.
* @param[in] xClass PKCS #11 certificate object class.
* @param[out] pxCertificateContext Certificate context.
*
* @return Zero on success.
*/
static int prvReadCertificateIntoContext( TLSContext_t * pxTlsContext,
const char * pcLabelName,
CK_OBJECT_CLASS xClass,
mbedtls_x509_crt * pxCertificateContext )
{
BaseType_t xResult = CKR_OK;
CK_ATTRIBUTE xTemplate = { 0 };
CK_OBJECT_HANDLE xCertObj = 0;
/* Get the handle of the certificate. */
xResult = xFindObjectWithLabelAndClass( pxTlsContext->xP11Session,
pcLabelName,
xClass,
&xCertObj );
if( ( CKR_OK == xResult ) && ( xCertObj == CK_INVALID_HANDLE ) )
{
xResult = CKR_OBJECT_HANDLE_INVALID;
}
/* Query the certificate size. */
if( 0 == xResult )
{
xTemplate.type = CKA_VALUE;
xTemplate.ulValueLen = 0;
xTemplate.pValue = NULL;
xResult = ( BaseType_t ) pxTlsContext->pxP11FunctionList->C_GetAttributeValue( pxTlsContext->xP11Session,
xCertObj,
&xTemplate,
1 );
}
/* Create a buffer for the certificate. */
if( 0 == xResult )
{
xTemplate.pValue = pvPortMalloc( xTemplate.ulValueLen ); /*lint !e9079 Allow casting void* to other types. */
if( NULL == xTemplate.pValue )
{
xResult = ( BaseType_t ) CKR_HOST_MEMORY;
}
}
/* Export the certificate. */
if( 0 == xResult )
{
xResult = ( BaseType_t ) pxTlsContext->pxP11FunctionList->C_GetAttributeValue( pxTlsContext->xP11Session,
xCertObj,
&xTemplate,
1 );
}
/* Decode the certificate. */
if( 0 == xResult )
{
xResult = mbedtls_x509_crt_parse( pxCertificateContext,
( const unsigned char * ) xTemplate.pValue,
xTemplate.ulValueLen );
}
/* Free memory. */
if( NULL != xTemplate.pValue )
{
vPortFree( xTemplate.pValue );
}
return xResult;
}
/*-----------------------------------------------------------*/
/**
* @brief Helper for setting up potentially hardware-based cryptographic context
* for the client TLS certificate and private key.
*
* @param Caller context.
*
* @return Zero on success.
*/
static int prvInitializeClientCredential( TLSContext_t * pxCtx )
{
BaseType_t xResult = CKR_OK;
CK_SLOT_ID * pxSlotIds = NULL;
CK_ULONG xCount = 0;
CK_ATTRIBUTE xTemplate[ 2 ];
mbedtls_pk_type_t xKeyAlgo = ( mbedtls_pk_type_t ) ~0;
char * pcJitrCertificate = keyJITR_DEVICE_CERTIFICATE_AUTHORITY_PEM;
/* Initialize the mbed contexts. */
mbedtls_x509_crt_init( &pxCtx->xMbedX509Cli );
/* Get the PKCS #11 module/token slot count. */
if( CKR_OK == xResult )
{
xResult = ( BaseType_t ) pxCtx->pxP11FunctionList->C_GetSlotList( CK_TRUE,
NULL,
&xCount );
}
/* Allocate memory to store the token slots. */
if( CKR_OK == xResult )
{
pxSlotIds = ( CK_SLOT_ID * ) pvPortMalloc( sizeof( CK_SLOT_ID ) * xCount );
if( NULL == pxSlotIds )
{
xResult = CKR_HOST_MEMORY;
}
}
/* Get all of the available private key slot identities. */
if( CKR_OK == xResult )
{
xResult = ( BaseType_t ) pxCtx->pxP11FunctionList->C_GetSlotList( CK_TRUE,
pxSlotIds,
&xCount );
}
/* Start a private session with the P#11 module using the first
* enumerated slot. */
if( CKR_OK == xResult )
{
xResult = ( BaseType_t ) pxCtx->pxP11FunctionList->C_OpenSession( pxSlotIds[ 0 ],
CKF_SERIAL_SESSION,
NULL,
NULL,
&pxCtx->xP11Session );
}
/* Put the module in authenticated mode. */
if( CKR_OK == xResult )
{
xResult = ( BaseType_t ) pxCtx->pxP11FunctionList->C_Login( pxCtx->xP11Session,
CKU_USER,
( CK_UTF8CHAR_PTR ) configPKCS11_DEFAULT_USER_PIN,
sizeof( configPKCS11_DEFAULT_USER_PIN ) - 1 );
}
#if SSS_HAVE_SSS
char keyLabel[20];
memset(keyLabel, 0, sizeof(keyLabel));
snprintf(keyLabel, sizeof(keyLabel), "sss:%08lx", pex_sss_demo_tls_ctx->client_keyPair_index);
const char * pcKeyLabelName = (const char * ) &keyLabel[0];
#else
const char * pcKeyLabelName = pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS;
#endif
if( CKR_OK == xResult )
{
/* Get the handle of the device private key. */
xResult = xFindObjectWithLabelAndClass( pxCtx->xP11Session,
pcKeyLabelName,
CKO_PRIVATE_KEY,
&pxCtx->xP11PrivateKey );
}
if( ( CKR_OK == xResult ) && ( pxCtx->xP11PrivateKey == CK_INVALID_HANDLE ) )
{
xResult = TLS_ERROR_NO_PRIVATE_KEY;
TLS_PRINT( ( "ERROR: Private key not found. " ) );
}
/* Query the device private key type. */
if( xResult == CKR_OK )
{
xTemplate[ 0 ].type = CKA_KEY_TYPE;
xTemplate[ 0 ].pValue = &pxCtx->xKeyType;
xTemplate[ 0 ].ulValueLen = sizeof( CK_KEY_TYPE );
xResult = pxCtx->pxP11FunctionList->C_GetAttributeValue( pxCtx->xP11Session,
pxCtx->xP11PrivateKey,
xTemplate,
1 );
}
/* Map the PKCS #11 key type to an mbedTLS algorithm. */
if( xResult == CKR_OK )
{
switch( pxCtx->xKeyType )
{
case CKK_RSA:
xKeyAlgo = MBEDTLS_PK_RSA;
break;
case CKK_EC:
xKeyAlgo = MBEDTLS_PK_ECKEY;
break;
default:
xResult = CKR_ATTRIBUTE_VALUE_INVALID;
break;
}
}
/* Map the mbedTLS algorithm to its internal metadata. */
if( xResult == CKR_OK )
{
memcpy( &pxCtx->xMbedPkInfo, mbedtls_pk_info_from_type( xKeyAlgo ), sizeof( mbedtls_pk_info_t ) );
pxCtx->xMbedPkInfo.sign_func = prvPrivateKeySigningCallback;
pxCtx->xMbedPkCtx.pk_info = &pxCtx->xMbedPkInfo;
pxCtx->xMbedPkCtx.pk_ctx = pxCtx;
}
#if SSS_HAVE_SSS
char certLabel[20];
memset(certLabel, 0, sizeof(certLabel));
snprintf(certLabel, sizeof(certLabel), "sss:%08lx", pex_sss_demo_tls_ctx->client_cert_index);
const char * pcCertLabelName = (const char * ) &certLabel[0];
#else
const char * pcCertLabelName = pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS;
#endif
/* Get the handle of the device client certificate. */
if( xResult == CKR_OK )
{
xResult = prvReadCertificateIntoContext( pxCtx,
pcCertLabelName,
CKO_CERTIFICATE,
&pxCtx->xMbedX509Cli );
}
/* Add a Just-in-Time Registration (JITR) device issuer certificate, if
* present, to the TLS context handle. */
if( xResult == CKR_OK )
{
/* Prioritize a statically defined certificate over one in storage. */
if( ( NULL != pcJitrCertificate ) &&
( 0 != strcmp( "", pcJitrCertificate ) ) )
{
xResult = mbedtls_x509_crt_parse( &pxCtx->xMbedX509Cli,
( const unsigned char * ) pcJitrCertificate,
1 + strlen( pcJitrCertificate ) );
}
else
{
/* Check for a device JITR certificate in storage. */
xResult = prvReadCertificateIntoContext( pxCtx,
pkcs11configLABEL_JITP_CERTIFICATE,
CKO_CERTIFICATE,
&pxCtx->xMbedX509Cli );
/* It is optional to have a JITR certificate in storage. */
if( CKR_OBJECT_HANDLE_INVALID == xResult )
{
xResult = CKR_OK;
}
}
}
/* Attach the client certificate(s) and private key to the TLS configuration. */
if( 0 == xResult )
{
xResult = mbedtls_ssl_conf_own_cert( &pxCtx->xMbedSslConfig,
&pxCtx->xMbedX509Cli,
&pxCtx->xMbedPkCtx );
}
/* Free memory. */
if( NULL != pxSlotIds )
{
vPortFree( pxSlotIds );
}
return xResult;
}
/*-----------------------------------------------------------*/
/*
* Interface routines.
*/
BaseType_t TLS_Init( void ** ppvContext,
TLSParams_t * pxParams )
{
BaseType_t xResult = CKR_OK;
TLSContext_t * pxCtx = NULL;
CK_C_GetFunctionList xCkGetFunctionList = NULL;
/* Allocate an internal context. */
pxCtx = ( TLSContext_t * ) pvPortMalloc( sizeof( TLSContext_t ) ); /*lint !e9087 !e9079 Allow casting void* to other types. */
if( NULL != pxCtx )
{
memset( pxCtx, 0, sizeof( TLSContext_t ) );
*ppvContext = pxCtx;
/* Initialize the context. */
pxCtx->pcDestination = pxParams->pcDestination;
pxCtx->pcServerCertificate = pxParams->pcServerCertificate;
pxCtx->ulServerCertificateLength = pxParams->ulServerCertificateLength;
pxCtx->ppcAlpnProtocols = pxParams->ppcAlpnProtocols;
pxCtx->ulAlpnProtocolsCount = pxParams->ulAlpnProtocolsCount;
pxCtx->xNetworkRecv = pxParams->pxNetworkRecv;
pxCtx->xNetworkSend = pxParams->pxNetworkSend;
pxCtx->pvCallerContext = pxParams->pvCallerContext;
/* Get the function pointer list for the PKCS#11 module. */
xCkGetFunctionList = C_GetFunctionList;
xResult = ( BaseType_t ) xCkGetFunctionList( &pxCtx->pxP11FunctionList );
/* Ensure that the PKCS #11 module is initialized. */
if( CKR_OK == xResult )
{
xResult = ( BaseType_t ) xInitializePKCS11();
/* It is ok if the module was previously initialized. */
if( xResult == CKR_CRYPTOKI_ALREADY_INITIALIZED )
{
xResult = CKR_OK;
}
}
}
else
{
xResult = ( BaseType_t ) CKR_HOST_MEMORY;
}
return xResult;
}
/*-----------------------------------------------------------*/
#ifdef MBEDTLS_DEBUG_C
static void prvTlsDebugPrint( void * ctx,
int lLevel,
const char * pcFile,
int lLine,
const char * pcStr )
{
/* Unused parameters. */
( void ) ctx;
( void ) pcFile;
( void ) lLine;
/* Send the debug string to the portable logger. */
vLoggingPrintf( "mbedTLS: |%d| %s", lLevel, pcStr );
}
#endif /* ifdef MBEDTLS_DEBUG_C */
/*-----------------------------------------------------------*/
BaseType_t TLS_Connect( void * pvContext )
{
BaseType_t xResult = 0;
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
/* Ensure that the FreeRTOS heap is used. */
CRYPTO_ConfigureHeap();
/* Initialize mbedTLS structures. */
mbedtls_ssl_init( &pxCtx->xMbedSslCtx );
mbedtls_ssl_config_init( &pxCtx->xMbedSslConfig );
mbedtls_x509_crt_init( &pxCtx->xMbedX509CA );
/* Decode the root certificate: either the default or the override. */
if( NULL != pxCtx->pcServerCertificate )
{
xResult = mbedtls_x509_crt_parse( &pxCtx->xMbedX509CA,
( const unsigned char * ) pxCtx->pcServerCertificate,
pxCtx->ulServerCertificateLength );
if( 0 != xResult )
{
TLS_PRINT( ( "ERROR: Failed to parse custom server certificates %d \r\n", xResult ) );
}
}
else
{
xResult = mbedtls_x509_crt_parse( &pxCtx->xMbedX509CA,
( const unsigned char * ) tlsVERISIGN_ROOT_CERTIFICATE_PEM,
tlsVERISIGN_ROOT_CERTIFICATE_LENGTH );
if( 0 == xResult )
{
xResult = mbedtls_x509_crt_parse( &pxCtx->xMbedX509CA,
( const unsigned char * ) tlsATS1_ROOT_CERTIFICATE_PEM,
tlsATS1_ROOT_CERTIFICATE_LENGTH );
if( 0 == xResult )
{
xResult = mbedtls_x509_crt_parse( &pxCtx->xMbedX509CA,
( const unsigned char * ) tlsSTARFIELD_ROOT_CERTIFICATE_PEM,
tlsSTARFIELD_ROOT_CERTIFICATE_LENGTH );
}
}
if( 0 != xResult )
{
/* Default root certificates should be in aws_default_root_certificate.h */
TLS_PRINT( ( "ERROR: Failed to parse default server certificates %d \r\n", xResult ) );
}
}
/* Start with protocol defaults. */
if( 0 == xResult )
{
xResult = mbedtls_ssl_config_defaults( &pxCtx->xMbedSslConfig,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT );
if( 0 != xResult )
{
TLS_PRINT( ( "ERROR: Failed to set ssl config defaults %d \r\n", xResult ) );
}
}
#if SSS_HAVE_SSS
if (0 == xResult)
{
sss_status_t sss_status = sss_key_object_init(&pex_sss_demo_tls_ctx->obj, &pex_sss_demo_boot_ctx->ks);
sss_status = sss_key_object_get_handle(&pex_sss_demo_tls_ctx->obj, pex_sss_demo_tls_ctx->client_keyPair_index);
if(sss_status != kStatus_SSS_Success) {
xResult = 1;
}
else if(pex_sss_demo_tls_ctx->obj.cipherType == kSSS_CipherType_EC_NIST_P) {
xResult = mbedtls_ssl_set_curve_list(&pxCtx->xMbedSslConfig, pex_sss_demo_tls_ctx->client_keyPair_index);
}
}
#endif
if( 0 == xResult )
{
/* Use a callback for additional server certificate validation. */
mbedtls_ssl_conf_verify( &pxCtx->xMbedSslConfig,
&prvCheckCertificate,
pxCtx );
/* Server certificate validation is mandatory. */
mbedtls_ssl_conf_authmode( &pxCtx->xMbedSslConfig, MBEDTLS_SSL_VERIFY_REQUIRED );
/* Set the RNG callback. */
mbedtls_ssl_conf_rng( &pxCtx->xMbedSslConfig, &prvGenerateRandomBytes, pxCtx ); /*lint !e546 Nothing wrong here. */
/* Set issuer certificate. */
mbedtls_ssl_conf_ca_chain( &pxCtx->xMbedSslConfig, &pxCtx->xMbedX509CA, NULL );
/* Configure the SSL context for the device credentials. */
xResult = prvInitializeClientCredential( pxCtx );
}
if( ( 0 == xResult ) && ( NULL != pxCtx->ppcAlpnProtocols ) )
{
/* Include an application protocol list in the TLS ClientHello
* message. */
xResult = mbedtls_ssl_conf_alpn_protocols(
&pxCtx->xMbedSslConfig,
pxCtx->ppcAlpnProtocols );
}
#ifdef MBEDTLS_DEBUG_C
/* If mbedTLS is being compiled with debug support, assume that the
* runtime configuration should use verbose output. */
mbedtls_ssl_conf_dbg( &pxCtx->xMbedSslConfig, prvTlsDebugPrint, NULL );
mbedtls_debug_set_threshold( tlsDEBUG_VERBOSE );
#endif
if( 0 == xResult )
{
/* Set the resulting protocol configuration. */
xResult = mbedtls_ssl_setup( &pxCtx->xMbedSslCtx, &pxCtx->xMbedSslConfig );
}
#if SSS_HAVE_ALT_SSS
if( 0 == xResult )
{
pex_sss_demo_tls_ctx->pHost_ks = &pex_sss_demo_boot_ctx->host_ks;
if (pex_sss_demo_tls_ctx->obj.cipherType == kSSS_CipherType_EC_NIST_P) {
xResult = sss_mbedtls_associate_ecdhctx(pxCtx->xMbedSslCtx.handshake, &pex_sss_demo_tls_ctx->obj, pex_sss_demo_tls_ctx->pHost_ks);
}
}
#endif /*SSS_HAVE_ALT_SSS*/
/* Set the hostname, if requested. */
if( ( 0 == xResult ) && ( NULL != pxCtx->pcDestination ) )
{
xResult = mbedtls_ssl_set_hostname( &pxCtx->xMbedSslCtx, pxCtx->pcDestination );
}
/* Set the socket callbacks. */
if( 0 == xResult )
{
mbedtls_ssl_set_bio( &pxCtx->xMbedSslCtx,
pxCtx,
prvNetworkSend,
prvNetworkRecv,
NULL );
/* Negotiate. */
while( 0 != ( xResult = mbedtls_ssl_handshake( &pxCtx->xMbedSslCtx ) ) )
{
if( ( MBEDTLS_ERR_SSL_WANT_READ != xResult ) &&
( MBEDTLS_ERR_SSL_WANT_WRITE != xResult ) )
{
/* There was an unexpected error. Per mbedTLS API documentation,
* ensure that upstream clean-up code doesn't accidentally use
* a context that failed the handshake. */
prvFreeContext( pxCtx );
TLS_PRINT( ( "ERROR: Handshake failed with error code %d \r\n", xResult ) );
break;
}
}
}
/* Keep track of successful completion of the handshake. */
if( 0 == xResult )
{
pxCtx->xTLSHandshakeSuccessful = pdTRUE;
}
else if( xResult > 0 )
{
TLS_PRINT( ( "ERROR: TLS_Connect failed with error code %d \r\n", xResult ) );
/* Convert PKCS #11 failures to a negative error code. */
xResult = TLS_ERROR_HANDSHAKE_FAILED;
}
/* Free up allocated memory. */
mbedtls_x509_crt_free( &pxCtx->xMbedX509CA );
mbedtls_x509_crt_free( &pxCtx->xMbedX509Cli );
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t TLS_Recv( void * pvContext,
unsigned char * pucReadBuffer,
size_t xReadLength )
{
BaseType_t xResult = 0;
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
size_t xRead = 0;
if( ( NULL != pxCtx ) && ( pdTRUE == pxCtx->xTLSHandshakeSuccessful ) )
{
/* This routine will return however many bytes are returned from from mbedtls_ssl_read
* immediately unless MBEDTLS_ERR_SSL_WANT_READ is returned, in which case we try again. */
do
{
xResult = mbedtls_ssl_read( &pxCtx->xMbedSslCtx,
pucReadBuffer + xRead,
xReadLength - xRead );
if( xResult > 0 )
{
/* Got data, so update the tally and keep looping. */
xRead += ( size_t ) xResult;
}
/* If xResult == 0, then no data was received (and there is no error).
* The secure sockets API supports non-blocking read, so stop the loop,
* but don't flag an error. */
} while( ( xResult == MBEDTLS_ERR_SSL_WANT_READ ) );
}
else
{
xResult = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
if( xResult >= 0 )
{
xResult = ( BaseType_t ) xRead;
}
else
{
/* xResult < 0 is a hard error, so invalidate the context and stop. */
prvFreeContext( pxCtx );
}
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t TLS_Send( void * pvContext,
const unsigned char * pucMsg,
size_t xMsgLength )
{
BaseType_t xResult = 0;
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
size_t xWritten = 0;
if( ( NULL != pxCtx ) && ( pdTRUE == pxCtx->xTLSHandshakeSuccessful ) )
{
while( xWritten < xMsgLength )
{
xResult = mbedtls_ssl_write( &pxCtx->xMbedSslCtx,
pucMsg + xWritten,
xMsgLength - xWritten );
if( 0 < xResult )
{
/* Sent data, so update the tally and keep looping. */
xWritten += ( size_t ) xResult;
}
else if( ( 0 == xResult ) || ( -pdFREERTOS_ERRNO_ENOSPC == xResult ) )
{
/* No data sent. The secure sockets
* API supports non-blocking send, so stop the loop but don't
* flag an error. */
xResult = 0;
break;
}
else if( MBEDTLS_ERR_SSL_WANT_WRITE != xResult )
{
/* Hard error: invalidate the context and stop. */
prvFreeContext( pxCtx );
break;
}
}
}
else
{
xResult = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
if( 0 <= xResult )
{
xResult = ( BaseType_t ) xWritten;
}
return xResult;
}
/*-----------------------------------------------------------*/
void TLS_Cleanup( void * pvContext )
{
TLSContext_t * pxCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */
if( NULL != pxCtx )
{
if( pdTRUE == pxCtx->xTLSHandshakeSuccessful )
{
prvFreeContext( pxCtx );
}
/* Free memory. */
vPortFree( pxCtx );
}
}