diff --git a/components/mbedtls/test/test_mbedtls_mpi.c b/components/mbedtls/test/test_mbedtls_mpi.c index 515f9d305..ade0fdb6b 100644 --- a/components/mbedtls/test/test_mbedtls_mpi.c +++ b/components/mbedtls/test/test_mbedtls_mpi.c @@ -140,6 +140,11 @@ static void test_bignum_modexp(const char *z_str, const char *x_str, const char mbedtls_mpi_write_string(&Z, 16, z_buf, sizeof(z_buf)-1, &z_buf_len); TEST_ASSERT_EQUAL_STRING_MESSAGE(z_str, z_buf, "mbedtls_mpi_exp_mod incorrect"); + + mbedtls_mpi_free(&Z); + mbedtls_mpi_free(&X); + mbedtls_mpi_free(&Y); + mbedtls_mpi_free(&M); } TEST_CASE("test MPI modexp", "[bignum]") diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 8564f1ba0..c8be031a7 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -6,6 +6,7 @@ set(COMPONENT_SRCS "port/os_xtensa.c" "src/crypto/aes-unwrap.c" "src/crypto/aes-wrap.c" "src/crypto/bignum.c" + "src/crypto/crypto_mbedtls.c" "src/crypto/crypto_internal-cipher.c" "src/crypto/crypto_internal-modexp.c" "src/crypto/crypto_internal-rsa.c" @@ -94,4 +95,5 @@ component_compile_definitions( USE_WPS_TASK ESPRESSIF_USE ESP32_WORKAROUND + CONFIG_ECC ) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index ae73ccf12..f4a57ef7e 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -1,4 +1,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include COMPONENT_SRCDIRS := src/crypto port src/fast_crypto src/wpa2/eap_peer src/wpa2/tls src/wpa2/utils src/wps -CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing +CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -DCONFIG_ECC -Wno-strict-aliasing diff --git a/components/wpa_supplicant/include/crypto/crypto.h b/components/wpa_supplicant/include/crypto/crypto.h index bccb6fed7..f6b7b2f2c 100644 --- a/components/wpa_supplicant/include/crypto/crypto.h +++ b/components/wpa_supplicant/include/crypto/crypto.h @@ -606,4 +606,363 @@ int __must_check fast_crypto_mod_exp(const uint8_t *base, size_t base_len, int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len); + +/** + * crypto_get_random - Generate cryptographically strong pseudy-random bytes + * @buf: Buffer for data + * @len: Number of bytes to generate + * Returns: 0 on success, -1 on failure + * + * If the PRNG does not have enough entropy to ensure unpredictable byte + * sequence, this functions must return -1. + */ +int crypto_get_random(void *buf, size_t len); + + +/** + * struct crypto_bignum - bignum + * + * Internal data structure for bignum implementation. The contents is specific + * to the used crypto library. + */ +struct crypto_bignum; + +/** + * crypto_bignum_init - Allocate memory for bignum + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct crypto_bignum * crypto_bignum_init(void); + +/** + * crypto_bignum_init_set - Allocate memory for bignum and set the value + * @buf: Buffer with unsigned binary value + * @len: Length of buf in octets + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len); + +/** + * crypto_bignum_deinit - Free bignum + * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set() + * @clear: Whether to clear the value from memory + */ +void crypto_bignum_deinit(struct crypto_bignum *n, int clear); + +/** + * crypto_bignum_to_bin - Set binary buffer to unsigned bignum + * @a: Bignum + * @buf: Buffer for the binary number + * @len: Length of @buf in octets + * @padlen: Length in octets to pad the result to or 0 to indicate no padding + * Returns: Number of octets written on success, -1 on failure + */ +int crypto_bignum_to_bin(const struct crypto_bignum *a, + u8 *buf, size_t buflen, size_t padlen); + +/** + * crypto_bignum_add - c = a + b + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_add(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); + +/** + * crypto_bignum_mod - c = a % b + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result of a % b + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_mod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); + +/** + * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c) + * @a: Bignum; base + * @b: Bignum; exponent + * @c: Bignum; modulus + * @d: Bignum; used to store the result of a^b (mod c) + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_exptmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + const struct crypto_bignum *c, + struct crypto_bignum *d); + +/** + * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b) + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_inverse(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); + +/** + * crypto_bignum_sub - c = a - b + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result of a - b + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_sub(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); + +/** + * crypto_bignum_div - c = a / b + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result of a / b + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_div(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); + +/** + * crypto_bignum_mulmod - d = a * b (mod c) + * @a: Bignum + * @b: Bignum + * @c: Bignum + * @d: Bignum; used to store the result of (a * b) % c + * Returns: 0 on success, -1 on failure + */ +int crypto_bignum_mulmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + const struct crypto_bignum *c, + struct crypto_bignum *d); + +/** + * crypto_bignum_cmp - Compare two bignums + * @a: Bignum + * @b: Bignum + * Returns: -1 if a < b, 0 if a == b, or 1 if a > b + */ +int crypto_bignum_cmp(const struct crypto_bignum *a, + const struct crypto_bignum *b); + +/** + * crypto_bignum_bits - Get size of a bignum in bits + * @a: Bignum + * Returns: Number of bits in the bignum + */ +int crypto_bignum_bits(const struct crypto_bignum *a); + +/** + * crypto_bignum_is_zero - Is the given bignum zero + * @a: Bignum + * Returns: 1 if @a is zero or 0 if not + */ +int crypto_bignum_is_zero(const struct crypto_bignum *a); + +/** + * crypto_bignum_is_one - Is the given bignum one + * @a: Bignum + * Returns: 1 if @a is one or 0 if not + */ +int crypto_bignum_is_one(const struct crypto_bignum *a); + +/** + * crypto_bignum_legendre - Compute the Legendre symbol (a/p) + * @a: Bignum + * @p: Bignum + * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure + */ +int crypto_bignum_legendre(const struct crypto_bignum *a, + const struct crypto_bignum *p); + + +/** + * struct crypto_ec - Elliptic curve context + * + * Internal data structure for EC implementation. The contents is specific + * to the used crypto library. + */ +struct crypto_ec; + +/** + * crypto_ec_init - Initialize elliptic curve context + * @group: Identifying number for the ECC group (IANA "Group Description" + * attribute registrty for RFC 2409) + * Returns: Pointer to EC context or %NULL on failure + */ +struct crypto_ec * crypto_ec_init(int group); + +/** + * crypto_ec_deinit - Deinitialize elliptic curve context + * @e: EC context from crypto_ec_init() + */ +void crypto_ec_deinit(struct crypto_ec *e); + +/** + * crypto_ec_prime_len - Get length of the prime in octets + * @e: EC context from crypto_ec_init() + * Returns: Length of the prime defining the group + */ +size_t crypto_ec_prime_len(struct crypto_ec *e); + +/** + * crypto_ec_prime_len_bits - Get length of the prime in bits + * @e: EC context from crypto_ec_init() + * Returns: Length of the prime defining the group in bits + */ +size_t crypto_ec_prime_len_bits(struct crypto_ec *e); + +/** + * crypto_ec_get_prime - Get prime defining an EC group + * @e: EC context from crypto_ec_init() + * Returns: Prime (bignum) defining the group + */ +const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e); + +/** + * crypto_ec_get_order - Get order of an EC group + * @e: EC context from crypto_ec_init() + * Returns: Order (bignum) of the group + */ +const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e); + +/** + * struct crypto_ec_point - Elliptic curve point + * + * Internal data structure for EC implementation to represent a point. The + * contents is specific to the used crypto library. + */ +struct crypto_ec_point; + +/** + * crypto_ec_point_init - Initialize data for an EC point + * @e: EC context from crypto_ec_init() + * Returns: Pointer to EC point data or %NULL on failure + */ +struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e); + +/** + * crypto_ec_point_deinit - Deinitialize EC point data + * @p: EC point data from crypto_ec_point_init() + * @clear: Whether to clear the EC point value from memory + */ +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear); + +/** + * crypto_ec_point_to_bin - Write EC point value as binary data + * @e: EC context from crypto_ec_init() + * @p: EC point data from crypto_ec_point_init() + * @x: Buffer for writing the binary data for x coordinate or %NULL if not used + * @y: Buffer for writing the binary data for y coordinate or %NULL if not used + * Returns: 0 on success, -1 on failure + * + * This function can be used to write an EC point as binary data in a format + * that has the x and y coordinates in big endian byte order fields padded to + * the length of the prime defining the group. + */ +int crypto_ec_point_to_bin(struct crypto_ec *e, + const struct crypto_ec_point *point, u8 *x, u8 *y); + +/** + * crypto_ec_point_from_bin - Create EC point from binary data + * @e: EC context from crypto_ec_init() + * @val: Binary data to read the EC point from + * Returns: Pointer to EC point data or %NULL on failure + * + * This function readers x and y coordinates of the EC point from the provided + * buffer assuming the values are in big endian byte order with fields padded to + * the length of the prime defining the group. + */ +struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, + const u8 *val); + +/** + * crypto_bignum_add - c = a + b + * @e: EC context from crypto_ec_init() + * @a: Bignum + * @b: Bignum + * @c: Bignum; used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, + const struct crypto_ec_point *b, + struct crypto_ec_point *c); + +/** + * crypto_bignum_mul - res = b * p + * @e: EC context from crypto_ec_init() + * @p: EC point + * @b: Bignum + * @res: EC point; used to store the result of b * p + * Returns: 0 on success, -1 on failure + */ +int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, + const struct crypto_bignum *b, + struct crypto_ec_point *res); + +/** + * crypto_ec_point_invert - Compute inverse of an EC point + * @e: EC context from crypto_ec_init() + * @p: EC point to invert (and result of the operation) + * Returns: 0 on success, -1 on failure + */ +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p); + +/** + * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate + * @e: EC context from crypto_ec_init() + * @p: EC point to use for the returning the result + * @x: x coordinate + * @y_bit: y-bit (0 or 1) for selecting the y value to use + * Returns: 0 on success, -1 on failure + */ +int crypto_ec_point_solve_y_coord(struct crypto_ec *e, + struct crypto_ec_point *p, + const struct crypto_bignum *x, int y_bit); + +/** + * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b + * @e: EC context from crypto_ec_init() + * @x: x coordinate + * Returns: y^2 on success, %NULL failure + */ +struct crypto_bignum * +crypto_ec_point_compute_y_sqr(struct crypto_ec *e, + const struct crypto_bignum *x); + +/** + * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element + * @e: EC context from crypto_ec_init() + * @p: EC point + * Returns: 1 if the specified EC point is the neutral element of the group or + * 0 if not + */ +int crypto_ec_point_is_at_infinity(struct crypto_ec *e, + const struct crypto_ec_point *p); + +/** + * crypto_ec_point_is_on_curve - Check whether EC point is on curve + * @e: EC context from crypto_ec_init() + * @p: EC point + * Returns: 1 if the specified EC point is on the curve or 0 if not + */ +int crypto_ec_point_is_on_curve(struct crypto_ec *e, + const struct crypto_ec_point *p); + +/** + * crypto_ec_point_cmp - Compare two EC points + * @e: EC context from crypto_ec_init() + * @a: EC point + * @b: EC point + * Returns: 0 on equal, non-zero otherwise + */ +int crypto_ec_point_cmp(const struct crypto_ec *e, + const struct crypto_ec_point *a, + const struct crypto_ec_point *b); + + #endif /* CRYPTO_H */ diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c new file mode 100644 index 000000000..835af1d37 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -0,0 +1,603 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "crypto/includes.h" +#include "crypto/common.h" +#include "crypto/crypto.h" + +#include "mbedtls/ecp.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#ifdef ESP_PLATFORM +#include "esp_system.h" +#include "mbedtls/bignum.h" +#endif + + +#define IANA_SECP256R1 19 + +#ifdef ESP_PLATFORM +int crypto_get_random(void *buf, size_t len) +{ + if (!buf) { + return -1; + } + esp_fill_random(buf, len); + return 0; +} +#endif + +struct crypto_bignum *crypto_bignum_init(void) +{ + mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); + if (bn == NULL) { + return NULL; + } + + mbedtls_mpi_init(bn); + + return (struct crypto_bignum *)bn; +} + + +struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len) +{ + int ret = 0; + mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); + if (bn == NULL) { + return NULL; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len)); + return (struct crypto_bignum *) bn; + +cleanup: + os_free(bn); + return NULL; +} + + +void crypto_bignum_deinit(struct crypto_bignum *n, int clear) +{ + mbedtls_mpi_free((mbedtls_mpi *)n); + os_free((mbedtls_mpi *)n); +} + + +int crypto_bignum_to_bin(const struct crypto_bignum *a, + u8 *buf, size_t buflen, size_t padlen) +{ + int num_bytes, offset; + + if (padlen > buflen) { + return -1; + } + + num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a); + + if ((size_t) num_bytes > buflen) { + return -1; + } + if (padlen > (size_t) num_bytes) { + offset = padlen - num_bytes; + } else { + offset = 0; + } + + os_memset(buf, 0, offset); + mbedtls_mpi_write_binary((mbedtls_mpi *) a, buf + offset, mbedtls_mpi_size((mbedtls_mpi *)a) ); + + return num_bytes + offset; +} + + +int crypto_bignum_add(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_add_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? + -1 : 0; +} + + +int crypto_bignum_mod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_mod_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; +} + + +int crypto_bignum_exptmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + const struct crypto_bignum *c, + struct crypto_bignum *d) +{ + return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c, NULL) ? -1 : 0; + +} + + +int crypto_bignum_inverse(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_inv_mod((mbedtls_mpi *) c, (const mbedtls_mpi *) a, + (const mbedtls_mpi *) b) ? -1 : 0; +} + + +int crypto_bignum_sub(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_sub_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? + -1 : 0; +} + + +int crypto_bignum_div(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_div_mpi((mbedtls_mpi *) c, NULL, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? + -1 : 0; +} + + +int crypto_bignum_mulmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + const struct crypto_bignum *c, + struct crypto_bignum *d) +{ + int res; +#if ALLOW_EVEN_MOD // Must enable this macro if c is even. + mbedtls_mpi temp; + mbedtls_mpi_init(&temp); + + res = mbedtls_mpi_mul_mpi(&temp, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b); + if (res) { + return -1; + } + + res = mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, &temp, (mbedtls_mpi *) c); + + mbedtls_mpi_free(&temp); +#else + // Works with odd modulus only, but it is faster with HW acceleration + res = esp_mpi_mul_mpi_mod((mbedtls_mpi *) d, (mbedtls_mpi *) a, (mbedtls_mpi *) b, (mbedtls_mpi *) c); +#endif + return res ? -1 : 0; +} + + +int crypto_bignum_cmp(const struct crypto_bignum *a, + const struct crypto_bignum *b) +{ + return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) a, (const mbedtls_mpi *) b); +} + + +int crypto_bignum_bits(const struct crypto_bignum *a) +{ + return mbedtls_mpi_bitlen((const mbedtls_mpi *) a); +} + + +int crypto_bignum_is_zero(const struct crypto_bignum *a) +{ + return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 0) == 0); +} + + +int crypto_bignum_is_one(const struct crypto_bignum *a) +{ + return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 1) == 0); +} + + +int crypto_bignum_legendre(const struct crypto_bignum *a, + const struct crypto_bignum *p) +{ + mbedtls_mpi exp, tmp; + int res = -2, ret; + + mbedtls_mpi_init(&exp); + mbedtls_mpi_init(&tmp); + + /* exp = (p-1) / 2 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *) p, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *) a, &exp, (const mbedtls_mpi *) p, NULL)); + + if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) { + res = 1; + } else if (mbedtls_mpi_cmp_int(&tmp, 0) == 0 + /* The below check is workaround for the case where HW + * does not behave properly for X ^ A mod M when X is + * power of M. Instead of returning value 0, value M is + * returned.*/ + || mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) { + res = 0; + } else { + res = -1; + } + +cleanup: + mbedtls_mpi_free(&tmp); + mbedtls_mpi_free(&exp); + return res; +} + +#ifdef CONFIG_ECC +struct crypto_ec { + mbedtls_ecp_group group; +}; + +struct crypto_ec *crypto_ec_init(int group) +{ + struct crypto_ec *e; + + mbedtls_ecp_group_id grp_id; + + /* IANA registry to mbedtls internal mapping*/ + switch (group) { + case IANA_SECP256R1: + /* For now just support NIST-P256. + * This is of type "short Weierstrass". + */ + grp_id = MBEDTLS_ECP_DP_SECP256R1; + break; + default: + return NULL; + + } + e = os_zalloc(sizeof(*e)); + if (e == NULL) { + return NULL; + } + + mbedtls_ecp_group_init( &e->group ); + + if (mbedtls_ecp_group_load(&e->group, grp_id)) { + crypto_ec_deinit(e); + e = NULL; + } + + return e; +} + + +void crypto_ec_deinit(struct crypto_ec *e) +{ + if (e == NULL) { + return; + } + + mbedtls_ecp_group_free( &e->group ); + os_free(e); +} + + +struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e) +{ + mbedtls_ecp_point *pt; + if (e == NULL) { + return NULL; + } + + pt = os_zalloc(sizeof(mbedtls_ecp_point)); + + if( pt == NULL) { + return NULL; + } + + mbedtls_ecp_point_init(pt); + + return (struct crypto_ec_point *) pt; +} + + +size_t crypto_ec_prime_len(struct crypto_ec *e) +{ + return mbedtls_mpi_size(&e->group.P); +} + + +size_t crypto_ec_prime_len_bits(struct crypto_ec *e) +{ + return mbedtls_mpi_bitlen(&e->group.P); +} + + +const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e) +{ + return (const struct crypto_bignum *) &e->group.P; +} + + +const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e) +{ + return (const struct crypto_bignum *) &e->group.N; +} + + +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) +{ + mbedtls_ecp_point_free((mbedtls_ecp_point *) p); + os_free(p); +} + + +int crypto_ec_point_to_bin(struct crypto_ec *e, + const struct crypto_ec_point *point, u8 *x, u8 *y) +{ + int len = mbedtls_mpi_size(&e->group.P); + + if (x) { + if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->X, + x, len, len) < 0) { + return -1; + } + + } + + if (y) { + if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->Y, + y, len, len) < 0) { + return -1; + } + } + + return 0; +} + + +struct crypto_ec_point *crypto_ec_point_from_bin(struct crypto_ec *e, + const u8 *val) +{ + mbedtls_ecp_point *pt; + int len, ret; + + if (e == NULL) { + return NULL; + } + + len = mbedtls_mpi_size(&e->group.P); + + pt = os_zalloc(sizeof(mbedtls_ecp_point)); + mbedtls_ecp_point_init(pt); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, val, len)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->Y, val + len, len)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset((&pt->Z), 1)); + + return (struct crypto_ec_point *) pt; + +cleanup: + mbedtls_ecp_point_free(pt); + os_free(pt); + return NULL; +} + + +int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, + const struct crypto_ec_point *b, + struct crypto_ec_point *c) +{ + int ret; + mbedtls_mpi one; + + mbedtls_mpi_init(&one); + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &one, 1 )); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&e->group, (mbedtls_ecp_point *) c, &one, (const mbedtls_ecp_point *)a , &one, (const mbedtls_ecp_point *)b)); + +cleanup: + mbedtls_mpi_free(&one); + return ret ? -1 : 0; +} + + +int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, + const struct crypto_bignum *b, + struct crypto_ec_point *res) +{ + int ret; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_entropy_init(&entropy); + + MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0)); + + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&e->group, + (mbedtls_ecp_point *) res, + (const mbedtls_mpi *)b, + (const mbedtls_ecp_point *)p, + mbedtls_ctr_drbg_random, + &ctr_drbg)); +cleanup: + mbedtls_ctr_drbg_free( &ctr_drbg ); + mbedtls_entropy_free( &entropy ); + return ret ? -1 : 0; +} + + +/* Currently mbedtls does not have any function for inverse + * This function calculates inverse of a point. + * Set R = -P + */ +static int ecp_opp( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P) +{ + int ret = 0; + + /* Copy */ + if (R != P) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + } + + /* In-place opposite */ + if (mbedtls_mpi_cmp_int( &R->Y, 0) != 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&R->Y, &grp->P, &R->Y)); + } + +cleanup: + return ( ret ); +} + +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) +{ + return ecp_opp(&e->group, (mbedtls_ecp_point *) p, (mbedtls_ecp_point *) p) ? -1 : 0; +} + +int crypto_ec_point_solve_y_coord(struct crypto_ec *e, + struct crypto_ec_point *p, + const struct crypto_bignum *x, int y_bit) +{ + mbedtls_mpi temp; + mbedtls_mpi *y_sqr, *y; + mbedtls_mpi_init(&temp); + int ret = 0; + + y = &((mbedtls_ecp_point *)p)->Y; + + /* Faster way to find sqrt + * Works only with curves having prime p + * such that p ≡ 3 (mod 4) + * y_ = (y2 ^ ((p+1)/4)) mod p + * + * if y_bit: y = p-y_ + * else y = y_` + */ + + y_sqr = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, x); + + if (y_sqr) { + + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&temp, &e->group.P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL)); + + if (y_bit) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y)); + } + } else { + ret = 1; + } +cleanup: + mbedtls_mpi_free(&temp); + mbedtls_mpi_free(y_sqr); + os_free(y_sqr); + return ret ? -1 : 0; +} + +struct crypto_bignum * +crypto_ec_point_compute_y_sqr(struct crypto_ec *e, + const struct crypto_bignum *x) +{ + mbedtls_mpi temp, temp2, num; + int ret = 0; + + mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi)); + if (y_sqr == NULL) { + return NULL; + } + + mbedtls_mpi_init(&temp); + mbedtls_mpi_init(&temp2); + mbedtls_mpi_init(&num); + mbedtls_mpi_init(y_sqr); + + /* y^2 = x^3 + ax + b mod P*/ + /* mbedtls does not have mod-add or mod-mul apis. + * + */ + + /* Calculate x^3 mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &num, 3)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&temp, (const mbedtls_mpi *) x, &num, &e->group.P, NULL)); + + /* Calculate ax mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &num, -3)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x, &num)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P)); + + /* Calculate ax + b mod P. Note that b is already < P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &e->group.B)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P)); + + /* Calculate x^3 + ax + b mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &e->group.P)); + + +cleanup: + mbedtls_mpi_free(&temp); + mbedtls_mpi_free(&temp2); + mbedtls_mpi_free(&num); + if (ret) { + mbedtls_mpi_free(y_sqr); + os_free(y_sqr); + return NULL; + } else { + return (struct crypto_bignum *) y_sqr; + } +} + + + +int crypto_ec_point_is_at_infinity(struct crypto_ec *e, + const struct crypto_ec_point *p) +{ + return mbedtls_ecp_is_zero((mbedtls_ecp_point *) p); +} + +int crypto_ec_point_is_on_curve(struct crypto_ec *e, + const struct crypto_ec_point *p) +{ + mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two; + int ret = 0, on_curve = 0; + + mbedtls_mpi_init(&y_sqr_lhs); + mbedtls_mpi_init(&two); + + /* Calculate y^2 mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &two, 2)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&y_sqr_lhs, &((const mbedtls_ecp_point *)p)->Y , &two, &e->group.P, NULL)); + + y_sqr_rhs = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *) & ((const mbedtls_ecp_point *)p)->X); + + if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) { + on_curve = 1; + } + +cleanup: + mbedtls_mpi_free(&y_sqr_lhs); + mbedtls_mpi_free(y_sqr_rhs); + os_free(y_sqr_rhs); + return (ret == 0) && (on_curve == 1); +} + +int crypto_ec_point_cmp(const struct crypto_ec *e, + const struct crypto_ec_point *a, + const struct crypto_ec_point *b) +{ + return mbedtls_ecp_point_cmp((const mbedtls_ecp_point *) a, + (const mbedtls_ecp_point *) b); +} + +#endif /* CONFIG_ECC */ diff --git a/components/wpa_supplicant/test/component.mk b/components/wpa_supplicant/test/component.mk new file mode 100644 index 000000000..5dd172bdb --- /dev/null +++ b/components/wpa_supplicant/test/component.mk @@ -0,0 +1,5 @@ +# +#Component Makefile +# + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/wpa_supplicant/test/test_crypto.c b/components/wpa_supplicant/test/test_crypto.c new file mode 100644 index 000000000..e8f8d05a5 --- /dev/null +++ b/components/wpa_supplicant/test/test_crypto.c @@ -0,0 +1,545 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include +#include "unity.h" +#include +#include "crypto/crypto.h" + +#include "mbedtls/ecp.h" +typedef struct crypto_bignum crypto_bignum; + +TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") +{ + { + + uint8_t buf[32], buf2[32]; + + /* BN - Init & Deinit*/ + crypto_bignum *bn = crypto_bignum_init(); + crypto_bignum_deinit(bn, 1); + + /* BN - Binary to bignum & bignum to binary*/ + TEST_ASSERT(!crypto_get_random(buf, 32)); + + bn = crypto_bignum_init_set(buf, 32); + TEST_ASSERT_NOT_NULL(bn); + + + TEST_ASSERT(crypto_bignum_to_bin(bn, buf2, 32, 0) == 32); + + TEST_ASSERT(!memcmp(buf, buf2, 32)); + crypto_bignum_deinit(bn, 1); + + } + + { /** BN summation*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32]; + crypto_bignum *bn1, *bn2, *sum; + uint8_t count; + + sum = crypto_bignum_init(); + + for (count = 0; count < 32; count++) { + buf1[count] = 0x11; + buf2[count] = 0x22; + buf3[count] = 0x33; //expected result + buf4[count] = 0x0; //Calculated result + } + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + TEST_ASSERT(crypto_bignum_add(bn1, bn2, sum) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(sum, buf4, 32, 0) == 32); + + TEST_ASSERT(!memcmp(buf3, buf4, 32)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(sum, 1); + + } + + { /** BN mod*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32]; + crypto_bignum *bn1, *bn2, *mod; + uint8_t count; + + mod = crypto_bignum_init(); + + for (count = 0; count < 32; count++) { + buf1[count] = 0x33; + buf2[count] = 0x22; + buf3[count] = 0x11; //expected result + buf4[count] = 0x0; //Calculated result + } + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + TEST_ASSERT(crypto_bignum_mod(bn1, bn2, mod) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(mod, buf4, 32, 0) == 32); + + TEST_ASSERT(!memcmp(buf3, buf4, 32)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(mod, 1); + + } + + { /** BN sub*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32]; + crypto_bignum *bn1, *bn2, *sub; + uint8_t count; + + sub = crypto_bignum_init(); + + for (count = 0; count < 32; count++) { + buf1[count] = 0x44; + buf2[count] = 0x11; + buf3[count] = 0x33; //expected result + buf4[count] = 0x0; //Calculated result + } + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + TEST_ASSERT(crypto_bignum_sub(bn1, bn2, sub) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(sub, buf4, 32, 0) == 32); + + TEST_ASSERT(!memcmp(buf3, buf4, 32)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(sub, 1); + + } + + { /** BN div*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32]; + crypto_bignum *bn1, *bn2, *div; + uint8_t count; + + div = crypto_bignum_init(); + + for (count = 0; count < 32; count++) { + buf1[count] = 0x44; + buf2[count] = 0x22; + buf3[count] = count ? 0 : 0x2; //expected result + buf4[count] = 0x0; //Calculated result + } + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + TEST_ASSERT(crypto_bignum_div(bn1, bn2, div) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(div, buf4, 32, 0) == 1); + + TEST_ASSERT(!memcmp(buf3, buf4, 1)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(div, 1); + + } + + { /** BN mul mod*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32], buf5[32]; + crypto_bignum *bn1, *bn2, *bn3, *mulmod; + uint8_t count; + + for (count = 0; count < 32; count++) { + buf1[count] = 0x22; + buf2[count] = 0x11; + buf3[count] = (count < 4) ? 0x21 : 0; + buf4[count] = (count < 4) ? 0x14 : 0; + buf5[count] = 0; + } + mulmod = crypto_bignum_init(); + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + bn3 = crypto_bignum_init_set(buf3, 4); + TEST_ASSERT_NOT_NULL(bn3); + + TEST_ASSERT(crypto_bignum_mulmod(bn1, bn2, bn3, mulmod) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(mulmod, buf5, 32, 0) == 4); + + TEST_ASSERT(!memcmp(buf5, buf4, 4)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(bn3, 1); + crypto_bignum_deinit(mulmod, 1); + + } + + { /** BN exp mod*/ + uint8_t buf1[32], buf2[32], buf3[32], buf4[32], buf5[32]; + + crypto_bignum *bn1, *bn2, *bn3, *expmod; + uint8_t count; + + expmod = crypto_bignum_init(); + + for (count = 0; count < 32; count++) { + buf1[count] = 0x22; + buf2[count] = (count >= 30) ? 0x11 : 0; + buf3[count] = (count >= 31) ? 0xE9 : 0; + buf4[count] = count ? 0 : 0x62; + buf5[count] = 0; + } + + bn1 = crypto_bignum_init_set(buf1, 32); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 32); + TEST_ASSERT_NOT_NULL(bn2); + + bn3 = crypto_bignum_init_set(buf3, 32); + TEST_ASSERT_NOT_NULL(bn3); + + TEST_ASSERT(crypto_bignum_exptmod(bn1, bn2, bn3, expmod) == 0); + + TEST_ASSERT(crypto_bignum_to_bin(expmod, buf5, 32, 0) == 1); + + TEST_ASSERT(!memcmp(buf5, buf4, 1)); + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(bn3, 1); + crypto_bignum_deinit(expmod, 1); + + } + + { /** BN Legendre symbol test*/ + uint8_t buf1[32], buf2[32]; + crypto_bignum *bn1, *bn2; + + + buf1[0] = 0xf; + buf2[0] = 0x11; + + bn1 = crypto_bignum_init_set(buf1, 1); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(buf2, 1); + TEST_ASSERT_NOT_NULL(bn2); + + TEST_ASSERT(crypto_bignum_legendre(bn1, bn2) == 1); + + crypto_bignum_deinit(bn1, 1); + buf1[0] = 0xa; + bn1 = crypto_bignum_init_set(buf1, 1); + TEST_ASSERT_NOT_NULL(bn1); + + TEST_ASSERT(crypto_bignum_legendre(bn1, bn2) == -1); + + crypto_bignum_deinit(bn1, 1); + buf1[0] = 0x11; + bn1 = crypto_bignum_init_set(buf1, 1); + TEST_ASSERT_NOT_NULL(bn1); + + TEST_ASSERT(crypto_bignum_legendre(bn1, bn2) == 0); + + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + + } +} + + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_4( a, b, 0, 0 ) + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + BYTES_TO_T_UINT_4( a, b, c, d ), \ + BYTES_TO_T_UINT_4( e, f, g, h ) + +#else /* 64-bits */ + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) | \ + ( (mbedtls_mpi_uint) e << 32 ) | \ + ( (mbedtls_mpi_uint) f << 40 ) | \ + ( (mbedtls_mpi_uint) g << 48 ) | \ + ( (mbedtls_mpi_uint) h << 56 ) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 ) + +#endif /* bits in mbedtls_mpi_uint */ + +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) + * Allocate a new memory as well so that it can be freed. + */ +static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +{ + X->s = 1; + X->n = len / sizeof( mbedtls_mpi_uint ); + X->p = os_zalloc(len); + memcpy(X->p, (void *)p, len); +} + + +TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") +{ + + static const mbedtls_mpi_uint secp256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), + BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), + BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), + BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), + }; + static const mbedtls_mpi_uint secp256r1_gy[] = { + BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), + BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), + BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), + BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), + }; + + { + /* Check init and deinit APIs*/ + struct crypto_ec *e = crypto_ec_init(19); + struct crypto_ec_point *pt = crypto_ec_point_init(e); + crypto_ec_point_deinit(pt, 1); + crypto_ec_deinit(e); + } + + { + uint8_t pt1[64], pt2[64]; + struct crypto_ec *e = crypto_ec_init(19); + struct crypto_ec_point *p; + + TEST_ASSERT_NOT_NULL(e); + + /* Note this is just testing coversion & not whether point is + * in the group or not*/ + TEST_ASSERT(!crypto_get_random(pt1, 64)); + + p = crypto_ec_point_from_bin(e, pt1); + + TEST_ASSERT(crypto_ec_prime_len(e) == 32); + + TEST_ASSERT(crypto_ec_point_to_bin(e, p, pt2, &pt2[32]) == 0); + TEST_ASSERT(!memcmp(pt1, pt2, sizeof(pt1))); + + crypto_ec_point_deinit(p, 1); + crypto_ec_deinit(e); + } + { + /* Check addition and multiplication APIs + * yield the same answer. + */ + struct crypto_ec *e = crypto_ec_init(19); + + struct crypto_ec_point *p = crypto_ec_point_init(e); + struct crypto_ec_point *q = crypto_ec_point_init(e); + struct crypto_ec_point *r = crypto_ec_point_init(e); + mbedtls_mpi num; + + TEST_ASSERT_NOT_NULL(e); + TEST_ASSERT_NOT_NULL(p); + TEST_ASSERT_NOT_NULL(q); + TEST_ASSERT_NOT_NULL(r); + + mbedtls_mpi_init( &num ); + mbedtls_mpi_lset( &num, 3 ); + + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->X, secp256r1_gx, sizeof(secp256r1_gx)); + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->Y, secp256r1_gy, sizeof(secp256r1_gy)); + + mbedtls_mpi_lset((&((mbedtls_ecp_point *)p)->Z), 1); + + TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, q) == 0); //q = 3p + + TEST_ASSERT(crypto_ec_point_add(e, p, p, r) == 0); + TEST_ASSERT(crypto_ec_point_add(e, p, r, r) == 0); + + TEST_ASSERT(crypto_ec_point_cmp(e, q, r) == 0); + + mbedtls_mpi_free( &num ); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(q, 1); + crypto_ec_point_deinit(r, 1); + crypto_ec_deinit(e); + + } + + { + /* Generate a point using generator and take its inverse + * Check that adding point to inverse yields identity + */ + struct crypto_ec *e = crypto_ec_init(19); + + struct crypto_ec_point *p = crypto_ec_point_init(e); + struct crypto_ec_point *q = crypto_ec_point_init(e); + struct crypto_ec_point *r = crypto_ec_point_init(e); + mbedtls_mpi num; + + TEST_ASSERT_NOT_NULL(e); + TEST_ASSERT_NOT_NULL(p); + TEST_ASSERT_NOT_NULL(q); + TEST_ASSERT_NOT_NULL(r); + + mbedtls_mpi_init( &num ); + mbedtls_mpi_lset( &num, 100 ); + + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->X, secp256r1_gx, sizeof(secp256r1_gx)); + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->Y, secp256r1_gy, sizeof(secp256r1_gy)); + + mbedtls_mpi_lset((&((mbedtls_ecp_point *)p)->Z), 1); + + TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, q) == 0); + TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, r) == 0); + + TEST_ASSERT(crypto_ec_point_invert(e, r) == 0); + TEST_ASSERT(crypto_ec_point_add(e, q, r, r) == 0); + + TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r)); + + mbedtls_mpi_free( &num ); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(q, 1); + crypto_ec_point_deinit(r, 1); + crypto_ec_deinit(e); + + } + { + /* Check y_sqr calculations and other dependent APIs */ + + struct crypto_ec *e = crypto_ec_init(19); + + struct crypto_ec_point *p = crypto_ec_point_init(e); + struct crypto_ec_point *q = crypto_ec_point_init(e); + mbedtls_mpi num; + + TEST_ASSERT_NOT_NULL(e); + TEST_ASSERT_NOT_NULL(p); + TEST_ASSERT_NOT_NULL(q); + + mbedtls_mpi_init( &num ); + mbedtls_mpi_lset( &num, 50 ); + + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->X, secp256r1_gx, sizeof(secp256r1_gx)); + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->Y, secp256r1_gy, sizeof(secp256r1_gy)); + + mbedtls_mpi_lset((&((mbedtls_ecp_point *)p)->Z), 1); + + /* Generator should always be on the curve*/ + TEST_ASSERT(crypto_ec_point_is_on_curve(e, p)); + + /* Any point generated using generated should also be on the same curve*/ + TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, q) == 0); + TEST_ASSERT(crypto_ec_point_is_on_curve(e, q)); + + + mbedtls_mpi_free( &num ); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(q, 1); + crypto_ec_deinit(e); + + } + + { + /* crypto_ec_point_solve_y_coord APIs*/ + + struct crypto_ec *e = crypto_ec_init(19); + + struct crypto_ec_point *p = crypto_ec_point_init(e); + struct crypto_ec_point *q = crypto_ec_point_init(e); + struct crypto_ec_point *r = crypto_ec_point_init(e); + mbedtls_mpi num; + + TEST_ASSERT_NOT_NULL(e); + TEST_ASSERT_NOT_NULL(p); + TEST_ASSERT_NOT_NULL(q); + TEST_ASSERT_NOT_NULL(r); + + mbedtls_mpi_init( &num ); + mbedtls_mpi_lset( &num, 50 ); + + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->X, secp256r1_gx, sizeof(secp256r1_gx)); + ecp_mpi_load(& ((mbedtls_ecp_point *)p)->Y, secp256r1_gy, sizeof(secp256r1_gy)); + + mbedtls_mpi_lset((&((mbedtls_ecp_point *)p)->Z), 1); + + mbedtls_mpi_copy(&((mbedtls_ecp_point *)q)->X, &((mbedtls_ecp_point *)p)->X); + mbedtls_mpi_copy(&((mbedtls_ecp_point *)r)->X, &((mbedtls_ecp_point *)p)->X); + + mbedtls_mpi_lset((&((mbedtls_ecp_point *)q)->Z), 1); + mbedtls_mpi_lset((&((mbedtls_ecp_point *)r)->Z), 1); + + TEST_ASSERT(crypto_ec_point_solve_y_coord(e, q, (crypto_bignum *) & ((mbedtls_ecp_point *)q)->X, 0) == 0); + TEST_ASSERT(crypto_ec_point_is_on_curve(e, q)); + + TEST_ASSERT(crypto_ec_point_solve_y_coord(e, r, (crypto_bignum *) & ((mbedtls_ecp_point *)q)->X, 1) == 0); + TEST_ASSERT(crypto_ec_point_is_on_curve(e, r)); + + TEST_ASSERT((crypto_ec_point_cmp(e, p, q) == 0) || (crypto_ec_point_cmp(e, p, r) == 0)); + + /* The two roots should be inverse of one another*/ + TEST_ASSERT(crypto_ec_point_add(e, q, r, r) == 0); + TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r)); + + mbedtls_mpi_free( &num ); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(q, 1); + crypto_ec_point_deinit(r, 1); + crypto_ec_deinit(e); + + } + +} +