diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 0dba72d0a1e4f9..a180b3d45e5c88 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -26,6 +26,8 @@ #include #endif +#include + #include #include #include @@ -80,18 +82,7 @@ constexpr size_t kMAX_P256Keypair_Context_Size = 512; constexpr size_t kEmitDerIntegerWithoutTagOverhead = 1; // 1 sign stuffer constexpr size_t kEmitDerIntegerOverhead = 3; // Tag + Length byte + 1 sign stuffer -/* - * Worst case is OpenSSL, so let's use its worst case and let static assert tell us if - * we are wrong, since `typedef SHA_LONG unsigned int` is default. - * SHA_LONG h[8]; - * SHA_LONG Nl, Nh; - * SHA_LONG data[SHA_LBLOCK]; // SHA_LBLOCK is 16 for SHA256 - * unsigned int num, md_len; - * - * We also have to account for possibly some custom extensions on some targets, - * especially for mbedTLS, so an extra sizeof(uint64_t) is added to account. - */ -constexpr size_t kMAX_Hash_SHA256_Context_Size = ((sizeof(unsigned int) * (8 + 2 + 16 + 2)) + sizeof(uint64_t)); +constexpr size_t kMAX_Hash_SHA256_Context_Size = CHIP_CONFIG_SHA256_CONTEXT_SIZE; /* * Overhead to encode a raw ECDSA signature in X9.62 format in ASN.1 DER diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index fa40168750175d..6525beed44609c 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -207,13 +207,6 @@ CHIP_ERROR Hash_SHA1(const uint8_t * data, const size_t data_length, uint8_t * o return CHIP_NO_ERROR; } -Hash_SHA256_stream::Hash_SHA256_stream(void) {} - -Hash_SHA256_stream::~Hash_SHA256_stream(void) -{ - Clear(); -} - static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(mbedtls_sha256_context), "kMAX_Hash_SHA256_Context_Size is too small for the size of underlying mbedtls_sha256_context"); @@ -222,6 +215,19 @@ static inline mbedtls_sha256_context * to_inner_hash_sha256_context(HashSHA256Op return SafePointerCast(context); } +Hash_SHA256_stream::Hash_SHA256_stream(void) +{ + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + mbedtls_sha256_init(context); +} + +Hash_SHA256_stream::~Hash_SHA256_stream(void) +{ + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + mbedtls_sha256_free(context); + Clear(); +} + CHIP_ERROR Hash_SHA256_stream::Begin(void) { mbedtls_sha256_context * const context = to_inner_hash_sha256_context(&mContext); @@ -254,7 +260,7 @@ CHIP_ERROR Hash_SHA256_stream::GetDigest(MutableByteSpan & out_buffer) CHIP_ERROR result = Finish(out_buffer); // Restore context prior to finalization. - *context = previous_ctx; + mbedtls_sha256_clone(context, &previous_ctx); return result; } diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 9168df553a39d3..364a7dd4ca1094 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -863,6 +863,28 @@ #error "Please assert exactly one CHIP_CONFIG_HASH_IMPLEMENTATION_... option." #endif +/** + * @def CHIP_CONFIG_SHA256_CONTEXT_SIZE + * + * @brief + * Size of the statically allocated context for SHA256 operations in CryptoPAL + * + * The default size is based on the Worst software implementation, OpenSSL. A + * static assert will tell us if we are wrong, since `typedef SHA_LONG unsigned + * int` is default. + * SHA_LONG h[8]; + * SHA_LONG Nl, Nh; + * SHA_LONG data[SHA_LBLOCK]; // SHA_LBLOCK is 16 for SHA256 + * unsigned int num, md_len; + * + * We also have to account for possibly some custom extensions on some targets, + * especially for mbedTLS, so an extra sizeof(uint64_t) is added to account. + * + */ +#ifndef CHIP_CONFIG_SHA256_CONTEXT_SIZE +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE ((sizeof(unsigned int) * (8 + 2 + 16 + 2)) + sizeof(uint64_t)) +#endif // CHIP_CONFIG_SHA256_CONTEXT_SIZE + /** * @name chip key export protocol configuration. * diff --git a/src/platform/cc13x2_26x2/BLEManagerImpl.h b/src/platform/cc13x2_26x2/BLEManagerImpl.h index 4b577d34b27b79..76f66bbcfed9a5 100644 --- a/src/platform/cc13x2_26x2/BLEManagerImpl.h +++ b/src/platform/cc13x2_26x2/BLEManagerImpl.h @@ -22,27 +22,22 @@ * Instruments cc13xx_cc26xx platform. */ -#ifndef BLEManager_IMPL_H -#define BLEManager_IMPL_H - #pragma once #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE -#ifdef __cplusplus -extern "C" { -#endif - #include "FreeRTOS.h" #include #include +#ifdef __cplusplus +extern "C" { +#endif #include #include #include "hal_types.h" -#include "chipOBleProfile.h" #include "ti_ble_config.h" #include "ti_drivers_config.h" @@ -50,6 +45,8 @@ extern "C" { } #endif +#include "chipOBleProfile.h" + namespace chip { namespace DeviceLayer { namespace Internal { @@ -367,5 +364,3 @@ inline BleLayer * BLEManagerImpl::_GetBleLayer() } // namespace chip #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - -#endif // BLEManager_IMPL_H diff --git a/src/platform/cc13x2_26x2/CHIPPlatformConfig.h b/src/platform/cc13x2_26x2/CHIPPlatformConfig.h index c561e1fe3c7582..62d7637405fd0a 100644 --- a/src/platform/cc13x2_26x2/CHIPPlatformConfig.h +++ b/src/platform/cc13x2_26x2/CHIPPlatformConfig.h @@ -41,14 +41,17 @@ // ==================== Security Adaptations ==================== +// This platform uses mbedtls, but these defines don't seem to be used in source #define CHIP_CONFIG_USE_OPENSSL_ECC 0 #define CHIP_CONFIG_USE_MICRO_ECC 1 #define CHIP_CONFIG_HASH_IMPLEMENTATION_OPENSSL 0 -#define CHIP_CONFIG_HASH_IMPLEMENTATION_MINCRYPT 1 -#define CHIP_CONFIG_HASH_IMPLEMENTATION_MBEDTLS 0 +#define CHIP_CONFIG_HASH_IMPLEMENTATION_MINCRYPT 0 +#define CHIP_CONFIG_HASH_IMPLEMENTATION_MBEDTLS 1 #define CHIP_CONFIG_HASH_IMPLEMENTATION_PLATFORM 0 +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE (sizeof(unsigned int) * 76) + #define CHIP_CONFIG_AES_IMPLEMENTATION_OPENSSL 0 #define CHIP_CONFIG_AES_IMPLEMENTATION_AESNI 0 #define CHIP_CONFIG_AES_IMPLEMENTATION_MBEDTLS 1 diff --git a/src/platform/cc13x2_26x2/crypto/aes_alt.c b/src/platform/cc13x2_26x2/crypto/aes_alt.c new file mode 100644 index 00000000000000..55165c076c49b4 --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/aes_alt.c @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "aes_alt.h" +#include "mbedtls/aes.h" + +#if defined(MBEDTLS_AES_ALT) + +#include + +#include "ti_drivers_config.h" + +#include +#include +#include + +/* + * number of active contexts, used for power on/off of the crypto core + */ +static unsigned int ref_num = 0; + +static AESECB_Handle AESECB_handle = NULL; + +void mbedtls_aes_init(mbedtls_aes_context * ctx) +{ + AESECB_Params AESECBParams; + + if (ref_num == 0) + { + AESECB_Params_init(&AESECBParams); + AESECBParams.returnBehavior = AESECB_RETURN_BEHAVIOR_POLLING; + AESECB_handle = AESECB_open(CONFIG_AESECB_1, &AESECBParams); + + // handle will be NULL if open failed, subsequent calls will fail with a generic HW error + } + ref_num++; +} + +void mbedtls_aes_free(mbedtls_aes_context * ctx) +{ + if (ref_num > 0) + { + ref_num--; + if (ref_num == 0) + { + AESECB_close(AESECB_handle); + + AESECB_handle = NULL; + } + } + + memset((void *) ctx, 0x00, sizeof(ctx)); +} + +int mbedtls_aes_setkey_enc(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits) +{ + int_fast16_t statusCrypto; + size_t keylen = keybits / 8U; // 8 bits in a byte + + if (keylen > sizeof(ctx->keyMaterial)) + { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + /* Initialize AES key */ + memcpy(ctx->keyMaterial, key, keylen); + statusCrypto = CryptoKeyPlaintext_initKey(&ctx->cryptoKey, (uint8_t *) ctx->keyMaterial, keylen); + + if (CryptoKey_STATUS_SUCCESS != statusCrypto) + { + return MBEDTLS_ERR_AES_HW_ACCEL_FAILED; + } + + return 0; +} + +int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits) +{ + int_fast16_t statusCrypto; + size_t keylen = keybits / 8U; // 8 bits in a byte + + if (keylen > sizeof(ctx->keyMaterial)) + { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + /* Initialize AES key */ + statusCrypto = CryptoKeyPlaintext_initKey(&ctx->cryptoKey, (uint8_t *) key, keylen); + + if (CryptoKey_STATUS_SUCCESS != statusCrypto) + { + return MBEDTLS_ERR_AES_HW_ACCEL_FAILED; + } + + return 0; +} + +int mbedtls_aes_crypt_ecb(mbedtls_aes_context * ctx, int mode, const unsigned char input[16], unsigned char output[16]) +{ + int statusCrypto; + AESECB_Operation operationOneStepEncrypt; + + /* run it through the authentication + encryption, pass the ccmLVal = 2 */ + AESECB_Operation_init(&operationOneStepEncrypt); + + operationOneStepEncrypt.key = &ctx->cryptoKey; + operationOneStepEncrypt.inputLength = 16; + operationOneStepEncrypt.input = (uint8_t *) input; + operationOneStepEncrypt.output = (uint8_t *) output; + + statusCrypto = AESECB_oneStepEncrypt(AESECB_handle, &operationOneStepEncrypt); + + if (CryptoKey_STATUS_SUCCESS != statusCrypto) + { + return MBEDTLS_ERR_AES_HW_ACCEL_FAILED; + } + + return 0; +} +#endif diff --git a/src/platform/cc13x2_26x2/crypto/aes_alt.h b/src/platform/cc13x2_26x2/crypto/aes_alt.h new file mode 100644 index 00000000000000..dd980f4ed50cbf --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/aes_alt.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls-config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_ALT) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + CryptoKey cryptoKey; /*!< structure for the AES driver */ + uint32_t keyMaterial[16]; /*!< memory for the key bytes used by cryptoKey */ +} mbedtls_aes_context; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_AES_ALT */ diff --git a/src/platform/cc13x2_26x2/cc13x2_26x2-mbedtls-config.h b/src/platform/cc13x2_26x2/crypto/cc13x2_26x2-mbedtls-config.h similarity index 98% rename from src/platform/cc13x2_26x2/cc13x2_26x2-mbedtls-config.h rename to src/platform/cc13x2_26x2/crypto/cc13x2_26x2-mbedtls-config.h index 8d2c7f64a27319..efca6840f5d25d 100644 --- a/src/platform/cc13x2_26x2/cc13x2_26x2-mbedtls-config.h +++ b/src/platform/cc13x2_26x2/crypto/cc13x2_26x2-mbedtls-config.h @@ -42,7 +42,7 @@ #define MBEDTLS_ECJPAKE_ALT #define MBEDTLS_AES_ALT #define MBEDTLS_SHA256_ALT -//#define MBEDTLS_ENTROPY_HARDWARE_ALT +#define MBEDTLS_ENTROPY_HARDWARE_ALT /** * Enable Crypto and Entropy modules diff --git a/src/platform/cc13x2_26x2/crypto/ecjpake_alt.c b/src/platform/cc13x2_26x2/crypto/ecjpake_alt.c new file mode 100644 index 00000000000000..84b60b0f92c347 --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/ecjpake_alt.c @@ -0,0 +1,900 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/ecjpake.h" + +#if defined(MBEDTLS_ECJPAKE_ALT) +#include "ecjpake_alt.h" + +#include + +#include "ti_drivers_config.h" + +#include +#include + +/* + * NOTE: On calling convention in this file. + * + * Many of the helper functions in this file take a pointer to a `uint8_t*`, + * usually called `p`. This is the current working pointer for the input or + * output buffer. They will also take a pointer to a `uint8_t`, usually called + * `end`. This is the pointer to the end of the current working buffer. The + * difference between these two pointers is calculated and used as the current + * available length of the working buffer. This is checked before anything is + * written to or read from the buffer. While values are read or written to the + * data at the pointer pointed at by `p`, the pointer pointed at by `p` is + * updated to point to the next available value. The callee updates the value + * of `p` for the caller, almost in the same fashion as strtok. + * + * Here is an example: + * ``` + * static int read_be_uint16(const uint8_t **p, + * const uint8_t *end, + * uint16_t *value) + * { + * if ((end < *p) || (end - *p < sizeof(uint16_t))) + * { + * return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + * } + * *value = ((uint16_t)(*p)[0] << 8) | (*p)[1]); + * return (0); + * } + * + * void sample_func(void) + * { + * uint8_t buffer[4] = {0x01, 0x02, 0x03, 0x04}; + * uint8_t* p = buffer + sizeof(buffer); + * uint8_t* end = buffer + sizeof(buffer); + * uint16_t value; + * + * read_be_uint16(&p, end, &value); + * // value is now 0x0102 + * // p points to buffer[2] + * read_be_uint16(&p, end, &value); + * // value is now 0x0304 + * // p points to buffer[4] (invalid) + * } + */ + +/* + * Convert a mbedtls_ecjpake_role to identifier string. + * + * depends on the value of the enumeration of mbedtls_ecjpake_role. + */ +static const char * const ecjpake_id[] = { "client", "server" }; + +#define ID_MINE (ecjpake_id[ctx->role]) +#define ID_PEER (ecjpake_id[1 - ctx->role]) + +/* + * Size of the temporary buffer for ecjpake_hash: + * 3 EC points plus their length, plus ID and its length (4 + 6 bytes) + */ +#define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6) + +/** + * \breif execute the contents of this macro, save the return in + * `ret` and goto `cleanup` if it is not `0` + * + * The internal functions of this file driver are designed to return `0` on + * success. The caller is expected to have an `int ret` in the translation unit + * of the call-site, and a target `cleanup`. It is common practice to return + * `ret` in the caller. + * + * ``` + * int example_func(void) + * { + * int ret; + * ECJPAKE_ALT_CHK(some_func()); + * + * some_other_func(); + * + * cleanup: + * return ret; + * } + * ``` + * + * \param f code to execute + */ +#define ECJPAKE_ALT_CHK(f) \ + do \ + { \ + if ((ret = f) != 0) \ + goto cleanup; \ + } while (0) + +/** + * \brief writes a buffer prepended with a length byte + * + * \param p pointer to output buffer, will be changed by a successful + * call + * \param end pointer to the end of the output buffer + * \param key the CryptoKey to write + * \param bin the source to copy + * \param len the length to copy and write + * + * \return 0 if successful, + * a negative error code otherwise + * + * \retval MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * the input buffer is too small + */ +static int tls_write_binary(uint8_t ** p, const uint8_t * end, const uint8_t * bin, size_t len) +{ + if ((end < *p) || ((size_t)(end - *p) < 1 + len)) + { + return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + } + + /* write the length to the buffer */ + (*p)[0] = len; + *p += 1; + + /* write the binary data as is */ + memcpy(*p, bin, len); + *p += len; + + return (0); +} + +/** + * \brief read a binary value prepended by a length bit + * + * \param p pointer to input buffer, will be changed by a successful + * call + * \param end pointer to the end of the input buffer + * \param bin the array to fill + * \param len the size of \p bin + * + * \return 0 if successful, + * a negative error code otherwise + * + * \retval MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * the input buffer is too small + */ +static int tls_read_binary(const uint8_t ** p, const uint8_t * end, uint8_t * bin, size_t len) +{ + uint8_t data_len; + + /* length byte plus the length of the crypto key */ + if ((end < *p) || ((size_t)(end - *p) < 1 + len)) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + /* read the length byte */ + data_len = (*p)[0]; + *p += 1; + /* check the length matches */ + if (data_len != len) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + memcpy(bin, *p, len); + + *p += len; + + return (0); +} + +/** + * \brief writes a tls point into a CryptoKey + * + * \param p pointer to output buffer, will be changed by a successful + * call + * \param end pointer to the end of the output buffer + * \param key the CryptoKey to write + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int tls_write_crypto_key(uint8_t ** p, const uint8_t * end, CryptoKey * key) +{ + return tls_write_binary(p, end, key->u.plaintext.keyMaterial, key->u.plaintext.keyLength); +} + +/** + * \brief read a tls point into a CryptoKey + * + * \param p pointer to input buffer, will be changed by a successful + * call + * \param end pointer to the end of the input buffer + * \param key the CryptoKey to fill + * + * \return 0 if successful, + * a negative error code otherwise + * + * \retval MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * the input buffer is too small + * \retval MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE + * the point is not in uncompressed form + */ +static int tls_read_crypto_key(const uint8_t ** p, const uint8_t * end, CryptoKey * key) +{ + /* check that the point is uncompressed */ + if ((end < *p) || (end - *p < 2)) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + if ((*p)[1] != 0x04) + { + return (MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE); + } + + return tls_read_binary(p, end, key->u.plaintext.keyMaterial, key->u.plaintext.keyLength); +} + +/** + * \brief write the curve info into the buffer + * + * \param p pointer to output buffer, will be changed by a successful + * call + * \param end pointer to the end of the output buffer + * \param group_id the mbedtls group id write + * + * \return 0 if successful, + * a negative error code otherwise + * + * \retval MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * the input buffer is too small + * \retval MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * the group id did not name a valid curve + */ +static int tls_write_curve_info(uint8_t ** p, const uint8_t * end, mbedtls_ecp_group_id group_id) +{ + const mbedtls_ecp_curve_info * curve_info; + + if ((end < *p) || (end - *p < 3)) + { + return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + } + + curve_info = mbedtls_ecp_curve_info_from_grp_id(group_id); + + if (NULL == curve_info) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + /* write that we use named curves */ + (*p)[0] = MBEDTLS_ECP_TLS_NAMED_CURVE; + (*p)[1] = curve_info->tls_id >> 8; + (*p)[2] = curve_info->tls_id & 0xFF; + *p += 3; + + return (0); +} + +/** + * \brief read and verify the curve info from the buffer + * + * \param p pointer to input buffer, will be changed by a successful + * call + * \param end pointer to the end of the input buffer + * \param group_id the mbedtls group id to load to check a match + * + * \return 0 if successful, + * a negative error code otherwise + * + * \retval MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * the input buffer is too small + * \retval MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE + * the tls curve identifiers do not match + * \retval MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * the curve info was not for a named curve or we do not have + * that named curve + */ +static int tls_verify_curve_info(const uint8_t ** p, const uint8_t * end, mbedtls_ecp_group_id group_id) +{ + uint16_t curve_name_id; + const mbedtls_ecp_curve_info * curve_info; + + if ((end < *p) || (end - *p < 3)) + { + return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + } + + if ((*p)[0] != MBEDTLS_ECP_TLS_NAMED_CURVE) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + curve_name_id = (((uint16_t)(*p)[1] << 8)) | (((uint16_t)(*p)[2])); + *p += 3; + + curve_info = mbedtls_ecp_curve_info_from_grp_id(group_id); + + if (NULL == curve_info) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + if (curve_name_id != curve_info->tls_id) + { + return (MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE); + } + + return (0); +} + +/** + * \brief Fill the a point with a random function + * + * \param private_key + * key to fill with random data + * \param f_rng random number function + * \param p_rng context for the random function + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int gen_private_key(unsigned char * private_key, int (*f_rng)(void *, unsigned char *, size_t), void * p_rng) +{ + unsigned int i; + unsigned int j = 0; + unsigned int sum = 0U; + + do + { + unsigned int * pkey = (unsigned int *) private_key; + f_rng(p_rng, private_key, NISTP256_CURVE_LENGTH_BYTES); + + /* check if private_key is equal to zero */ + for (i = 0; i < (NISTP256_CURVE_LENGTH_BYTES / sizeof(unsigned int)); i++) + { + sum |= pkey[i]; + } + j++; + } while (0U == sum && (j < 3)); + + return (0U != sum ? 0 : -1); +} + +/** + * \brief Generate the second round of keys for this node and peer + * + * \param ctx Context to use + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int ecjpake_alt_generate_round2_keys(mbedtls_ecjpake_context * ctx) +{ + ECJPAKE_OperationRoundTwoGenerateKeys roundTwoGenerateKeys; + int ret; + + if (ctx->roundTwoGenerated) + { + return (0); + } + + ECJPAKE_OperationRoundTwoGenerateKeys_init(&roundTwoGenerateKeys); + roundTwoGenerateKeys.curve = &ECCParams_NISTP256; + roundTwoGenerateKeys.myPrivateKey2 = &ctx->myPrivateCryptoKey2; + roundTwoGenerateKeys.myPublicKey1 = &ctx->myPublicCryptoKey1; + roundTwoGenerateKeys.myPublicKey2 = &ctx->myPublicCryptoKey2; + roundTwoGenerateKeys.theirPublicKey1 = &ctx->theirPublicCryptoKey1; + roundTwoGenerateKeys.theirPublicKey2 = &ctx->theirPublicCryptoKey2; + roundTwoGenerateKeys.preSharedSecret = &ctx->preSharedSecretCryptoKey; + roundTwoGenerateKeys.theirNewGenerator = &ctx->theirGeneratorKey; + roundTwoGenerateKeys.myNewGenerator = &ctx->myGeneratorKey; + roundTwoGenerateKeys.myCombinedPrivateKey = &ctx->myCombinedPrivateKey; + roundTwoGenerateKeys.myCombinedPublicKey = &ctx->myCombinedPublicKey; + roundTwoGenerateKeys.myPrivateV = &ctx->myPrivateCryptoV3; + roundTwoGenerateKeys.myPublicV = &ctx->myPublicCryptoV3; + + ECJPAKE_ALT_CHK(ECJPAKE_roundTwoGenerateKeys(ctx->handle, &roundTwoGenerateKeys)); + + ctx->roundTwoGenerated = true; + +cleanup: + return (ret); +} + +void mbedtls_ecjpake_init(mbedtls_ecjpake_context * ctx) +{ + ECJPAKE_Params params; + + if (ctx == NULL) + { + return; + } + + ctx->md_info = NULL; + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + + ECJPAKE_Params_init(¶ms); + + ctx->handle = ECJPAKE_open(0, ¶ms); +} + +void mbedtls_ecjpake_free(mbedtls_ecjpake_context * ctx) +{ + if (ctx == NULL) + { + return; + } + + ctx->md_info = NULL; + + ECJPAKE_close(ctx->handle); + ctx->handle = NULL; +} + +static void big_num_reverse(uint8_t * arr, size_t len) +{ + unsigned int left = 0; + unsigned int right = len - 1; + uint8_t temp; + + while (left < right) + { + temp = arr[left]; + arr[left] = arr[right]; + arr[right] = temp; + + ++left; + --right; + } +} + +/** + * \brief write a 4 byte length and binary output + * + * \param p pointer to output buffer, will be changed by a successful + * call + * \param end pointer to the end of the output buffer + * \param bin value to write + * \param len length to write + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int ecjpake_write_len_binary(uint8_t ** p, const uint8_t * end, const uint8_t * bin, size_t len) +{ + if ((end < *p) || ((size_t)(end - *p) < 4 + len)) + { + return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + } + + memcpy(*p + 4, bin, len); + + (*p)[0] = (unsigned char) ((len >> 24) & 0xFF); + (*p)[1] = (unsigned char) ((len >> 16) & 0xFF); + (*p)[2] = (unsigned char) ((len >> 8) & 0xFF); + (*p)[3] = (unsigned char) ((len) &0xFF); + + *p += 4 + len; + + return (0); +} + +/** + * \brief Create the EC-JPAKE hash for each round + * + * \param md_info message digest info to use + * \param G 1st point to digest + * \param V 2nd point to digest + * \param X 3rd point to digest + * \param id string id to digest + * \param hash output buffer for digest + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int ecjpake_hash(const mbedtls_md_info_t * md_info, CryptoKey * G, CryptoKey * V, CryptoKey * X, const char * id, + uint8_t * hash) +{ + int ret; + uint8_t buf[ECJPAKE_HASH_BUF_LEN]; + uint8_t * p = buf; + const uint8_t * end = buf + sizeof(buf); + const size_t id_len = strlen(id); + + /* + * Write 'lenG || G || lenV || V || lenX || X || lenID || ID' to the + * temporary buffer + */ + ECJPAKE_ALT_CHK(ecjpake_write_len_binary(&p, end, G->u.plaintext.keyMaterial, G->u.plaintext.keyLength)); + ECJPAKE_ALT_CHK(ecjpake_write_len_binary(&p, end, V->u.plaintext.keyMaterial, V->u.plaintext.keyLength)); + ECJPAKE_ALT_CHK(ecjpake_write_len_binary(&p, end, X->u.plaintext.keyMaterial, X->u.plaintext.keyLength)); + ECJPAKE_ALT_CHK(ecjpake_write_len_binary(&p, end, (uint8_t *) id, id_len)); + + /* + * Compute hash + * + * XXX: possible speedup by digesting the buffers directly instead of + * creating a temp buffer + */ + ECJPAKE_ALT_CHK(mbedtls_md(md_info, buf, p - buf, hash)); + +cleanup: + return (ret); +} + +/** + * \brief Read and validate the ZKP based on this public key. + * + * \param ctx Context to use + * \param generator_key + * Generator point to use + * \param public_key + * Public key use + * \param p Pointer to current place in buffer, will point to the next + * character after a successful call + * \param end Pointer to the end of the buffer + * + * \return 0 if successful, + * a negative error code otherwise + */ +static int ecjpake_zkp_read(mbedtls_ecjpake_context * ctx, CryptoKey * generator_key, CryptoKey * public_key, const uint8_t ** p, + const uint8_t * end) +{ + int ret; + CryptoKey v; + uint8_t v_material[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + uint8_t r[NISTP256_CURVE_LENGTH_BYTES]; + uint8_t hash[NISTP256_CURVE_LENGTH_BYTES]; + + ECJPAKE_OperationVerifyZKP operation_verify_zkp; + + CryptoKeyPlaintext_initKey(&v, v_material, sizeof(v_material)); + + /* read the Ephemeral public key V */ + ECJPAKE_ALT_CHK(tls_read_crypto_key(p, end, &v)); + + /* read the Schnorr signature r */ + ECJPAKE_ALT_CHK(tls_read_binary(p, end, r, sizeof(r))); + + /* calculate the hash */ + ECJPAKE_ALT_CHK(ecjpake_hash(ctx->md_info, generator_key, &v, public_key, ID_PEER, hash)); + + /* verify the r and hash based on V */ + ECJPAKE_OperationVerifyZKP_init(&operation_verify_zkp); + operation_verify_zkp.curve = &ECCParams_NISTP256; + operation_verify_zkp.theirGenerator = generator_key; + operation_verify_zkp.theirPublicKey = public_key; + operation_verify_zkp.theirPublicV = &v; + operation_verify_zkp.hash = hash; + operation_verify_zkp.r = r; + + ECJPAKE_ALT_CHK(ECJPAKE_verifyZKP(ctx->handle, &operation_verify_zkp)); + +cleanup: + return (ret); +} + +/** + * \brief Check if a CryptoKey is zero + * + * \param G CryptoKey to use + * + * \return 0 CryptoKey is not zero + * MBEDTLS_ERR_ECP_INVALID_KEY if CryptoKey is zero + */ +static int check_CryptoKey_is_zero(CryptoKey * G) +{ + unsigned int i; + /* skip beginning 0x04 byte */ + for (i = 1; i < G->u.plaintext.keyLength; i++) + { + if (G->u.plaintext.keyMaterial[i] != 0U) + { + /* the point is not all zero */ + return (0); + } + } + /* the for loop completed, they were all zero */ + return (MBEDTLS_ERR_ECP_INVALID_KEY); +} + +int mbedtls_ecjpake_setup(mbedtls_ecjpake_context * ctx, mbedtls_ecjpake_role role, mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, const uint8_t * secret, size_t len) +{ + int ret = 0; + + ctx->roundTwoGenerated = false; + ctx->role = role; + + if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL) + { + return (MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE); + } + + ctx->curve = curve; + + /* copy NISTP256 generator for hash functions */ + ctx->nistP256Generator[0] = 0x04; + memcpy(&(ctx->nistP256Generator[1]), ECCParams_NISTP256.generatorX, (NISTP256_CURVE_LENGTH_BYTES * 2)); + big_num_reverse(&(ctx->nistP256Generator[1]), NISTP256_CURVE_LENGTH_BYTES); + big_num_reverse(&(ctx->nistP256Generator[NISTP256_CURVE_LENGTH_BYTES + 1]), NISTP256_CURVE_LENGTH_BYTES); + CryptoKeyPlaintext_initKey(&ctx->nistP256GeneratorCryptoKey, ctx->nistP256Generator, sizeof(ctx->nistP256Generator)); + + /* Pre-shared secret */ + memcpy(ctx->preSharedSecretKeyingMaterial, secret, len); + + CryptoKeyPlaintext_initKey(&ctx->preSharedSecretCryptoKey, ctx->preSharedSecretKeyingMaterial, len); + + CryptoKeyPlaintext_initKey(&ctx->myPrivateCryptoKey1, ctx->myPrivateKeyMaterial1, sizeof(ctx->myPrivateKeyMaterial1)); + CryptoKeyPlaintext_initKey(&ctx->myPrivateCryptoKey2, ctx->myPrivateKeyMaterial2, sizeof(ctx->myPrivateKeyMaterial2)); + CryptoKeyPlaintext_initKey(&ctx->myPrivateCryptoV1, ctx->myPrivateVMaterial1, sizeof(ctx->myPrivateVMaterial1)); + CryptoKeyPlaintext_initKey(&ctx->myPrivateCryptoV2, ctx->myPrivateVMaterial2, sizeof(ctx->myPrivateVMaterial2)); + CryptoKeyPlaintext_initKey(&ctx->myPrivateCryptoV3, ctx->myPrivateVMaterial3, sizeof(ctx->myPrivateVMaterial3)); + + CryptoKeyPlaintext_initBlankKey(&ctx->myPublicCryptoKey1, ctx->myPublicKeyMaterial1, sizeof(ctx->myPublicKeyMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->myPublicCryptoKey2, ctx->myPublicKeyMaterial2, sizeof(ctx->myPublicKeyMaterial2)); + CryptoKeyPlaintext_initBlankKey(&ctx->myPublicCryptoV1, ctx->myPublicVMaterial1, sizeof(ctx->myPublicVMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->myPublicCryptoV2, ctx->myPublicVMaterial2, sizeof(ctx->myPublicVMaterial2)); + CryptoKeyPlaintext_initBlankKey(&ctx->myPublicCryptoV3, ctx->myPublicVMaterial3, sizeof(ctx->myPublicVMaterial3)); + CryptoKeyPlaintext_initBlankKey(&ctx->myCombinedPrivateKey, ctx->myCombinedPrivateKeyMaterial1, + sizeof(ctx->myCombinedPrivateKeyMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->myCombinedPublicKey, ctx->myCombinedPublicKeyMaterial1, + sizeof(ctx->myCombinedPublicKeyMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->myGeneratorKey, ctx->myGenerator, sizeof(ctx->myGenerator)); + + CryptoKeyPlaintext_initBlankKey(&ctx->theirPublicCryptoKey1, ctx->theirPublicKeyMaterial1, + sizeof(ctx->theirPublicKeyMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->theirPublicCryptoKey2, ctx->theirPublicKeyMaterial2, + sizeof(ctx->theirPublicKeyMaterial2)); + CryptoKeyPlaintext_initBlankKey(&ctx->theirCombinedPublicKey, ctx->theirCombinedPublicKeyMaterial1, + sizeof(ctx->theirCombinedPublicKeyMaterial1)); + CryptoKeyPlaintext_initBlankKey(&ctx->theirGeneratorKey, ctx->theirGenerator, sizeof(ctx->theirGenerator)); + + return (ret); +} + +int mbedtls_ecjpake_check(const mbedtls_ecjpake_context * ctx) +{ + if (ctx->md_info == NULL || ctx->curve == MBEDTLS_ECP_DP_NONE || ctx->handle == NULL) + { + return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + return (0); +} + +int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context * ctx, const unsigned char * buf, size_t len) +{ + int ret; + const unsigned char * p = buf; + const unsigned char * end = buf + len; + + /* read their combined key material (Xc or Xs) */ + ECJPAKE_ALT_CHK(tls_read_crypto_key(&p, end, &ctx->theirPublicCryptoKey1)); + + /* verify that the point is not zero */ + ECJPAKE_ALT_CHK(check_CryptoKey_is_zero(&ctx->theirPublicCryptoKey1)); + + /* verify the proof (ZKP(Xc) or ZKP(Xs)) */ + ECJPAKE_ALT_CHK(ecjpake_zkp_read(ctx, &ctx->nistP256GeneratorCryptoKey, &ctx->theirPublicCryptoKey1, &p, end)); + + /* read their combined key material (Xc or Xs) */ + ECJPAKE_ALT_CHK(tls_read_crypto_key(&p, end, &ctx->theirPublicCryptoKey2)); + + /* verify that the point is not zero */ + ECJPAKE_ALT_CHK(check_CryptoKey_is_zero(&ctx->theirPublicCryptoKey2)); + + /* verify the proof (ZKP(Xc) or ZKP(Xs)) */ + ECJPAKE_ALT_CHK(ecjpake_zkp_read(ctx, &ctx->nistP256GeneratorCryptoKey, &ctx->theirPublicCryptoKey2, &p, end)); + +cleanup: + return (ret); +} + +int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context * ctx, uint8_t * buf, size_t len, size_t * olen, + int (*f_rng)(void *, unsigned char *, size_t), void * p_rng) +{ + int ret; + uint8_t * p = buf; + const uint8_t * end = buf + len; + uint8_t hash[NISTP256_CURVE_LENGTH_BYTES]; + uint8_t r[NISTP256_CURVE_LENGTH_BYTES]; + + /* Generate round one keys */ + ECJPAKE_OperationRoundOneGenerateKeys roundOneGenerateKeys; + ECJPAKE_OperationGenerateZKP operationGenerateZKP; + + /* Generate private keys */ + ECJPAKE_ALT_CHK(gen_private_key(ctx->myPrivateKeyMaterial1, f_rng, p_rng)); + ECJPAKE_ALT_CHK(gen_private_key(ctx->myPrivateKeyMaterial2, f_rng, p_rng)); + ECJPAKE_ALT_CHK(gen_private_key(ctx->myPrivateVMaterial1, f_rng, p_rng)); + ECJPAKE_ALT_CHK(gen_private_key(ctx->myPrivateVMaterial2, f_rng, p_rng)); + ECJPAKE_ALT_CHK(gen_private_key(ctx->myPrivateVMaterial3, f_rng, p_rng)); + + ECJPAKE_OperationRoundOneGenerateKeys_init(&roundOneGenerateKeys); + roundOneGenerateKeys.curve = &ECCParams_NISTP256; + roundOneGenerateKeys.myPrivateKey1 = &ctx->myPrivateCryptoKey1; + roundOneGenerateKeys.myPrivateKey2 = &ctx->myPrivateCryptoKey2; + roundOneGenerateKeys.myPublicKey1 = &ctx->myPublicCryptoKey1; + roundOneGenerateKeys.myPublicKey2 = &ctx->myPublicCryptoKey2; + roundOneGenerateKeys.myPrivateV1 = &ctx->myPrivateCryptoV1; + roundOneGenerateKeys.myPrivateV2 = &ctx->myPrivateCryptoV2; + roundOneGenerateKeys.myPublicV1 = &ctx->myPublicCryptoV1; + roundOneGenerateKeys.myPublicV2 = &ctx->myPublicCryptoV2; + + ECJPAKE_ALT_CHK(ECJPAKE_roundOneGenerateKeys(ctx->handle, &roundOneGenerateKeys)); + + /* write X1 */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myPublicCryptoKey1)); + + ECJPAKE_ALT_CHK(ecjpake_hash(ctx->md_info, &ctx->nistP256GeneratorCryptoKey, &ctx->myPublicCryptoV1, &ctx->myPublicCryptoKey1, + ID_MINE, hash)); + + /* generate round one ZKPs */ + ECJPAKE_OperationGenerateZKP_init(&operationGenerateZKP); + operationGenerateZKP.curve = &ECCParams_NISTP256; + operationGenerateZKP.myPrivateKey = &ctx->myPrivateCryptoKey1; + operationGenerateZKP.myPrivateV = &ctx->myPrivateCryptoV1; + operationGenerateZKP.hash = hash; + operationGenerateZKP.r = r; + + ECJPAKE_ALT_CHK(ECJPAKE_generateZKP(ctx->handle, &operationGenerateZKP)); + + /* write ZKP for X1 (V1 and r1) */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myPublicCryptoV1)); + + /* write r */ + ECJPAKE_ALT_CHK(tls_write_binary(&p, end, r, NISTP256_CURVE_LENGTH_BYTES)); + + ECJPAKE_ALT_CHK(ecjpake_hash(ctx->md_info, &ctx->nistP256GeneratorCryptoKey, &ctx->myPublicCryptoV2, &ctx->myPublicCryptoKey2, + ID_MINE, hash)); + + ECJPAKE_OperationGenerateZKP_init(&operationGenerateZKP); + operationGenerateZKP.curve = &ECCParams_NISTP256; + operationGenerateZKP.myPrivateKey = &ctx->myPrivateCryptoKey2; + operationGenerateZKP.myPrivateV = &ctx->myPrivateCryptoV2; + operationGenerateZKP.hash = hash; + operationGenerateZKP.r = r; + + ECJPAKE_ALT_CHK(ECJPAKE_generateZKP(ctx->handle, &operationGenerateZKP)); + + /* write X2 */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myPublicCryptoKey2)); + + /* write ZKP for X2 */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myPublicCryptoV2)); + + /* write r */ + ECJPAKE_ALT_CHK(tls_write_binary(&p, end, r, NISTP256_CURVE_LENGTH_BYTES)); + + *olen = p - buf; + +cleanup: + return (ret); +} + +int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context * ctx, const unsigned char * buf, size_t len) +{ + int ret; + const uint8_t * p = buf; + const uint8_t * end = buf + len; + + ECJPAKE_ALT_CHK(ecjpake_alt_generate_round2_keys(ctx)); + + if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) + { + ECJPAKE_ALT_CHK(tls_verify_curve_info(&p, end, ctx->curve)); + } + + /* read their combined key material (Xc or Xs) */ + ECJPAKE_ALT_CHK(tls_read_crypto_key(&p, end, &ctx->theirCombinedPublicKey)); + + /* verify that the point is not zero */ + ECJPAKE_ALT_CHK(check_CryptoKey_is_zero(&ctx->theirCombinedPublicKey)); + + /* verify the proof (ZKP(Xc) or ZKP(Xs)) */ + ECJPAKE_ALT_CHK(ecjpake_zkp_read(ctx, &ctx->theirGeneratorKey, &ctx->theirCombinedPublicKey, &p, end)); + +cleanup: + return (ret); +} + +int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context * ctx, unsigned char * buf, size_t len, size_t * olen, + int (*f_rng)(void *, unsigned char *, size_t), void * p_rng) +{ + int ret; + uint8_t hash[NISTP256_CURVE_LENGTH_BYTES]; + uint8_t r[NISTP256_CURVE_LENGTH_BYTES]; + uint8_t * p = buf; + const uint8_t * end = buf + len; + + ECJPAKE_OperationGenerateZKP operationGenerateZKP; + + ECJPAKE_ALT_CHK(ecjpake_alt_generate_round2_keys(ctx)); + + ECJPAKE_ALT_CHK( + ecjpake_hash(ctx->md_info, &ctx->myGeneratorKey, &ctx->myPublicCryptoV3, &ctx->myCombinedPublicKey, ID_MINE, hash)); + + ECJPAKE_OperationGenerateZKP_init(&operationGenerateZKP); + operationGenerateZKP.curve = &ECCParams_NISTP256; + operationGenerateZKP.myPrivateKey = &ctx->myCombinedPrivateKey; + operationGenerateZKP.myPrivateV = &ctx->myPrivateCryptoV3; + operationGenerateZKP.hash = hash; + operationGenerateZKP.r = r; + + ECJPAKE_ALT_CHK(ECJPAKE_generateZKP(ctx->handle, &operationGenerateZKP)); + + if (ctx->role == MBEDTLS_ECJPAKE_SERVER) + { + /* write curve info */ + ECJPAKE_ALT_CHK(tls_write_curve_info(&p, end, ctx->curve)); + } + + /* write public key X */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myCombinedPublicKey)); + + /* write ZKP for X (V and r) */ + ECJPAKE_ALT_CHK(tls_write_crypto_key(&p, end, &ctx->myPublicCryptoV3)); + + /* write r */ + ECJPAKE_ALT_CHK(tls_write_binary(&p, end, r, NISTP256_CURVE_LENGTH_BYTES)); + + *olen = p - buf; + +cleanup: + return (ret); +} + +int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context * ctx, unsigned char * buf, size_t len, size_t * olen, + int (*f_rng)(void *, unsigned char *, size_t), void * p_rng) +{ + int ret; + unsigned char md_len; + CryptoKey sharedSecretCryptoKey; + uint8_t sharedSecretKeyingMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + + ECJPAKE_OperationComputeSharedSecret computeSharedSecret; + + md_len = mbedtls_md_get_size(ctx->md_info); + if (len < md_len) + { + return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); + } + + CryptoKeyPlaintext_initKey(&sharedSecretCryptoKey, sharedSecretKeyingMaterial1, sizeof(sharedSecretKeyingMaterial1)); + + /* Generate shared secret */ + ECJPAKE_OperationComputeSharedSecret_init(&computeSharedSecret); + computeSharedSecret.curve = &ECCParams_NISTP256; + computeSharedSecret.myCombinedPrivateKey = &ctx->myCombinedPrivateKey; + computeSharedSecret.theirCombinedPublicKey = &ctx->theirCombinedPublicKey; + computeSharedSecret.theirPublicKey2 = &ctx->theirPublicCryptoKey2; + computeSharedSecret.myPrivateKey2 = &ctx->myPrivateCryptoKey2; + computeSharedSecret.sharedSecret = &sharedSecretCryptoKey; + + ECJPAKE_ALT_CHK(ECJPAKE_computeSharedSecret(ctx->handle, &computeSharedSecret)); + + ECJPAKE_ALT_CHK(mbedtls_md(ctx->md_info, sharedSecretKeyingMaterial1 + 1, NISTP256_CURVE_LENGTH_BYTES, buf)); + + *olen = md_len; + +cleanup: + return (ret); +} + +#undef ID_MINE +#undef ID_PEER + +#endif /* MBEDTLS_ECJPAKE_ALT */ diff --git a/src/platform/cc13x2_26x2/crypto/ecjpake_alt.h b/src/platform/cc13x2_26x2/crypto/ecjpake_alt.h new file mode 100644 index 00000000000000..1ce4d008c487f4 --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/ecjpake_alt.h @@ -0,0 +1,120 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls-config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECJPAKE_ALT) + +#include "mbedtls/ecp.h" +#include "mbedtls/md.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Length of parameters for the NIST p256r1. + * + * ECJ-PAKE is only defined for p256r1 + */ +#define NISTP256_CURVE_LENGTH_BYTES (32) + +/** + * Size in bytes of the identifier at the beginning of the point format + */ +#define OCTET_STRING_OFFSET 1 + +/** + * Size in bytes of a point expressed in the TLS point format + * + * id_byte || X coord || Y coord + */ +#define NISTP256_PUBLIC_KEY_LENGTH_BYTES (OCTET_STRING_OFFSET + (NISTP256_CURVE_LENGTH_BYTES * 2)) + +/** + * EC J-PAKE context structure. + */ +typedef struct +{ + const mbedtls_md_info_t * md_info; + mbedtls_ecp_group_id curve; + mbedtls_ecjpake_role role; + int point_format; + + bool roundTwoGenerated; + /* + * XXX: possible size reduction by moving ephemeral material to round + * calculations. + */ + unsigned char myPrivateKeyMaterial1[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char myPrivateKeyMaterial2[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char myPrivateVMaterial1[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char myPrivateVMaterial2[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char myPrivateVMaterial3[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char myPublicKeyMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myPublicKeyMaterial2[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myPublicVMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myPublicVMaterial2[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myPublicVMaterial3[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myCombinedPublicKeyMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myCombinedPrivateKeyMaterial1[NISTP256_CURVE_LENGTH_BYTES]; + unsigned char nistP256Generator[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char myGenerator[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char theirPublicKeyMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char theirPublicKeyMaterial2[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char theirCombinedPublicKeyMaterial1[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char theirGenerator[NISTP256_PUBLIC_KEY_LENGTH_BYTES]; + unsigned char preSharedSecretKeyingMaterial[NISTP256_CURVE_LENGTH_BYTES]; + + CryptoKey nistP256GeneratorCryptoKey; + CryptoKey preSharedSecretCryptoKey; + CryptoKey myPrivateCryptoKey1; + CryptoKey myPrivateCryptoKey2; + CryptoKey myPrivateCryptoV1; + CryptoKey myPrivateCryptoV2; + CryptoKey myPrivateCryptoV3; + CryptoKey myCombinedPrivateKey; + CryptoKey myPublicCryptoKey1; + CryptoKey myPublicCryptoKey2; + CryptoKey myPublicCryptoV1; + CryptoKey myPublicCryptoV2; + CryptoKey myPublicCryptoV3; + CryptoKey myCombinedPublicKey; + CryptoKey myGeneratorKey; + CryptoKey theirPublicCryptoKey1; + CryptoKey theirPublicCryptoKey2; + CryptoKey theirCombinedPublicKey; + CryptoKey theirGeneratorKey; + + ECJPAKE_Handle handle; +} mbedtls_ecjpake_context; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_ECJPAKE_ALT */ diff --git a/src/platform/cc13x2_26x2/crypto/sha256_alt.c b/src/platform/cc13x2_26x2/crypto/sha256_alt.c new file mode 100644 index 00000000000000..8dabab6f88dff3 --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/sha256_alt.c @@ -0,0 +1,191 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_SHA256_ALT) + +#include + +#include +#include + +/*! + * Hardware-specific configuration attributes, may be replaced with SysConfig + * ti_drivers.h structure. + */ +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs_sha = { + .intPriority = ~0, +}; + +void mbedtls_sha256_init(mbedtls_sha256_context * ctx) +{ + SHA2_Params sha2Params; + + memset(ctx, 0, sizeof(mbedtls_sha256_context)); + SHA2_Params_init(&sha2Params); + + sha2Params.returnBehavior = SHA2_RETURN_BEHAVIOR_POLLING; + + ctx->config.object = &ctx->object; + ctx->config.hwAttrs = &sha2CC26X2HWAttrs_sha; + + ctx->hndl = SHA2_construct(&ctx->config, &sha2Params); +} + +void mbedtls_sha256_free(mbedtls_sha256_context * ctx) +{ + if (NULL == ctx) + { + return; + } + + if (ctx->hndl != NULL) + { + SHA2_close(ctx->hndl); + + memset(ctx, 0, sizeof(mbedtls_sha256_context)); + } +} + +/* + * Deviation from documentation in sha256.h. + * + * It has been noticed that some code using mbedtls does not call `init` before + * starting a SHA operation. Rather these implementations assume the `ctx` + * structure may be zero'ed out as initialization. To support this usage the + * driver instance is assumed to be uninitialized if the context's `hndl` is a + * NULL pointer. Start will initialize the driver and assign the handle to the + * context in this case. + */ +int mbedtls_sha256_starts_ret(mbedtls_sha256_context * ctx, int is224) +{ + SHA2_HashType type; + + // open the driver here because no-one called init + if (ctx->hndl == NULL) + { + SHA2_Params sha2Params; + + SHA2_Params_init(&sha2Params); + + sha2Params.returnBehavior = SHA2_RETURN_BEHAVIOR_POLLING; + + ctx->config.object = &ctx->object; + ctx->config.hwAttrs = &sha2CC26X2HWAttrs_sha; + + ctx->hndl = SHA2_construct(&ctx->config, &sha2Params); + + if (NULL == ctx->hndl) + { + return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED; + } + } + else + { + SHA2_reset(ctx->hndl); + } + + if (is224) + { + type = SHA2_HASH_TYPE_224; + } + else + { + type = SHA2_HASH_TYPE_256; + } + + SHA2_setHashType(ctx->hndl, type); + + return 0; +} + +/** + * Deviation from documentation in sha256.h. + * + * It has been noticed that some code using mbedtls does not call `init` on the + * contexts being passed into this function. This seems to be done to avoid + * allocating hardware to cloned context instances. To support this use-case, + * only internal buffers to the SHA2 structure are copied without checking the + * driver handles. + */ +void mbedtls_sha256_clone(mbedtls_sha256_context * dst, const mbedtls_sha256_context * src) +{ + dst->object.hashType = src->object.hashType; + dst->object.bytesInBuffer = src->object.bytesInBuffer; + dst->object.bytesProcessed = src->object.bytesProcessed; + memcpy(dst->object.buffer, src->object.buffer, sizeof(dst->object.buffer)); +} + +int mbedtls_sha256_finish_ret(mbedtls_sha256_context * ctx, unsigned char output[32]) +{ + int_fast16_t result; + + result = SHA2_finalize(ctx->hndl, output); + + if (SHA2_STATUS_SUCCESS != result) + { + return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED; + } + else + { + return 0; + } +} + +int mbedtls_sha256_update_ret(mbedtls_sha256_context * ctx, const unsigned char * input, size_t ilen) +{ + int_fast16_t result; + + // Process data in chunks. The driver buffers incomplete blocks internally. + result = SHA2_addData(ctx->hndl, input, ilen); + + if (SHA2_STATUS_SUCCESS != result) + { + return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED; + } + else + { + return 0; + } +} + +int mbedtls_internal_sha256_process(mbedtls_sha256_context * ctx, const unsigned char data[64]) +{ + int_fast16_t result; + + // Process data in chunks. The driver buffers incomplete blocks internally. + result = SHA2_addData(ctx->hndl, data, SHA2_BLOCK_SIZE_BYTES_256); + + if (SHA2_STATUS_SUCCESS != result) + { + return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED; + } + else + { + return 0; + } +} + +#endif /* MBEDTLS_SHA256_ALT */ diff --git a/src/platform/cc13x2_26x2/crypto/sha256_alt.h b/src/platform/cc13x2_26x2/crypto/sha256_alt.h new file mode 100644 index 00000000000000..96505775cd1119 --- /dev/null +++ b/src/platform/cc13x2_26x2/crypto/sha256_alt.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls-config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_ALT) +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct +{ + SHA2_Handle hndl; /*!< A handle that is returned by the SHA driver */ + SHA2_Config config; /*!< structure containing SHA2 driver specific implementation */ + SHA2CC26X2_Object object; /*!< Pointer to a driver specific data object */ +} mbedtls_sha256_context; + +#ifdef __cplusplus +} +#endif +#endif /* MBEDTLS_SHA256_ALT */ diff --git a/third_party/ti_simplelink_sdk/BUILD.gn b/third_party/ti_simplelink_sdk/BUILD.gn index 09ca83c00ef2cb..73e9b3e965603e 100644 --- a/third_party/ti_simplelink_sdk/BUILD.gn +++ b/third_party/ti_simplelink_sdk/BUILD.gn @@ -39,19 +39,22 @@ config("ti_simplelink_mbedtls_config") { include_dirs = [ "${chip_root}/src/platform/cc13x2_26x2", + "${chip_root}/src/platform/cc13x2_26x2/crypto", "${ti_simplelink_sdk_root}/source", - "${ti_simplelink_sdk_root}/source/ti/thread/cc13x2_26x2/libmbedcrypto/config", ] } mbedtls_target("mbedtls") { + # Hardware acceleration sources = [ - # XXX: fill in hardware accelerated versions, how to link sysconfig dependent code? + "${chip_root}/src/platform/cc13x2_26x2/crypto/aes_alt.c", + "${chip_root}/src/platform/cc13x2_26x2/crypto/ecjpake_alt.c", + "${chip_root}/src/platform/cc13x2_26x2/crypto/sha256_alt.c", ] public_configs = [ ":ti_simplelink_mbedtls_config" ] - public_deps = [] + public_deps = [ ti_simplelink_sysconfig_target ] } config("ti_simplelink_freertos_config") { diff --git a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni index 282e1bdacf9f79..aebec3c96940f2 100644 --- a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni +++ b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni @@ -272,9 +272,6 @@ template("ti_simplelink_sdk") { sources = [ "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/alarm.c", "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/alarm_micro.c", - "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/crypto/aes_alt.c", - "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/crypto/ecjpake_alt.c", - "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/crypto/sha256_alt.c", "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/diag.c", "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/entropy.c", "${ti_simplelink_sdk_root}/examples/rtos/${ti_simplelink_board}/thread/${openthread_example}/platform/misc.c",