/* * 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 */ /* FreeRTOS includes. */ #include "freertos_tls.h" #include "task.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 4 #endif /* C runtime includes. */ #include #include #include #if SSS_HAVE_SSS #include 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 SSS_HAVE_SSS */ 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( 0 == xResult ) { #if SSS_HAVE_ALT_SSS 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 ); } }