/* * * 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 */