-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for micro-ecc (WIP) #228
base: develop
Are you sure you want to change the base?
Changes from all commits
6cf43c0
0f1be30
ff73600
44eddf4
b306f27
9232271
0580b36
4c39d5c
3ce86c2
86b6765
121cad5
61763fe
f972a67
8014f05
f8204f2
0e068ec
3dc62b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "ext/micro-ecc"] | ||
path = ext/micro-ecc | ||
url = https://github.com/kmackay/micro-ecc.git |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,14 +24,17 @@ | |
#else | ||
#define assert(x) | ||
#endif | ||
#include <inttypes.h> | ||
|
||
#include "global.h" | ||
#include "dtls_debug.h" | ||
#include "numeric.h" | ||
#include "dtls.h" | ||
#include "crypto.h" | ||
#include "ccm.h" | ||
#include "ecc/ecc.h" | ||
#ifdef DTLS_ECC | ||
#include "ext/micro-ecc/uECC.h" | ||
#endif /* DTLS_ECC */ | ||
#include "dtls_prng.h" | ||
#include "netq.h" | ||
|
||
|
@@ -356,6 +359,10 @@ dtls_psk_pre_master_secret(unsigned char *key, size_t keylen, | |
#endif /* DTLS_PSK */ | ||
|
||
#ifdef DTLS_ECC | ||
#ifdef uECC_SUPPORTS_secp256r1 | ||
const dtls_ecdh_curve default_curve = TLS_EXT_ELLIPTIC_CURVES_SECP256R1; | ||
#endif /* uECC_SUPPORTS_secp256r1 */ | ||
|
||
static void dtls_ec_key_to_uint32(const unsigned char *key, size_t key_size, | ||
uint32_t *result) { | ||
int i; | ||
|
@@ -432,69 +439,148 @@ int dtls_ec_key_asn1_from_uint32(const uint32_t *key, size_t key_size, | |
return key_size + 2; | ||
} | ||
|
||
static int get_uecc_curve(dtls_ecdh_curve curve, uECC_Curve *result) { | ||
struct { | ||
dtls_ecdh_curve curve; | ||
uECC_Curve uecc_curve; | ||
} known_curves[] = { | ||
#if uECC_SUPPORTS_secp256r1 | ||
{ TLS_EXT_ELLIPTIC_CURVES_SECP256R1, uECC_secp256r1() }, | ||
#endif /* uECC_SUPPORTS_secp256r1 */ | ||
}; | ||
unsigned int index; | ||
|
||
for (index = 0; index < sizeof(known_curves)/sizeof(known_curves[0]); index++) { | ||
if (known_curves[index].curve == curve) { | ||
*result = known_curves[index].uecc_curve; | ||
return 1; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
int dtls_ecdh_pre_master_secret2(const unsigned char *priv_key, | ||
const unsigned char *pub_key, | ||
size_t key_size, | ||
dtls_ecdh_curve curve, | ||
unsigned char *result, | ||
size_t result_len) { | ||
uECC_Curve uecc_curve; | ||
if (!get_uecc_curve(curve, &uecc_curve)) { | ||
dtls_warn("curve %" PRIu16 " not supported\n", curve); | ||
return -1; | ||
} | ||
|
||
if (result_len < key_size) { | ||
return -1; | ||
} | ||
|
||
if (!uECC_valid_public_key(pub_key, uecc_curve)) { | ||
dtls_warn("invalid public key\n"); | ||
} | ||
|
||
if (!uECC_shared_secret(pub_key, priv_key, result, uecc_curve)) { | ||
dtls_warn("cannot generate ECDH shared secret\n"); | ||
return 0; | ||
} | ||
|
||
return key_size; | ||
} | ||
|
||
int dtls_ecdh_pre_master_secret(unsigned char *priv_key, | ||
unsigned char *pub_key_x, | ||
unsigned char *pub_key_y, | ||
size_t key_size, | ||
unsigned char *result, | ||
size_t result_len) { | ||
uint32_t priv[8]; | ||
uint32_t pub_x[8]; | ||
uint32_t pub_y[8]; | ||
uint32_t result_x[8]; | ||
uint32_t result_y[8]; | ||
const dtls_ecdh_curve curve = default_curve; | ||
uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; | ||
|
||
assert(key_size == sizeof(priv)); | ||
if (result_len < key_size) { | ||
return -1; | ||
} | ||
|
||
dtls_ec_key_to_uint32(priv_key, key_size, priv); | ||
dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x); | ||
dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y); | ||
|
||
ecc_ecdh(pub_x, pub_y, priv, result_x, result_y); | ||
|
||
dtls_ec_key_from_uint32(result_x, key_size, result); | ||
return key_size; | ||
memcpy(pub_key, pub_key_x, DTLS_EC_KEY_SIZE); | ||
memcpy(pub_key + DTLS_EC_KEY_SIZE, pub_key_y, DTLS_EC_KEY_SIZE); | ||
return dtls_ecdh_pre_master_secret2(priv_key, pub_key, key_size, curve, | ||
result, result_len); | ||
} | ||
|
||
void | ||
dtls_ecdsa_generate_key(unsigned char *priv_key, | ||
unsigned char *pub_key_x, | ||
unsigned char *pub_key_y, | ||
size_t key_size) { | ||
uint32_t priv[8]; | ||
uint32_t pub_x[8]; | ||
uint32_t pub_y[8]; | ||
const dtls_ecdh_curve curve = default_curve; | ||
uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; | ||
|
||
int res = dtls_ecdsa_generate_key2(priv_key, pub_key, key_size, curve); | ||
if (res > 0) { | ||
memcpy(pub_key_x, pub_key, res); | ||
memcpy(pub_key_y, pub_key + res, res); | ||
} | ||
} | ||
|
||
do { | ||
dtls_prng((unsigned char *)priv, key_size); | ||
} while (!ecc_is_valid_key(priv)); | ||
int | ||
dtls_ecdsa_generate_key2(unsigned char *priv_key, | ||
unsigned char *pub_key, | ||
size_t key_size, | ||
dtls_ecdh_curve curve) { | ||
uECC_Curve uecc_curve; | ||
if (!get_uecc_curve(curve, &uecc_curve)) { | ||
dtls_warn("curve %" PRIu16 " not supported\n", curve); | ||
return -1; | ||
} | ||
|
||
ecc_gen_pub_key(priv, pub_x, pub_y); | ||
assert(key_size >= (unsigned int)uECC_curve_private_key_size(uecc_curve)); | ||
assert(2 * key_size >= (unsigned int)uECC_curve_public_key_size(uecc_curve)); | ||
|
||
dtls_ec_key_from_uint32(priv, key_size, priv_key); | ||
dtls_ec_key_from_uint32(pub_x, key_size, pub_key_x); | ||
dtls_ec_key_from_uint32(pub_y, key_size, pub_key_y); | ||
if (!uECC_make_key(pub_key, priv_key, uecc_curve) | ||
|| !uECC_valid_public_key(pub_key, uecc_curve)) { | ||
dtls_crit("cannot generate ECC key pair\n"); | ||
return 0; | ||
} | ||
return uECC_curve_private_key_size(uecc_curve); | ||
} | ||
|
||
/* rfc4492#section-5.4 */ | ||
void | ||
dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, | ||
const unsigned char *sign_hash, size_t sign_hash_size, | ||
uint32_t point_r[9], uint32_t point_s[9]) { | ||
int ret; | ||
uint32_t priv[8]; | ||
uint32_t hash[8]; | ||
uint32_t randv[8]; | ||
|
||
dtls_ec_key_to_uint32(priv_key, key_size, priv); | ||
dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash); | ||
do { | ||
dtls_prng((unsigned char *)randv, key_size); | ||
ret = ecc_ecdsa_sign(priv, hash, randv, point_r, point_s); | ||
} while (ret); | ||
const dtls_ecdh_curve curve = default_curve; | ||
dtls_ecdsa_create_sig_hash2(priv_key, key_size, | ||
sign_hash, sign_hash_size, | ||
curve, point_r, point_s); | ||
|
||
} | ||
|
||
int | ||
dtls_ecdsa_create_sig_hash2(const unsigned char *priv_key, size_t key_size, | ||
const unsigned char *sign_hash, size_t sign_hash_size, | ||
dtls_ecdh_curve curve, | ||
uint32_t point_r[9], uint32_t point_s[9]) { | ||
uint8_t sign[2 * DTLS_EC_KEY_SIZE]; | ||
uECC_Curve uecc_curve; | ||
int curve_size; | ||
if (!get_uecc_curve(curve, &uecc_curve)) { | ||
dtls_warn("curve %" PRIu16 " not supported\n", curve); | ||
return -1; | ||
} | ||
|
||
curve_size = uECC_curve_private_key_size(uecc_curve); | ||
|
||
assert(key_size >= (unsigned int)curve_size); | ||
assert(sign_hash_size >= (unsigned int)curve_size); | ||
assert(sizeof(sign) >= 2 * (unsigned int)curve_size); | ||
if (!uECC_sign(priv_key, sign_hash, sign_hash_size, sign, uecc_curve)) { | ||
dtls_warn("cannot create signature\n"); | ||
return -1; | ||
} | ||
|
||
dtls_ec_key_to_uint32(sign, curve_size, point_r); | ||
dtls_ec_key_to_uint32(sign + curve_size, curve_size, point_s); | ||
return 2 * curve_size; | ||
} | ||
|
||
void | ||
|
@@ -522,19 +608,39 @@ dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x, | |
const unsigned char *pub_key_y, size_t key_size, | ||
const unsigned char *sign_hash, size_t sign_hash_size, | ||
unsigned char *result_r, unsigned char *result_s) { | ||
uint32_t pub_x[8]; | ||
uint32_t pub_y[8]; | ||
uint32_t hash[8]; | ||
uint32_t point_r[8]; | ||
uint32_t point_s[8]; | ||
|
||
dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x); | ||
dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y); | ||
dtls_ec_key_to_uint32(result_r, key_size, point_r); | ||
dtls_ec_key_to_uint32(result_s, key_size, point_s); | ||
dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash); | ||
|
||
return ecc_ecdsa_validate(pub_x, pub_y, hash, point_r, point_s); | ||
const dtls_ecdh_curve curve = default_curve; | ||
uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; | ||
memcpy(pub_key, pub_key_x, key_size); | ||
memcpy(pub_key + key_size, pub_key_y, key_size); | ||
return dtls_ecdsa_verify_sig_hash2(pub_key, key_size, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess, the size of |
||
sign_hash, sign_hash_size, | ||
curve, | ||
result_r, result_s); | ||
} | ||
|
||
int | ||
dtls_ecdsa_verify_sig_hash2(const unsigned char *pub_key, size_t key_size, | ||
const unsigned char *sign_hash, size_t sign_hash_size, | ||
dtls_ecdh_curve curve, | ||
unsigned char *result_r, unsigned char *result_s) { | ||
uint8_t sign[2 * DTLS_EC_KEY_SIZE]; | ||
uECC_Curve uecc_curve; | ||
int curve_size; | ||
if (!get_uecc_curve(curve, &uecc_curve)) { | ||
dtls_warn("curve %" PRIu16 " not supported\n", curve); | ||
return -1; | ||
} | ||
(void)result_r; | ||
(void)result_s; | ||
|
||
curve_size = uECC_curve_public_key_size(uecc_curve); | ||
|
||
assert(key_size == (unsigned int)curve_size); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That fires on my interop test. Adding
I get
AFAIK, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Beside the assert, the first interop-tests with Californium are successful. |
||
assert(sizeof(sign) >= (unsigned int)curve_size); | ||
|
||
/* clear sign to avoid maybe-unitialized warning */ | ||
memset(sign, 0, sizeof(sign)); | ||
return uECC_verify(pub_key, sign_hash, sign_hash_size, sign, uecc_curve); | ||
} | ||
|
||
int | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"ext/micro-ecc" is part of the include path, maybe it's simpler to use "uECC.h"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is my preference to always include the package information path in the #include statement, to prevent name clashes (unlikely with
uECC.h
, but with possible with names likeglobal.h
etc.).So, I would recommend that the include path includes
ext/
, and use#include <micro-ecc/uECC.h>
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pain is, that "micro-ecc/uECC.c" uses:
and "micro-ecc/uECC_vli.h" uses:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anything that is getting built external to micro-ecc will need the equivalent of "micro-ecc/uECC.h" to get at the function definitions. For the actual micro-ecc code compilation, I assume that it is done in the micro-ecc/ directory, in which case just "uECCH.h" without a path is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I've checked it and at least the cmake build doesn't need to extend the include path with "ext/micro-ecc".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mixed it up, it's only part of "FILES".