diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91f3f42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +FreeRTOS-AWS/demos/pc/windows/visual_studio/.vs +*.sdf +*.opensdf +*.user diff --git a/.gitmodules b/.gitmodules index 8d5364a..a12ca92 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,7 @@ url=https://github.com/wolfSSL/wolfssl.git [submodule "FreeRTOS-Classic/FreeRTOS-Plus/Source/WolfMQTT"] path = FreeRTOS-Classic/FreeRTOS-Plus/Source/WolfMQTT url=https://github.com/wolfSSL/wolfMQTT.git +[submodule "FreeRTOS-AWS/lib/third_party/wolfssl"] + path = FreeRTOS-AWS/lib/third_party/wolfssl + url = git@github.com:dgarske/wolfssl.git + branch = mbedtls_compat diff --git a/FreeRTOS-AWS/demos/pc/windows/common/application_code/aws_entropy_hardware_poll.c b/FreeRTOS-AWS/demos/pc/windows/common/application_code/aws_entropy_hardware_poll.c index 8176fb4..9156508 100755 --- a/FreeRTOS-AWS/demos/pc/windows/common/application_code/aws_entropy_hardware_poll.c +++ b/FreeRTOS-AWS/demos/pc/windows/common/application_code/aws_entropy_hardware_poll.c @@ -26,6 +26,9 @@ #include #include + +#ifndef WOLF_AWSTLS + #include "mbedtls/entropy.h" /*-----------------------------------------------------------*/ @@ -59,3 +62,5 @@ int mbedtls_hardware_poll( void * data, return lStatus; } + +#endif /* WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/demos/pc/windows/common/config_files/user_settings.h b/FreeRTOS-AWS/demos/pc/windows/common/config_files/user_settings.h new file mode 100644 index 0000000..646635a --- /dev/null +++ b/FreeRTOS-AWS/demos/pc/windows/common/config_files/user_settings.h @@ -0,0 +1,66 @@ +/* WolfSSL settings file for AWS FreeRTOS PC Demo */ + +#ifndef _USER_SETTING_H_ +#define _USER_SETTING_H_ + +/* Use the FreeRTOS Heap and TCP API's */ +#define FREERTOS_TCP + +/* For Windows Simulator only */ +#define FREERTOS_TCP_WINSIM + +/* platform specific */ +#define SIZEOF_LONG_LONG 8 +#define WOLFSSL_HAVE_MIN +#define WOLFSSL_HAVE_MAX + +/* side-channel resistance */ +#define TFM_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT +#define WC_RSA_BLINDING + +/* ignore the #warning for optional include files (misc.c, bio.c, etc...) */ +#define WOLFSSL_IGNORE_FILE_WARN + +/* math */ +#define USE_FAST_MATH +#define ALT_ECC_SIZE +#define TFM_ECC256 + +/* enable algorithms */ +#define HAVE_ECC +#define ECC_SHAMIR +#define HAVE_AESGCM +#define HAVE_CHACHA +#define HAVE_POLY1305 +#define WOLFSSL_SHA384 +#define WOLFSSL_SHA512 + +#define WOLFSSL_BASE64_ENCODE + +/* these are required for TLS 1.3 */ +#define HAVE_HKDF +#define WC_RSA_PSS +#define HAVE_FFDHE_2048 + +/* extra compatibility functions for X509 */ +#define OPENSSL_EXTRA +#define OPENSSL_EXTRA_X509_SMALL +#define WOLFSSL_PEM_TO_DER + +/* enable TLS features */ +#define WOLFSSL_TLS13 +#define HAVE_TLS_EXTENSIONS +#define HAVE_SUPPORTED_CURVES +#define HAVE_ONE_TIME_AUTH + +/* disable algorithms off by default */ +#define NO_DSA +#define NO_RC4 +#define NO_HC128 +#define NO_RABBIT +#define NO_PSK +#define NO_MD4 +#define NO_DES3 + +#endif /* _USER_SETTING_H_ */ diff --git a/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.sln b/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.sln new file mode 100644 index 0000000..8484cf5 --- /dev/null +++ b/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.sln @@ -0,0 +1,24 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{704FE73F-93FB-47A6-8FAA-3280D09F1A72}") = "aws_demos_wolf", "aws_demos_wolf.vcxproj", "{DF666F11-4766-4652-B88D-C6769A70E073}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DF666F11-4766-4652-B88D-C6769A70E073}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF666F11-4766-4652-B88D-C6769A70E073}.Debug|Win32.Build.0 = Debug|Win32 + {DF666F11-4766-4652-B88D-C6769A70E073}.Debug|x64.ActiveCfg = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = aws_demos_wolf.vsmdi + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.vcxproj b/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.vcxproj new file mode 100644 index 0000000..5890471 --- /dev/null +++ b/FreeRTOS-AWS/demos/pc/windows/visual_studio/aws_demos_wolf.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug + Win32 + + + + {DF666F11-4766-4652-B88D-C6769A70E073} + aws_demos_wolf + 8.1 + + + + Application + false + MultiByte + v140 + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\common\win_pcap;..\common\config_files;..\common\application_code\include;..\..\..\..\demos\common\include;..\..\..\..\lib\include;..\..\..\..\lib\include\private;..\..\..\..\lib\FreeRTOS\include;..\..\..\..\lib\FreeRTOS\portable\MSVC-MingW;..\..\..\..\lib\FreeRTOS-Plus-TCP\include;..\..\..\..\lib\FreeRTOS-Plus-TCP\Source\portable\BufferManagement;..\..\..\..\lib\FreeRTOS-Plus-TCP\Source\portable\Compiler\MSVC;..\..\..\..\lib\ota\portable\pc\windows;..\..\..\..\lib\third_party\wolfssl;..\..\..\..\lib\third_party\tracealyzer_recorder\Include;..\..\..\..\lib\third_party\jsmn;..\..\..\..\lib\third_party\pkcs11;..\..\..\..\lib\third_party\tinycbor;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;__PRETTY_FUNCTION__=__FUNCTION__;WOLFSSL_USER_SETTINGS;WOLF_AWSTLS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + 4206;%(DisableSpecificWarnings) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/aws_demos_wolf.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;%(AdditionalDependencies) + ..\common\win_pcap + false + false + + + true + .\Debug/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-AWS/lib/crypto/aws_crypto.c b/FreeRTOS-AWS/lib/crypto/aws_crypto.c index 27e1d51..de62557 100755 --- a/FreeRTOS-AWS/lib/crypto/aws_crypto.c +++ b/FreeRTOS-AWS/lib/crypto/aws_crypto.c @@ -29,6 +29,8 @@ #include "FreeRTOSIPConfig.h" #include "aws_crypto.h" +#ifndef WOLF_AWSTLS + /* mbedTLS includes. */ #include "mbedtls/config.h" #include "mbedtls/platform.h" @@ -270,3 +272,5 @@ BaseType_t CRYPTO_SignatureVerificationFinal( void * pvContext, return xResult; } + +#endif /* !WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/lib/crypto/wolf_crypto.c b/FreeRTOS-AWS/lib/crypto/wolf_crypto.c new file mode 100755 index 0000000..e928e0c --- /dev/null +++ b/FreeRTOS-AWS/lib/crypto/wolf_crypto.c @@ -0,0 +1,321 @@ +/* + * Amazon FreeRTOS Crypto V1.0.1 + * Copyright (C) 2017 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.h" +#include "FreeRTOSIPConfig.h" +#include "aws_crypto.h" + +#ifdef WOLF_AWSTLS + +/* wolfSSL compatibility layer (github.com/wolfSSL/wolfssl) */ +#include + + +/* C runtime includes. */ +#include + +/** + * @brief Internal signature verification context structure + */ +typedef struct SignatureVerificationState +{ + BaseType_t xAsymmetricAlgorithm; + BaseType_t xHashAlgorithm; + wc_Sha xSHA1Context; + wc_Sha256 xSHA256Context; +} SignatureVerificationState_t, * SignatureVerificationStatePtr_t; + +/* + * Helper routines + */ + +/** + * @brief Implements libc calloc semantics using the FreeRTOS heap + */ +static void * prvCalloc( size_t xNmemb, + size_t xSize ) +{ + void * pvNew = pvPortMalloc( xNmemb * xSize ); + + if( NULL != pvNew ) + { + memset( pvNew, 0, xNmemb * xSize ); + } + + return pvNew; +} + +/** + * @brief Verifies a cryptographic signature based on the signer + * certificate, hash algorithm, and the data that was signed. + */ +static BaseType_t prvVerifySignature( char * pcSignerCertificate, + size_t xSignerCertificateLength, + BaseType_t xHashAlgorithm, + uint8_t * pucHash, + size_t xHashLength, + BaseType_t xAsymmetricAlgorithm, + uint8_t * pucSignature, + size_t xSignatureLength ) +{ + BaseType_t xResult = pdTRUE; + int buf_format = WOLFSSL_FILETYPE_ASN1; + uint8_t* pucSignerCertDer = (uint8_t*)pcSignerCertificate; + size_t xSignerCertDerLength = xSignerCertificateLength; + WOLFSSL_X509* xCertCtx = NULL; + WOLFSSL_EVP_PKEY* xPublicKey = NULL; + int hashAlg = NID_sha256; + + /* + * Map the hash algorithm + */ + if (xHashAlgorithm == cryptoHASH_ALGORITHM_SHA1) { + hashAlg = NID_sha1; + } + +#ifdef WOLFSSL_PEM_TO_DER + /* Determine certificate format */ + if( xSignerCertificateLength != 0 && + pcSignerCertificate[xSignerCertificateLength - 1] == '\0' && + strstr( (const char *) pcSignerCertificate, "-----BEGIN CERTIFICATE-----" ) != NULL ) + { + buf_format = WOLFSSL_FILETYPE_PEM; + + pucSignerCertDer = (uint8_t*)pvPortMalloc(xSignerCertificateLength); + if (pucSignerCertDer) { + xResult = wolfSSL_CertPemToDer( + (const unsigned char*)pcSignerCertificate, + xSignerCertificateLength, pucSignerCertDer, + xSignerCertificateLength, CERT_TYPE); + if (xResult > 0) { + xSignerCertDerLength = xResult; + xResult = pdTRUE; + } + else { + xResult = pdFALSE; + } + } + else { + xResult = pdFALSE; + } + } +#endif + + /* + * Decode and create a certificate context + */ + if (xResult == pdTRUE) { + xCertCtx = wolfSSL_X509_load_certificate_buffer( + (const unsigned char*)pucSignerCertDer, xSignerCertDerLength, + WOLFSSL_FILETYPE_ASN1); + if (xCertCtx == NULL) { + xResult = pdFALSE; + } + } + + if (xResult == pdTRUE) { + xPublicKey = wolfSSL_X509_get_pubkey(xCertCtx); + if (xPublicKey == NULL) { + xResult = pdFALSE; + } + } + + /* + * Verify the signature using the public key from the decoded certificate + */ + if (xResult == pdTRUE) { + if (xAsymmetricAlgorithm == cryptoASYMMETRIC_ALGORITHM_RSA) { + /* default to failure */ + xResult = pdFALSE; + + /* Perform verification of signature using provided RSA key */ + xResult = wolfSSL_RSA_verify(hashAlg, pucHash, xHashLength, + pucSignature, xSignatureLength, xPublicKey->rsa); + if (xResult == WOLFSSL_SUCCESS) { + xResult = pdTRUE; + } + } + else { + /* not supported */ + xResult = pdFALSE; + } + } + + /* + * Clean-up + */ + if (xCertCtx) { + wolfSSL_X509_free(xCertCtx); + } + if (xPublicKey) { + wolfSSL_EVP_PKEY_free(xPublicKey); + } + +#ifdef WOLFSSL_PEM_TO_DER + if (buf_format == WOLFSSL_FILETYPE_PEM) { + vPortFree(pucSignerCertDer); + } +#endif + + return xResult; +} + +/* + * Interface routines + */ + +/** + * @brief Overrides CRT heap callouts to use FreeRTOS instead + */ +void CRYPTO_ConfigureHeap( void ) +{ + /* mapped in user_settings.h with FREERTOS define. */ + +} + +/** + * @brief Creates signature verification context. + */ +BaseType_t CRYPTO_SignatureVerificationStart( void ** ppvContext, + BaseType_t xAsymmetricAlgorithm, + BaseType_t xHashAlgorithm ) +{ + BaseType_t xResult = pdTRUE; + SignatureVerificationStatePtr_t pxCtx = NULL; + + /* + * Allocate the context + */ + if( NULL == ( pxCtx = ( SignatureVerificationStatePtr_t ) pvPortMalloc( + sizeof( *pxCtx ) ) ) ) /*lint !e9087 Allow casting void* to other types. */ + { + xResult = pdFALSE; + } + + if( pdTRUE == xResult ) + { + *ppvContext = pxCtx; + + /* + * Store the algorithm identifiers + */ + pxCtx->xAsymmetricAlgorithm = xAsymmetricAlgorithm; + pxCtx->xHashAlgorithm = xHashAlgorithm; + + /* + * Initialize the requested hash type + */ + if( cryptoHASH_ALGORITHM_SHA1 == pxCtx->xHashAlgorithm ) + { + wc_InitSha(&pxCtx->xSHA1Context); + } + else + { + wc_InitSha256(&pxCtx->xSHA256Context); + } + } + + return xResult; +} + +/** + * @brief Adds bytes to an in-progress hash for subsequent signature + * verification. + */ +void CRYPTO_SignatureVerificationUpdate( void * pvContext, + uint8_t * pucData, + size_t xDataLength ) +{ + SignatureVerificationStatePtr_t pxCtx = ( SignatureVerificationStatePtr_t ) pvContext; /*lint !e9087 Allow casting void* to other types. */ + + /* + * Add the data to the hash of the requested type + */ + if( cryptoHASH_ALGORITHM_SHA1 == pxCtx->xHashAlgorithm ) + { + wc_ShaUpdate(&pxCtx->xSHA1Context, pucData, xDataLength); + } + else + { + wc_Sha256Update(&pxCtx->xSHA256Context, pucData, xDataLength); + } +} + +/** + * @brief Performs signature verification on a cryptographic hash. + */ +BaseType_t CRYPTO_SignatureVerificationFinal( void * pvContext, + char * pcSignerCertificate, + size_t xSignerCertificateLength, + uint8_t * pucSignature, + size_t xSignatureLength ) +{ + BaseType_t xResult = pdTRUE; + SignatureVerificationStatePtr_t pxCtx = + ( SignatureVerificationStatePtr_t ) pvContext; /*lint !e9087 Allow casting void* to other types. */ + uint8_t ucSHA1[ cryptoSHA1_DIGEST_BYTES ]; + uint8_t ucSHA256[ cryptoSHA256_DIGEST_BYTES ]; + uint8_t * pucHash = NULL; + size_t xHashLength = 0; + + /* + * Finish the hash + */ + if( cryptoHASH_ALGORITHM_SHA1 == pxCtx->xHashAlgorithm ) + { + wc_ShaFinal(&pxCtx->xSHA1Context, ucSHA1); + pucHash = ucSHA1; + xHashLength = cryptoSHA1_DIGEST_BYTES; + } + else + { + wc_Sha256Final(&pxCtx->xSHA256Context, ucSHA256); + pucHash = ucSHA256; + xHashLength = cryptoSHA256_DIGEST_BYTES; + } + + /* + * Verify the signature + */ + xResult = prvVerifySignature( pcSignerCertificate, + xSignerCertificateLength, + pxCtx->xHashAlgorithm, + pucHash, + xHashLength, + pxCtx->xAsymmetricAlgorithm, + pucSignature, + xSignatureLength ); + + /* + * Clean-up + */ + vPortFree( pxCtx ); + + return xResult; +} + +#endif /* WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/lib/ota/aws_ota_agent.c b/FreeRTOS-AWS/lib/ota/aws_ota_agent.c index c51051c..3b28452 100755 --- a/FreeRTOS-AWS/lib/ota/aws_ota_agent.c +++ b/FreeRTOS-AWS/lib/ota/aws_ota_agent.c @@ -52,8 +52,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* JSON job document parser includes. */ #include "jsmn.h" -#include "mbedtls/base64.h" +#ifdef WOLF_AWSTLS +/* wolfSSL compatibility layer (github.com/wolfSSL/wolfssl) */ +#include +#else +#include "mbedtls/base64.h" +#endif /* Macro to get the number of elements in a static type. */ #define NUM_ELEM(x) (sizeof(x)/sizeof(*x)) @@ -686,7 +691,7 @@ static void prvUpdateJobStatus (OTA_FileContext_t *C, char *pcOTA_DynamicTopic, /* If the topic name was built, try to publish the status message to it. Use QOS 1 to assure update. */ if (ulRequestTopicLen > 0) - { + { eResult = prvPublishMessage ( pvPubSubClient, pcOTA_DynamicTopic, @@ -1375,7 +1380,7 @@ OTA_FileContext_t *prvParseJobDocFromJSON(const char *pacRawMsg, u32 iMsgLen) { xErr = eOTA_JobParseErr_MalformedJobDoc; } else - { + { if (C->iFileSize == 0) { OTA_PRINT ("[OTA] Zero file size is not allowed!\r\n"); diff --git a/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/pkcs11.c b/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/pkcs11.c index 2545f15..dba1dca 100755 --- a/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/pkcs11.c +++ b/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/pkcs11.c @@ -38,6 +38,8 @@ #include "aws_crypto.h" #include "aws_pkcs11.h" +#ifndef WOLF_AWSTLS + /* mbedTLS includes. */ #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" @@ -1229,3 +1231,5 @@ CK_DEFINE_FUNCTION( CK_RV, C_GenerateRandom )( CK_SESSION_HANDLE xSession, return CKR_OK; } + +#endif /* !#ifndef WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/wolf_pkcs11.c b/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/wolf_pkcs11.c new file mode 100755 index 0000000..82f4b90 --- /dev/null +++ b/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/wolf_pkcs11.c @@ -0,0 +1,1201 @@ +/* + * Amazon FreeRTOS PKCS#11 for Windows Simulator V1.0.1 + * Copyright (C) 2017 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 + */ + + +/** + * @file wolf_pkcs11.c + * @brief Windows simulator PKCS#11 implementation for software keys. This + * file deviates from the FreeRTOS style standard for some function names and + * data types in order to maintain compliance with the PKCS#11 standard. + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "FreeRTOSIPConfig.h" +#include "task.h" +#include "aws_crypto.h" +#include "aws_pkcs11.h" + +#ifdef WOLF_AWSTLS + +/* wolfSSL compatibility layer (github.com/wolfSSL/wolfssl) */ +#include + +#include "aws_clientcredential.h" + +/* C runtime includes. */ +#include +#include + +/** + * @brief File storage location definitions. + */ +#define pkcs11FILE_NAME_CLIENT_CERTIFICATE "FreeRTOS_P11_Certificate.dat" +#define pkcs11FILE_NAME_KEY "FreeRTOS_P11_Key.dat" + +/** + * @brief Cryptoki module attribute definitions. + */ +#define pkcs11SLOT_ID 1 +#define pkcs11OBJECT_HANDLE_PUBLIC_KEY 1 +#define pkcs11OBJECT_HANDLE_PRIVATE_KEY 2 +#define pkcs11OBJECT_HANDLE_CERTIFICATE 3 + +#define pkcs11SUPPORTED_KEY_BITS 2048 + + +/** + * @brief Key structure. + */ +typedef struct P11Key +{ + mbedtls_pk_context xWolfPkCtx; + mbedtls_x509_crt xWolfX509Cli; +} P11Key_t, *P11KeyPtr_t; + +/** + * @brief Session structure. + */ +typedef struct P11Session +{ + P11KeyPtr_t pxCurrentKey; + CK_ULONG ulState; + CK_BBOOL xOpened; + CK_BBOOL xFindObjectInit; + CK_BBOOL xFindObjectComplete; + CK_OBJECT_CLASS xFindObjectClass; + mbedtls_ctr_drbg_context xWolfDrbgCtx; +} P11Session_t, * P11SessionPtr_t; + +/** + * @brief Helper definitions. + */ +#define pkcs11CREATE_OBJECT_MIN_ATTRIBUTE_COUNT 3 +#define pkcs11CERTIFICATE_ATTRIBUTE_COUNT 3 +#define pkcs11PRIVATE_KEY_ATTRIBUTE_COUNT 4 + +/*-----------------------------------------------------------*/ + +/** + * @brief Maps an opaque caller session handle into its internal state structure. + */ +static P11SessionPtr_t prvSessionPointerFromHandle( CK_SESSION_HANDLE xSession ) +{ + return ( P11SessionPtr_t ) xSession; /*lint !e923 Allow casting integer type to pointer for handle. */ +} + +/*-----------------------------------------------------------*/ + +/** + * @brief Writes a file to local storage. + */ +static BaseType_t prvSaveFile( char * pcFileName, + uint8_t * pucData, + uint32_t ulDataSize ) +{ + uint32_t ulStatus = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD lpNumberOfBytesWritten; + + /* Open the file. */ + hFile = CreateFileA( pcFileName, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if( INVALID_HANDLE_VALUE == hFile ) + { + ulStatus = GetLastError(); + } + + /* Write the data. */ + if( ERROR_SUCCESS == ulStatus ) + { + if( FALSE == WriteFile( hFile, pucData, ulDataSize, &lpNumberOfBytesWritten, NULL ) ) + { + ulStatus = GetLastError(); + } + } + + /* Clean up. */ + if( INVALID_HANDLE_VALUE != hFile ) + { + CloseHandle( hFile ); + } + + return 0 == ulStatus; +} + +/*-----------------------------------------------------------*/ + +/** + * @brief Reads a file from local storage. + */ +static BaseType_t prvReadFile( char * pcFileName, + uint8_t ** ppucData, + uint32_t * pulDataSize ) +{ + uint32_t ulStatus = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + uint32_t ulSize = 0; + + /* Open the file. */ + hFile = CreateFileA( pcFileName, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if( INVALID_HANDLE_VALUE == hFile ) + { + ulStatus = GetLastError(); + } + + if( 0 == ulStatus ) + { + /* Get the file size. */ + *pulDataSize = GetFileSize( hFile, ( LPDWORD ) ( &ulSize ) ); + + /* Create a buffer. */ + *ppucData = pvPortMalloc( *pulDataSize ); + + if( NULL == *ppucData ) + { + ulStatus = ERROR_NOT_ENOUGH_MEMORY; + } + } + + /* Read the file. */ + if( 0 == ulStatus ) + { + if( FALSE == ReadFile( hFile, + *ppucData, + *pulDataSize, + ( LPDWORD ) ( &ulSize ), + NULL ) ) + { + ulStatus = GetLastError(); + } + } + + /* Confirm the amount of data read. */ + if( 0 == ulStatus ) + { + if( ulSize != *pulDataSize ) + { + ulStatus = ERROR_INVALID_DATA; + } + } + + /* Clean up. */ + if( INVALID_HANDLE_VALUE != hFile ) + { + CloseHandle( hFile ); + } + + return 0 == ulStatus; +} + +/*-----------------------------------------------------------*/ + +/** + * @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, + unsigned int uiHashLen, + unsigned char * pucSig, + size_t * pxSigLen, + int ( *piRng )( void *, unsigned char *, size_t ), /*lint !e955 This parameter is unused. */ + void * pvRng ) +{ + BaseType_t xResult = 0; + P11SessionPtr_t pxSession = ( P11SessionPtr_t ) pvContext; + CK_MECHANISM xMech = { 0 }; + + /* Unreferenced parameters. */ + ( void ) ( piRng ); + ( void ) ( pvRng ); + ( void ) ( xMdAlg ); + + /* Use the PKCS#11 module to sign. */ + xMech.mechanism = CKM_SHA256; + + xResult = ( BaseType_t ) C_SignInit( + ( CK_SESSION_HANDLE ) pxSession, + &xMech, + ( CK_OBJECT_HANDLE ) pxSession->pxCurrentKey ); + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) C_Sign( + ( CK_SESSION_HANDLE ) pxSession, + ( CK_BYTE_PTR ) pucHash, /*lint !e9005 The interfaces are from 3rdparty libraries, we are not suppose to change them. */ + uiHashLen, + pucSig, + ( CK_ULONG_PTR ) pxSigLen ); + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +/** + * @brief Initializes a key structure. + */ +static CK_RV prvInitializeKey( P11SessionPtr_t pxSessionObj, + const char * pcEncodedKey, + const uint32_t ulEncodedKeyLength, + const char * pcEncodedCertificate, + const uint32_t ulEncodedCertificateLength ) +{ + CK_RV xResult = 0; + + /* + * Create the key structure, but allow an existing one to be used. + */ + + if( NULL == pxSessionObj->pxCurrentKey ) + { + if( NULL == ( pxSessionObj->pxCurrentKey = ( P11KeyPtr_t ) pvPortMalloc( + sizeof( P11Key_t ) ) ) ) /*lint !e9087 Allow casting void* to other types. */ + { + xResult = CKR_HOST_MEMORY; + } + } + + /* + * Initialize the key field, if requested. + */ + + if( ( CKR_OK == xResult ) && ( NULL != pcEncodedKey ) ) + { + memset( pxSessionObj->pxCurrentKey, 0, sizeof( P11Key_t ) ); + mbedtls_pk_init( &pxSessionObj->pxCurrentKey->xWolfPkCtx ); + + xResult = mbedtls_pk_parse_key( + &pxSessionObj->pxCurrentKey->xWolfPkCtx, + ( const unsigned char * ) pcEncodedKey, + ulEncodedKeyLength, + NULL, + 0 ); + + if (xResult != 0) { + xResult = CKR_FUNCTION_FAILED; + } + } + + /* + * Initialize the certificate field, if requested. + */ + + if( ( CKR_OK == xResult ) && ( NULL != pcEncodedCertificate ) ) + { + mbedtls_x509_crt_init( &pxSessionObj->pxCurrentKey->xWolfX509Cli ); + + mbedtls_x509_crt_parse( + &pxSessionObj->pxCurrentKey->xWolfX509Cli, + ( const unsigned char * ) pcEncodedCertificate, + ulEncodedCertificateLength ); + if (pxSessionObj->pxCurrentKey->xWolfX509Cli == NULL) { + xResult = CKR_FUNCTION_FAILED; + } + } + + return xResult; +} + + +/*-----------------------------------------------------------*/ + +/** + * @brief Load the default key and certificate from storage. + */ +static CK_RV prvLoadAndInitializeDefaultCertificateAndKey( P11SessionPtr_t pxSession ) +{ + CK_RV xResult = 0; + uint8_t * pucCertificateData = NULL; + uint32_t ulCertificateDataLength = 0; + BaseType_t xFreeCertificate = pdFALSE; + uint8_t * pucKeyData = NULL; + uint32_t ulKeyDataLength = 0; + BaseType_t xFreeKey = pdFALSE; + + /* Read the certificate from storage. */ + if( pdFALSE == prvReadFile( pkcs11FILE_NAME_CLIENT_CERTIFICATE, + &pucCertificateData, + &ulCertificateDataLength ) ) + { + pucCertificateData = ( uint8_t * ) clientcredentialCLIENT_CERTIFICATE_PEM; + ulCertificateDataLength = clientcredentialCLIENT_CERTIFICATE_LENGTH; + } + else + { + xFreeCertificate = pdTRUE; + } + + /* Read the private key from storage. */ + if( pdFALSE == prvReadFile( pkcs11FILE_NAME_KEY, + &pucKeyData, + &ulKeyDataLength ) ) + { + pucKeyData = ( uint8_t * ) clientcredentialCLIENT_PRIVATE_KEY_PEM; + ulKeyDataLength = clientcredentialCLIENT_PRIVATE_KEY_LENGTH; + } + else + { + xFreeKey = pdTRUE; + } + + /* Attach the certificate and key to the session. */ + xResult = prvInitializeKey( pxSession, + ( const char * ) pucKeyData, + ulKeyDataLength, + ( const char * ) pucCertificateData, + ulCertificateDataLength ); + + /* Clean-up. */ + if( ( NULL != pucCertificateData ) && ( pdTRUE == xFreeCertificate ) ) + { + vPortFree( pucCertificateData ); + } + + if( ( NULL != pucKeyData ) && ( pdTRUE == xFreeKey ) ) + { + vPortFree( pucKeyData ); + } + + return xResult; +} + + +/*-----------------------------------------------------------*/ + +/** + * @brief Cleans up a key structure. + */ +static void prvFreeKey( P11KeyPtr_t pxKey ) +{ + if( NULL != pxKey ) + { + /* Clean-up. */ + mbedtls_pk_free( &pxKey->xWolfPkCtx ); + mbedtls_x509_crt_free( &pxKey->xWolfX509Cli ); + vPortFree( pxKey ); + } +} + +/*-----------------------------------------------------------*/ + +/* + * PKCS#11 module implementation. + */ + +/** + * @brief PKCS#11 interface functions implemented by this Cryptoki module. + */ +static CK_FUNCTION_LIST prvP11FunctionList = +{ + { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR }, + C_Initialize, + C_Finalize, + NULL, + C_GetFunctionList, + C_GetSlotList, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + C_OpenSession, + C_CloseSession, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + C_CreateObject, + NULL, + C_DestroyObject, + NULL, + C_GetAttributeValue, + NULL, + C_FindObjectsInit, + C_FindObjects, + C_FindObjectsFinal, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + C_SignInit, + C_Sign, + NULL, + NULL, + NULL, + NULL, + C_VerifyInit, + C_Verify, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + C_GenerateRandom, + NULL, + NULL, + NULL +}; + +/** + * @brief Initialize the Cryptoki module for use. + */ +CK_DEFINE_FUNCTION( CK_RV, C_Initialize )( CK_VOID_PTR pvInitArgs ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( pvInitArgs ); + + return CKR_OK; +} + +/** + * @brief Un-initialize the Cryptoki module. + */ +CK_DEFINE_FUNCTION( CK_RV, C_Finalize )( CK_VOID_PTR pvReserved ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( pvReserved ); + + return CKR_OK; +} + +/** + * @brief Query the list of interface function pointers. + */ +CK_DEFINE_FUNCTION( CK_RV, C_GetFunctionList )( CK_FUNCTION_LIST_PTR_PTR ppxFunctionList ) +{ /*lint !e9072 It's OK to have different parameter name. */ + *ppxFunctionList = &prvP11FunctionList; + + return CKR_OK; +} + +/** + * @brief Query the list of slots. A single default slot is implemented. + */ +CK_DEFINE_FUNCTION( CK_RV, C_GetSlotList )( CK_BBOOL xTokenPresent, + CK_SLOT_ID_PTR pxSlotList, + CK_ULONG_PTR pulCount ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( xTokenPresent ); + + if( NULL == pxSlotList ) + { + *pulCount = 1; + } + else + { + if( 0u == *pulCount ) + { + return CKR_BUFFER_TOO_SMALL; + } + + pxSlotList[ 0 ] = pkcs11SLOT_ID; + *pulCount = 1; + } + + return CKR_OK; +} + +/** + * @brief Start a session for a cryptographic command sequence. + */ +CK_DEFINE_FUNCTION( CK_RV, C_OpenSession )( CK_SLOT_ID xSlotID, + CK_FLAGS xFlags, + CK_VOID_PTR pvApplication, + CK_NOTIFY xNotify, + CK_SESSION_HANDLE_PTR pxSession ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSessionObj = NULL; + + ( void ) ( xSlotID ); + ( void ) ( pvApplication ); + ( void ) ( xNotify ); + + /* + * Make space for the context. + */ + if( NULL == ( pxSessionObj = ( P11SessionPtr_t ) pvPortMalloc( sizeof( P11Session_t ) ) ) ) /*lint !e9087 Allow casting void* to other types. */ + { + xResult = CKR_HOST_MEMORY; + } + + /* + * Assume that there's no performance tradeoff in loading the default key + * now, since that's the principal use case for opening a session in this + * provider anyway. This way, the private key can be used for seeding the RNG, + * especially if there's no hardware-based alternative. + */ + + if( CKR_OK == xResult ) + { + memset( pxSessionObj, 0, sizeof( P11Session_t ) ); + xResult = prvLoadAndInitializeDefaultCertificateAndKey( pxSessionObj ); + } + + /* + * Initialize RNG. + */ + + if( CKR_OK == xResult ) + { + mbedtls_ctr_drbg_init( &pxSessionObj->xWolfDrbgCtx ); + } + + if( CKR_OK == xResult ) + { + /* + * Assign the session. + */ + + pxSessionObj->ulState = + 0u != ( xFlags & CKF_RW_SESSION ) ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; + pxSessionObj->xOpened = CK_TRUE; + + /* + * Return the session. + */ + + *pxSession = ( CK_SESSION_HANDLE ) pxSessionObj; /*lint !e923 Allow casting pointer to integer type for handle. */ + } + + return xResult; +} + +/** + * @brief Terminate a session and release resources. + */ +CK_DEFINE_FUNCTION( CK_RV, C_CloseSession )( CK_SESSION_HANDLE xSession ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); + + if( NULL != pxSession ) + { + /* + * Tear down the session. + */ + + if( NULL != pxSession->pxCurrentKey ) + { + prvFreeKey( pxSession->pxCurrentKey ); + } + + mbedtls_ctr_drbg_free( &pxSession->xWolfDrbgCtx ); + vPortFree( pxSession ); + } + + return xResult; +} + +/** + * @brief Provides import and storage of a single client certificate and + * associated private key. + */ +CK_DEFINE_FUNCTION( CK_RV, C_CreateObject )( CK_SESSION_HANDLE xSession, + CK_ATTRIBUTE_PTR pxTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR pxObject ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + + ( void )( xSession ); + + /* + * Check parameters. + */ + if( ( pkcs11CREATE_OBJECT_MIN_ATTRIBUTE_COUNT > ulCount ) || + ( NULL == pxTemplate ) || + ( NULL == pxObject ) ) + { + xResult = CKR_ARGUMENTS_BAD; + } + + if( CKR_OK == xResult ) + { + if( ( CKA_CLASS != pxTemplate[ 0 ].type ) || + ( sizeof( CK_OBJECT_CLASS ) != pxTemplate[ 0 ].ulValueLen ) ) + { + xResult = CKR_ARGUMENTS_BAD; + } + } + + /* + * Handle the object by class. + */ + + if( CKR_OK == xResult ) + { + switch( *( ( uint32_t * ) pxTemplate[ 0 ].pValue ) ) + { + case CKO_CERTIFICATE: + + /* Validate the attribute count for this object class. */ + if( pkcs11CERTIFICATE_ATTRIBUTE_COUNT != ulCount ) + { + xResult = CKR_ARGUMENTS_BAD; + break; + } + + /* Validate the next attribute type. */ + if( CKA_VALUE ) + { + if( CKA_VALUE != pxTemplate[ 1 ].type ) + { + xResult = CKR_ARGUMENTS_BAD; + break; + } + } + + if( *( ( uint32_t * )pxTemplate[ 2 ].pValue ) == pkcs11CERTIFICATE_TYPE_USER ) + { + /* Write out the client certificate. */ + if( pdFALSE == prvSaveFile( pkcs11FILE_NAME_CLIENT_CERTIFICATE, + pxTemplate[ 1 ].pValue, + pxTemplate[ 1 ].ulValueLen ) ) + { + xResult = CKR_DEVICE_ERROR; + break; + } + } + else if( *( ( uint32_t * )pxTemplate[ 2 ].pValue ) == pkcs11CERTIFICATE_TYPE_ROOT ) + { + /* Ignore writing the default root certificate. */ + } + break; + + case CKO_PRIVATE_KEY: + + /* Validate the attribute count for this object class. */ + if( pkcs11PRIVATE_KEY_ATTRIBUTE_COUNT != ulCount ) + { + xResult = CKR_ARGUMENTS_BAD; + break; + } + + /* Find the key bytes. */ + if( CKA_VALUE ) + { + if( CKA_VALUE != pxTemplate[ 3 ].type ) + { + xResult = CKR_ARGUMENTS_BAD; + break; + } + } + + /* Write out the key. */ + if( pdFALSE == prvSaveFile( pkcs11FILE_NAME_KEY, + pxTemplate[ 3 ].pValue, + pxTemplate[ 3 ].ulValueLen ) ) + { + xResult = CKR_DEVICE_ERROR; + break; + } + break; + + default: + xResult = CKR_ARGUMENTS_BAD; + } + } + + return xResult; +} + +/** + * @brief Free resources attached to an object handle. + */ +CK_DEFINE_FUNCTION( CK_RV, C_DestroyObject )( CK_SESSION_HANDLE xSession, + CK_OBJECT_HANDLE xObject ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( xSession ); + ( void ) ( xObject ); + + /* + * This implementation uses virtual handles, and the certificate and + * private key data are attached to the session, so nothing to do here. + */ + return CKR_OK; +} + +/** + * @brief Query the value of the specified cryptographic object attribute. + */ +CK_DEFINE_FUNCTION( CK_RV, C_GetAttributeValue )( CK_SESSION_HANDLE xSession, + CK_OBJECT_HANDLE xObject, + CK_ATTRIBUTE_PTR pxTemplate, + CK_ULONG ulCount ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); + CK_VOID_PTR pvAttr = NULL; + CK_ULONG ulAttrLength = 0; + mbedtls_pk_type_t xWolfPkType; + CK_ULONG xP11KeyType, iAttrib, xKeyBitLen; + + ( void ) ( xObject ); + + /* + * Enumerate the requested attributes. + */ + + for( iAttrib = 0; iAttrib < ulCount && CKR_OK == xResult; iAttrib++ ) + { + /* + * Get the attribute data and size. + */ + + switch( pxTemplate[ iAttrib ].type ) + { + case CKA_KEY_TYPE: + + /* + * Map the private key type between APIs. + */ + xWolfPkType = mbedtls_pk_get_type( &pxSession->pxCurrentKey->xWolfPkCtx ); + switch( xWolfPkType ) + { + case MBEDTLS_PK_RSA: + case MBEDTLS_PK_RSA_ALT: + case MBEDTLS_PK_RSASSA_PSS: + xP11KeyType = CKK_RSA; + break; + + case MBEDTLS_PK_ECKEY: + case MBEDTLS_PK_ECKEY_DH: + xP11KeyType = CKK_EC; + break; + + case MBEDTLS_PK_ECDSA: + xP11KeyType = CKK_ECDSA; + break; + + default: + xResult = CKR_ATTRIBUTE_VALUE_INVALID; + break; + } + + ulAttrLength = sizeof( xP11KeyType ); + pvAttr = &xP11KeyType; + break; + + case CKA_VALUE: + + /* + * Assume that the query is for the encoded client certificate. + */ + #if 0 + pvAttr = ( CK_VOID_PTR ) pxSession->pxCurrentKey->xWolfX509Cli.raw.p; /*lint !e9005 !e9087 Allow casting other types to void*. */ + ulAttrLength = pxSession->pxCurrentKey->xWolfX509Cli.raw.len; + #else + xResult = CKR_ATTRIBUTE_VALUE_INVALID; + #endif + break; + + case CKA_MODULUS_BITS: + case CKA_PRIME_BITS: + + /* + * Key strength size query, handled the same for RSA or ECDSA + * in this port. + */ + xKeyBitLen = mbedtls_pk_get_bitlen( + &pxSession->pxCurrentKey->xWolfPkCtx ); + ulAttrLength = sizeof( xKeyBitLen ); + pvAttr = &xKeyBitLen; + break; + + case CKA_VENDOR_DEFINED: + + /* + * Return the key context for application-layer use. + */ + #if 0 + ulAttrLength = sizeof( pxSession->pxCurrentKey->xWolfPkCtx ); + pvAttr = &pxSession->pxCurrentKey->xWolfPkCtx; + #else + xResult = CKR_ATTRIBUTE_VALUE_INVALID; + #endif + break; + + default: + xResult = CKR_ATTRIBUTE_TYPE_INVALID; + break; + } + + if( CKR_OK == xResult ) + { + /* + * Copy out the data and size. + */ + + if( NULL != pxTemplate[ iAttrib ].pValue ) + { + if( pxTemplate[ iAttrib ].ulValueLen < ulAttrLength ) + { + xResult = CKR_BUFFER_TOO_SMALL; + } + else + { + memcpy( pxTemplate[ iAttrib ].pValue, pvAttr, ulAttrLength ); + } + } + + pxTemplate[ iAttrib ].ulValueLen = ulAttrLength; + } + } + + return xResult; +} + +/** + * @brief Begin an enumeration sequence for the objects of the specified type. + */ +CK_DEFINE_FUNCTION( CK_RV, C_FindObjectsInit )( CK_SESSION_HANDLE xSession, + CK_ATTRIBUTE_PTR pxTemplate, + CK_ULONG ulCount ) +{ /*lint !e9072 It's OK to have different parameter name. */ + P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); + + ( void ) ( ulCount ); + + /* + * Allow filtering on a single object class attribute. + */ + + pxSession->xFindObjectInit = CK_TRUE; + pxSession->xFindObjectComplete = CK_FALSE; + memcpy( &pxSession->xFindObjectClass, + pxTemplate[ 0 ].pValue, + sizeof( CK_OBJECT_CLASS ) ); + + return CKR_OK; +} + +/** + * @brief Query the objects of the requested type. + */ +CK_DEFINE_FUNCTION( CK_RV, C_FindObjects )( CK_SESSION_HANDLE xSession, + CK_OBJECT_HANDLE_PTR pxObject, + CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + BaseType_t xDone = pdFALSE; + P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); + + /* + * Check parameters. + */ + + if( ( CK_BBOOL ) CK_FALSE == pxSession->xFindObjectInit ) + { + xResult = CKR_OPERATION_NOT_INITIALIZED; + xDone = pdTRUE; + } + + if( ( pdFALSE == xDone ) && ( 0u == ulMaxObjectCount ) ) + { + xResult = CKR_ARGUMENTS_BAD; + xDone = pdTRUE; + } + + if( ( pdFALSE == xDone ) && ( ( CK_BBOOL ) CK_TRUE == pxSession->xFindObjectComplete ) ) + { + *pulObjectCount = 0; + xResult = CKR_OK; + xDone = pdTRUE; + } + + /* + * Load the default private key and certificate. + */ + + if( ( pdFALSE == xDone ) && ( NULL == pxSession->pxCurrentKey ) ) + { + if( CKR_OK != ( xResult = prvLoadAndInitializeDefaultCertificateAndKey( pxSession ) ) ) + { + xDone = pdTRUE; + } + } + + if( pdFALSE == xDone ) + { + /* + * Return object handles based on find type. + */ + + switch( pxSession->xFindObjectClass ) + { + case CKO_PRIVATE_KEY: + *pxObject = pkcs11OBJECT_HANDLE_PRIVATE_KEY; + *pulObjectCount = 1; + break; + + case CKO_PUBLIC_KEY: + *pxObject = pkcs11OBJECT_HANDLE_PUBLIC_KEY; + *pulObjectCount = 1; + break; + + case CKO_CERTIFICATE: + *pxObject = pkcs11OBJECT_HANDLE_CERTIFICATE; + *pulObjectCount = 1; + break; + + default: + *pxObject = 0; + *pulObjectCount = 0; + break; + } + + pxSession->xFindObjectComplete = CK_TRUE; + } + + return xResult; +} + +/** + * @brief Terminate object enumeration. + */ +CK_DEFINE_FUNCTION( CK_RV, C_FindObjectsFinal )( CK_SESSION_HANDLE xSession ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); + + /* + * Check parameters. + */ + + if( ( CK_BBOOL ) CK_FALSE == pxSession->xFindObjectInit ) + { + xResult = CKR_OPERATION_NOT_INITIALIZED; + } + else + { + /* + * Clean-up find objects state. + */ + + pxSession->xFindObjectInit = CK_FALSE; + pxSession->xFindObjectComplete = CK_FALSE; + pxSession->xFindObjectClass = 0; + } + + return xResult; +} + +/** + * @brief Begin a digital signature generation session. + */ +CK_DEFINE_FUNCTION( CK_RV, C_SignInit )( CK_SESSION_HANDLE xSession, + CK_MECHANISM_PTR pxMechanism, + CK_OBJECT_HANDLE xKey ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( xSession ); + ( void ) ( pxMechanism ); + ( void ) ( xKey ); + + return CKR_OK; +} + +/** + * @brief Digitally sign the indicated cryptographic hash bytes. + */ +CK_DEFINE_FUNCTION( CK_RV, C_Sign )( CK_SESSION_HANDLE xSession, + CK_BYTE_PTR pucData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pucSignature, + CK_ULONG_PTR pulSignatureLen ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession ); + + /* + * Support length check. + */ + + if( NULL == pucSignature ) + { + *pulSignatureLen = pkcs11SUPPORTED_KEY_BITS / 8; + } + else + { + /* + * Check algorithm support. + */ + + if( ( CK_ULONG ) cryptoSHA256_DIGEST_BYTES != ulDataLen ) + { + xResult = CKR_DATA_LEN_RANGE; + } + + /* + * Sign the data. + */ +#if 0 + if( CKR_OK == xResult ) + { + if( 0 != pxSessionObj->pxCurrentKey->pfnSavedWolfSign( + pxSessionObj->pxCurrentKey->pvSavedWolfPkCtx, + MBEDTLS_MD_SHA256, + pucData, + ulDataLen, + pucSignature, + ( size_t * ) pulSignatureLen, + mbedtls_ctr_drbg_random, + &pxSessionObj->xWolfDrbgCtx ) ) + { + xResult = CKR_FUNCTION_FAILED; + } + } +#else + (void)pxSessionObj; + (void)pucData; + (void)ulDataLen; + (void)pucSignature; + (void)pulSignatureLen; + + xResult = CKR_FUNCTION_FAILED; +#endif + } + + return xResult; +} + +/** + * @brief Begin a digital signature verification session. + */ +CK_DEFINE_FUNCTION( CK_RV, C_VerifyInit )( CK_SESSION_HANDLE xSession, + CK_MECHANISM_PTR pxMechanism, + CK_OBJECT_HANDLE xKey ) +{ /*lint !e9072 It's OK to have different parameter name. */ + ( void ) ( xSession ); + ( void ) ( pxMechanism ); + ( void ) ( xKey ); + + return CKR_OK; +} + +/** + * @brief Verify the digital signature of the specified data using the public + * key attached to this session. + */ +CK_DEFINE_FUNCTION( CK_RV, C_Verify )( CK_SESSION_HANDLE xSession, + CK_BYTE_PTR pucData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pucSignature, + CK_ULONG ulSignatureLen ) +{ /*lint !e9072 It's OK to have different parameter name. */ + CK_RV xResult = CKR_OK; + P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession ); + +#if 0 + /* Verify the signature. */ + if( 0 != pxSessionObj->pxCurrentKey->xWolfPkInfo.verify_func( + pxSessionObj->pxCurrentKey->pvSavedWolfPkCtx, + MBEDTLS_MD_SHA256, + pucData, + ulDataLen, + pucSignature, + ulSignatureLen ) ) + { + xResult = CKR_SIGNATURE_INVALID; + } +#else + (void)pxSessionObj; + (void)pucData; + (void)ulDataLen; + (void)pucSignature; + (void)ulSignatureLen; + xResult = CKR_SIGNATURE_INVALID; +#endif + + /* Return the signature verification result. */ + return xResult; +} + +/** + * @brief Generate cryptographically random bytes. + */ +CK_DEFINE_FUNCTION( CK_RV, C_GenerateRandom )( CK_SESSION_HANDLE xSession, + CK_BYTE_PTR pucRandomData, + CK_ULONG ulRandomLen ) +{ /*lint !e9072 It's OK to have different parameter name. */ + P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession ); + + if( 0 != mbedtls_ctr_drbg_random( &pxSessionObj->xWolfDrbgCtx, pucRandomData, ulRandomLen ) ) + { + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +#endif /* WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/lib/third_party/wolfssl b/FreeRTOS-AWS/lib/third_party/wolfssl new file mode 160000 index 0000000..2988fee --- /dev/null +++ b/FreeRTOS-AWS/lib/third_party/wolfssl @@ -0,0 +1 @@ +Subproject commit 2988fee09c3d8f964752a83f55072f39df06d818 diff --git a/FreeRTOS-AWS/lib/tls/aws_tls.c b/FreeRTOS-AWS/lib/tls/aws_tls.c index e7e205b..0af8e1a 100755 --- a/FreeRTOS-AWS/lib/tls/aws_tls.c +++ b/FreeRTOS-AWS/lib/tls/aws_tls.c @@ -36,6 +36,8 @@ /* TODO */ /*#include "aws_clientcredential_keys.h"*/ +#ifndef WOLF_AWSTLS + /* mbedTLS includes. */ #include "mbedtls/platform.h" #include "mbedtls/net.h" @@ -642,3 +644,5 @@ void TLS_Cleanup( void * pvContext ) vPortFree( pCtx ); } } + +#endif /* !WOLF_AWSTLS */ diff --git a/FreeRTOS-AWS/lib/tls/wolf_tls.c b/FreeRTOS-AWS/lib/tls/wolf_tls.c new file mode 100755 index 0000000..7914791 --- /dev/null +++ b/FreeRTOS-AWS/lib/tls/wolf_tls.c @@ -0,0 +1,564 @@ +/* + * Amazon FreeRTOS TLS V1.1.0 + * Copyright (C) 2017 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.h" +#include "FreeRTOSIPConfig.h" +#include "aws_tls.h" +#include "aws_crypto.h" +#include "aws_pkcs11.h" +#include "task.h" +#include "aws_clientcredential.h" +#include "aws_default_root_certificates.h" + +#ifdef WOLF_AWSTLS + +/* wolfSSL compatibility layer (github.com/wolfSSL/wolfssl) */ +#include + +/* C runtime includes. */ +#include +#include +#include + +/** + * @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] pxNetworkRecv Callback for receiving data on an open TCP socket. + * @param[in] pxNetworkSend Callback for sending data on an open TCP socket. + * @param[in] pvCallerContext Opaque pointer provided by caller for above callbacks. + * @param[out] ctx wolfSSL context for creating connections + * @param[out] ssl wolfSSL object for connection + * @param[out] pxP11FunctionList PKCS#11 function list structure. + * @param[out] xP11Session PKCS#11 session context. + * @param[out] xP11PrivateKey PKCS#11 private key context. + * @param[out] ulP11ModulusBytes Number of bytes in the client private key modulus. + */ +typedef struct TLSContext +{ + const char * pcDestination; + const char * pcServerCertificate; + uint32_t ulServerCertificateLength; + const char ** ppcAlpnProtocols; + uint32_t ulAlpnProtocolsCount; + + NetworkRecv_t pxNetworkRecv; + NetworkSend_t pxNetworkSend; + void * pvCallerContext; + + /* wolfSSL */ + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + WOLFSSL_CERT_MANAGER* cm; + + /* PKCS#11. */ + CK_FUNCTION_LIST_PTR pxP11FunctionList; + CK_SESSION_HANDLE xP11Session; + CK_OBJECT_HANDLE xP11PrivateKey; + CK_ULONG ulP11ModulusBytes; +} TLSContext_t; + +/* + * Helper routines. + */ + +/** + * @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(WOLFSSL* ssl, char *pucData, int xDataLength, + void *pvContext) +{ + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + (void)ssl; + + return ( int ) pCtx->pxNetworkSend( pCtx->pvCallerContext, (const byte*)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(WOLFSSL* ssl, char *pucReceiveBuffer, int xReceiveLength, + void *pvContext) +{ + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + (void)ssl; + + return ( int ) pCtx->pxNetworkRecv( pCtx->pvCallerContext, (byte*)pucReceiveBuffer, xReceiveLength ); +} + + +static int prvCheckCertificate(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + char buffer[WOLFSSL_MAX_ERROR_SZ]; + (void)preverify; + + printf("In verification callback, error = %d, %s\n", store->error, + wolfSSL_ERR_error_string(store->error, buffer)); + printf("Subject's domain name is %s\n", store->domain); + + if (store->error == ASN_BEFORE_DATE_E || store->error == ASN_AFTER_DATE_E) { + printf("Overriding cert date error as example for bad clock testing\n"); + return 1; + } + printf("Cert error is not date error, not overriding\n"); + + return 0; +} + + +/** + * @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 * pCtx ) +{ + BaseType_t xResult = 0; + CK_C_GetFunctionList pxCkGetFunctionList = NULL; + CK_SLOT_ID xSlotId = 0; + CK_ULONG ulCount = 1; + CK_ATTRIBUTE xTemplate = { 0 }; + CK_OBJECT_CLASS xObjClass = 0; + CK_OBJECT_HANDLE xCertObj = 0; + CK_BYTE * pucCertificate = NULL; + + /* Ensure that the PKCS#11 module is initialized. */ + if( 0 == xResult ) + { + pxCkGetFunctionList = C_GetFunctionList; + xResult = ( BaseType_t ) pxCkGetFunctionList( &pCtx->pxP11FunctionList ); + } + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_Initialize( NULL ); + } + + /* Get the default private key storage ID. */ + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_GetSlotList( CK_TRUE, &xSlotId, &ulCount ); + } + + /* Start a private session with the P#11 module. */ + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_OpenSession( xSlotId, + 0, + NULL, + NULL, + &pCtx->xP11Session ); + } + + /* Enumerate the first private key. */ + if( 0 == xResult ) + { + xTemplate.type = CKA_CLASS; + xTemplate.ulValueLen = sizeof( CKA_CLASS ); + xTemplate.pValue = &xObjClass; + xObjClass = CKO_PRIVATE_KEY; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjectsInit( pCtx->xP11Session, &xTemplate, 1 ); + } + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjects( pCtx->xP11Session, &pCtx->xP11PrivateKey, 1, &ulCount ); + } + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjectsFinal( pCtx->xP11Session ); + } + + /* Get the internal key context. */ + if( 0 == xResult ) + { + xTemplate.type = CKA_VENDOR_DEFINED; + xTemplate.ulValueLen = sizeof( pCtx->cm ); + xTemplate.pValue = &pCtx->cm; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_GetAttributeValue( + pCtx->xP11Session, pCtx->xP11PrivateKey, &xTemplate, 1 ); + } + + /* Get the key size. */ + if( 0 == xResult ) + { + xTemplate.type = CKA_MODULUS_BITS; + xTemplate.ulValueLen = sizeof( pCtx->ulP11ModulusBytes ); + xTemplate.pValue = &pCtx->ulP11ModulusBytes; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_GetAttributeValue( + pCtx->xP11Session, pCtx->xP11PrivateKey, &xTemplate, 1 ); + } + + if( 0 == xResult ) + { + pCtx->ulP11ModulusBytes /= 8; + + /* Enumerate the first client certificate. */ + xTemplate.type = CKA_CLASS; + xTemplate.ulValueLen = sizeof( CKA_CLASS ); + xTemplate.pValue = &xObjClass; + xObjClass = CKO_CERTIFICATE; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjectsInit( pCtx->xP11Session, &xTemplate, 1 ); + } + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjects( pCtx->xP11Session, &xCertObj, 1, &ulCount ); + } + + if( 0 == xResult ) + { + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_FindObjectsFinal( pCtx->xP11Session ); + } + + if( 0 == xResult ) + { + /* Query the certificate size. */ + xTemplate.type = CKA_VALUE; + xTemplate.ulValueLen = 0; + xTemplate.pValue = NULL; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_GetAttributeValue( pCtx->xP11Session, xCertObj, &xTemplate, 1 ); + } + + if( 0 == xResult ) + { + /* Create a buffer for the certificate. */ + pucCertificate = ( CK_BYTE_PTR ) pvPortMalloc( xTemplate.ulValueLen ); /*lint !e9079 Allow casting void* to other types. */ + + if( NULL == pucCertificate ) + { + xResult = ( BaseType_t ) CKR_HOST_MEMORY; + } + } + + if( 0 == xResult ) + { + /* Export the certificate. */ + xTemplate.pValue = pucCertificate; + xResult = ( BaseType_t ) pCtx->pxP11FunctionList->C_GetAttributeValue( + pCtx->xP11Session, xCertObj, &xTemplate, 1 ); + } + + /* Decode the client certificate. */ + if( 0 == xResult ) + { + xResult = wolfSSL_CTX_load_verify_buffer(pCtx->ctx, + (const byte*)pucCertificate, xTemplate.ulValueLen, + WOLFSSL_FILETYPE_PEM); + } + + if( NULL != pucCertificate ) + { + vPortFree( pucCertificate ); + } + + return xResult; +} + +/* + * Interface routines. + */ + +BaseType_t TLS_Init( void ** ppvContext, + TLSParams_t * pxParams ) +{ + BaseType_t xResult = 0; + TLSContext_t * pCtx = NULL; + + /* Allocate an internal context. */ + pCtx = ( TLSContext_t * ) pvPortMalloc( sizeof( TLSContext_t ) ); /*lint !e9087 !e9079 Allow casting void* to other types. */ + + if( NULL != pCtx ) + { + memset( pCtx, 0, sizeof( TLSContext_t ) ); + *ppvContext = pCtx; + + /* Initialize the context. */ + pCtx->pcDestination = pxParams->pcDestination; + pCtx->pcServerCertificate = pxParams->pcServerCertificate; + pCtx->ulServerCertificateLength = pxParams->ulServerCertificateLength; + pCtx->ppcAlpnProtocols = pxParams->ppcAlpnProtocols; + pCtx->ulAlpnProtocolsCount = pxParams->ulAlpnProtocolsCount; + pCtx->pxNetworkRecv = pxParams->pxNetworkRecv; + pCtx->pxNetworkSend = pxParams->pxNetworkSend; + pCtx->pvCallerContext = pxParams->pvCallerContext; + + wolfSSL_Init(); + } + else + { + xResult = ( BaseType_t ) CKR_HOST_MEMORY; + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +BaseType_t TLS_Connect( void * pvContext ) +{ + BaseType_t xResult = pdFREERTOS_ERRNO_NONE; + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + + /* Ensure that the FreeRTOS heap is used. */ + CRYPTO_ConfigureHeap(); + + /* create wolf context (factory for generating wolfSSL connection objects) */ + pCtx->ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); + if (pCtx->ctx == NULL) { + xResult = pdFREERTOS_ERRNO_ENOMEM; + } + + /* load certificate */ + if ( NULL != pCtx->pcServerCertificate ) + { + xResult = wolfSSL_CTX_load_verify_buffer(pCtx->ctx, + (const byte*)pCtx->pcServerCertificate, + pCtx->ulServerCertificateLength, WOLFSSL_FILETYPE_PEM); + } + else + { + xResult = wolfSSL_CTX_load_verify_buffer(pCtx->ctx, + (const byte*)tlsVERISIGN_ROOT_CERTIFICATE_PEM, + tlsVERISIGN_ROOT_CERTIFICATE_LENGTH, + WOLFSSL_FILETYPE_PEM); + + if( 0 == xResult ) + { + xResult = wolfSSL_CTX_load_verify_buffer(pCtx->ctx, + (const byte*)tlsATS1_ROOT_CERTIFICATE_PEM, + tlsATS1_ROOT_CERTIFICATE_LENGTH, + WOLFSSL_FILETYPE_PEM); + } + } + + if( 0 == xResult ) + { + wolfSSL_CTX_set_verify(pCtx->ctx, WOLFSSL_VERIFY_PEER, + prvCheckCertificate); + + /* Setup the client credential. */ + xResult = prvInitializeClientCredential( pCtx ); + } + + /* Set the hostname, if requested. */ + if( ( 0 == xResult ) && ( NULL != pCtx->pcDestination ) ) + { +#ifdef HAVE_SNI + if (wolfSSL_CTX_UseSNI(pCtx->ctx, 0, pCtx->pcDestination, + (word16)XSTRLEN(pCtx->pcDestination)) != WOLFSSL_SUCCESS) { + xResult = pdFREERTOS_ERRNO_ENOPROTOOPT; +#endif + } + + + /* create connection object */ + if( 0 == xResult ) + { + pCtx->ssl = wolfSSL_new(pCtx->ctx); + if (pCtx->ssl == NULL) { + xResult = pdFREERTOS_ERRNO_ENOMEM; + } + } + + if( 0 == xResult && NULL != pCtx->ppcAlpnProtocols ) + { + /* Include an application protocol list in the TLS ClientHello + * message. */ +#ifdef HAVE_ALPN + size_t cur_len, tot_len; + const char **p; + tot_len = 0; + for( p = protos; *p != NULL; p++ ) { + cur_len = strlen( *p ); + tot_len += cur_len; + + if (cur_len > 0 && cur_len <= 255 && tot_len < 65535) { + wolfSSL_UseALPN(pCtx->ssl, *p, (word32)cur_len, WOLFSSL_ALPN_CONTINUE_ON_MISMATCH); + } + else { + xResult = pdFREERTOS_ERRNO_EINVAL; + break; + } + } +#endif + } + + + /* Set the socket callbacks. */ + if( 0 == xResult ) + { + /* Setup the IO callbacks */ + wolfSSL_CTX_SetIORecv(pCtx->ctx, prvNetworkRecv); + wolfSSL_CTX_SetIOSend(pCtx->ctx, prvNetworkSend); + wolfSSL_SetIOReadCtx( pCtx->ssl, (void*)pCtx); + wolfSSL_SetIOWriteCtx(pCtx->ssl, (void*)pCtx); + + /* Negotiate. */ + while( WOLFSSL_SUCCESS != ( xResult = wolfSSL_connect(pCtx->ssl) ) ) + { + xResult = wolfSSL_get_error(pCtx->ssl, 0); + + if( ( WOLFSSL_ERROR_WANT_READ != xResult ) && + ( WOLFSSL_ERROR_WANT_WRITE != xResult ) ) + { + break; + } + } + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +BaseType_t TLS_Recv( void * pvContext, + unsigned char * pucReadBuffer, + size_t xReadLength ) +{ + BaseType_t xResult = 0; + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + size_t xRead = 0; + + if( NULL != pCtx ) + { + while( xRead < xReadLength ) + { + xResult = wolfSSL_read( pCtx->ssl, + pucReadBuffer + xRead, + xReadLength - xRead ); + + if( 0 < xResult ) + { + /* Got data, so update the tally and keep looping. */ + xRead += ( size_t ) xResult; + } + else + { + if( ( 0 == xResult ) || ( WOLFSSL_ERROR_WANT_READ != xResult ) ) + { + /* No data and no error or call read again, if indicated, otherwise return error. */ + break; + } + } + } + } + + if( 0 <= xResult ) + { + xResult = ( BaseType_t ) xRead; + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +BaseType_t TLS_Send( void * pvContext, + const unsigned char * pucMsg, + size_t xMsgLength ) +{ + BaseType_t xResult = 0; + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + size_t xWritten = 0; + + if( NULL != pCtx ) + { + while( xWritten < xMsgLength ) + { + xResult = wolfSSL_write( pCtx->ssl, + pucMsg + xWritten, + xMsgLength - xWritten ); + + if( 0 < xResult ) + { + /* Sent data, so update the tally and keep looping. */ + xWritten += ( size_t ) xResult; + } + else + { + if( ( 0 == xResult ) || ( WOLFSSL_ERROR_WANT_WRITE != xResult ) ) + { + /* No data and no error or call read again, if indicated, otherwise return error. */ + break; + } + } + } + } + + if( 0 <= xResult ) + { + xResult = ( BaseType_t ) xWritten; + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +void TLS_Cleanup( void * pvContext ) +{ + TLSContext_t * pCtx = ( TLSContext_t * ) pvContext; /*lint !e9087 !e9079 Allow casting void* to other types. */ + + if( NULL != pCtx ) + { + /* Cleanup wolfSSL. */ + wolfSSL_shutdown( pCtx->ssl ); + wolfSSL_free( pCtx->ssl ); + wolfSSL_CTX_free( pCtx->ctx ); + + /* Cleanup PKCS#11. */ + if( ( NULL != pCtx->pxP11FunctionList ) && + ( NULL != pCtx->pxP11FunctionList->C_CloseSession ) ) + { + pCtx->pxP11FunctionList->C_CloseSession( pCtx->xP11Session ); /*lint !e534 This function always return CKR_OK. */ + pCtx->pxP11FunctionList->C_Finalize( NULL ); /*lint !e534 This function always return CKR_OK. */ + } + + /* Free memory. */ + vPortFree( pCtx ); + } +} + +#endif /* WOLF_AWSTLS */