summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/ecc.c59
-rw-r--r--src/shared/ecc.h10
-rw-r--r--unit/test-ecc.c35
3 files changed, 104 insertions, 0 deletions
diff --git a/src/shared/ecc.c b/src/shared/ecc.c
index 41be02b72..eb2cc005d 100644
--- a/src/shared/ecc.c
+++ b/src/shared/ecc.c
@@ -66,9 +66,13 @@ typedef struct {
#define CURVE_N_32 { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }
+#define CURVE_B_32 { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \
+ 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull }
+
static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32;
static struct ecc_point curve_g = CURVE_G_32;
static uint64_t curve_n[NUM_ECC_DIGITS] = CURVE_N_32;
+static uint64_t curve_b[NUM_ECC_DIGITS] = CURVE_B_32;
static bool get_random_number(uint64_t *vli)
{
@@ -183,6 +187,19 @@ static int vli_cmp(const uint64_t *left, const uint64_t *right)
return 0;
}
+/* Constant-time comparison function - secure way to compare long integers */
+/* Returns one if left == right, zero otherwise. */
+static bool vli_equal(const uint64_t *left, const uint64_t *right)
+{
+ uint64_t diff = 0;
+ int i;
+
+ for (i = NUM_ECC_DIGITS - 1; i >= 0; --i)
+ diff |= (left[i] ^ right[i]);
+
+ return (diff == 0);
+}
+
/* Computes result = in << c, returning carry. Can modify in place
* (if result == in). 0 < shift < 64.
*/
@@ -770,6 +787,34 @@ static void ecc_point_mult(struct ecc_point *result,
vli_set(result->y, ry[0]);
}
+static bool ecc_valid_point(const struct ecc_point *point)
+{
+ uint64_t tmp1[NUM_ECC_DIGITS];
+ uint64_t tmp2[NUM_ECC_DIGITS];
+ uint64_t _3[NUM_ECC_DIGITS] = { 3 }; /* -a = 3 */
+
+ /* The point at infinity is invalid. */
+ if (ecc_point_is_zero(point))
+ return false;
+
+ /* x and y must be smaller than p. */
+ if (vli_cmp(curve_p, point->x) != 1 ||
+ vli_cmp(curve_p, point->y) != 1)
+ return false;
+
+ /* Computes result = y^2. */
+ vli_mod_square_fast(tmp1, point->y);
+
+ /* Computes result = x^3 + ax + b. result must not overlap x. */
+ vli_mod_square_fast(tmp2, point->x); /* r = x^2 */
+ vli_mod_sub(tmp2, tmp2, _3, curve_p); /* r = x^2 - 3 */
+ vli_mod_mult_fast(tmp2, tmp2, point->x); /* r = x^3 - 3x */
+ vli_mod_add(tmp2, tmp2, curve_b, curve_p); /* r = x^3 - 3x + b */
+
+ /* Make sure that y^2 == x^3 + ax + b */
+ return vli_equal(tmp1, tmp2);
+}
+
/* Little endian byte-array to native conversion */
static void ecc_bytes2native(const uint8_t bytes[ECC_BYTES],
uint64_t native[NUM_ECC_DIGITS])
@@ -838,6 +883,16 @@ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32])
return true;
}
+bool ecc_valid_public_key(const uint8_t public_key[64])
+{
+ struct ecc_point pk;
+
+ ecc_bytes2native(public_key, pk.x);
+ ecc_bytes2native(&public_key[32], pk.y);
+
+ return ecc_valid_point(&pk);
+}
+
bool ecdh_shared_secret(const uint8_t public_key[64],
const uint8_t private_key[32],
uint8_t secret[32])
@@ -851,6 +906,10 @@ bool ecdh_shared_secret(const uint8_t public_key[64],
ecc_bytes2native(public_key, pk.x);
ecc_bytes2native(&public_key[32], pk.y);
+
+ if (!ecc_valid_point(&pk))
+ return false;
+
ecc_bytes2native(private_key, priv);
ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv));
diff --git a/src/shared/ecc.h b/src/shared/ecc.h
index e971375ac..f89f2b0c3 100644
--- a/src/shared/ecc.h
+++ b/src/shared/ecc.h
@@ -28,6 +28,7 @@
#include <stdint.h>
/* Create a public/private key pair.
+ *
* Outputs:
* public_key - Will be filled in with the public key.
* private_Key - Will be filled in with the private key.
@@ -37,6 +38,15 @@
*/
bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]);
+/* Check to see if a public key is valid.
+ *
+ * Inputs:
+ * public_key - The public key to check.
+ *
+ * Returns true if the public key is valid, false if it is invalid.
+*/
+bool ecc_valid_public_key(const uint8_t public_key[64]);
+
/* Compute a shared secret given your secret key and someone else's
* public key.
* Note: It is recommended that you hash the result of ecdh_shared_secret
diff --git a/unit/test-ecc.c b/unit/test-ecc.c
index 9b48d0b3a..98400a253 100644
--- a/unit/test-ecc.c
+++ b/unit/test-ecc.c
@@ -243,6 +243,39 @@ static void test_sample_3(const void *data)
tester_test_passed();
}
+static void test_invalid_pub(const void *data)
+{
+ uint8_t priv_a[32] = { 0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
+ 0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
+ 0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,
+ 0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f,
+ };
+ uint8_t pub_a[64] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
+ 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
+ 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
+ 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
+
+ 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
+ 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
+ 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
+ 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc,
+ };
+ uint8_t dhkey[32] = { 0x2d, 0xab, 0x00, 0x48, 0xcb, 0xb3, 0x7b, 0xda,
+ 0x55, 0x7b, 0x8b, 0x72, 0xa8, 0x57, 0x87, 0xc3,
+ 0x87, 0x27, 0x99, 0x32, 0xfc, 0x79, 0x5f, 0xae,
+ 0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70,
+ };
+ int fails;
+
+ memset(pub_a + 32, 0x42, 32);
+
+ fails = test_sample(priv_a, priv_a, pub_a, pub_a, dhkey);
+
+ g_assert(fails >= 1);
+
+ tester_test_passed();
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -253,5 +286,7 @@ int main(int argc, char *argv[])
tester_add("/ecdh/sample/2", NULL, NULL, test_sample_2, NULL);
tester_add("/ecdh/sample/3", NULL, NULL, test_sample_3, NULL);
+ tester_add("/ecdh/invalid", NULL, NULL, test_invalid_pub, NULL);
+
return tester_run();
}