Skip to content

Commit

Permalink
crypto.[hc]: Use micro-ecc for ECC support
Browse files Browse the repository at this point in the history
This change provides support for the curve secp256r1 from micro-ecc.

Change-Id: I2d272e2ddb498016a2d6e85af7af8247010768d8
  • Loading branch information
obgm committed Feb 18, 2024
1 parent 0e068ec commit 3dc62b1
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 33 deletions.
170 changes: 140 additions & 30 deletions crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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/micro-ecc/uECC.h"
#ifdef DTLS_ECC
#include "ext/micro-ecc/uECC.h"
#endif /* DTLS_ECC */
#include "dtls_prng.h"
#include "netq.h"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -432,64 +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) {
const dtls_ecdh_curve curve = default_curve;
uint8_t pub_key[2 * DTLS_EC_KEY_SIZE];
uint8_t priv[DTLS_EC_KEY_SIZE];

if (result_len < key_size) {
return -1;
}

memcpy(priv, priv_key, DTLS_EC_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);
if (!uECC_valid_public_key(pub_key)) {
dtls_warn("invalid public key\n");
}

if (!uECC_shared_secret(pub_key, priv, result)) {
dtls_warn("cannot generate ECDH shared secret\n");
return 0;
}

return 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) {
const dtls_ecdh_curve curve = default_curve;
uint8_t pub_key[2 * DTLS_EC_KEY_SIZE];

assert(key_size == DTLS_EC_KEY_SIZE);
if (!uECC_make_key(pub_key, priv_key)
|| !uECC_valid_public_key(pub_key)) {
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);
}
}

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;
}

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));

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;
}
memcpy(pub_key_x, pub_key, key_size);
memcpy(pub_key_y, pub_key + key_size, key_size);
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]) {
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 == DTLS_EC_KEY_SIZE);
assert(sign_hash_size >= uECC_BYTES);
assert(sizeof(sign) >= 2 * uECC_BYTES);
uECC_sign(priv_key, sign_hash, sign);
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, DTLS_EC_KEY_SIZE, point_r);
dtls_ec_key_to_uint32(sign + DTLS_EC_KEY_SIZE, DTLS_EC_KEY_SIZE, point_s);
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
Expand Down Expand Up @@ -517,20 +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) {
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,
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;

assert(key_size == DTLS_EC_KEY_SIZE);
assert(sign_hash_size >= uECC_BYTES);
assert(sizeof(sign) >= 2 * uECC_BYTES);
curve_size = uECC_curve_public_key_size(uecc_curve);

assert(key_size == (unsigned int)curve_size);
assert(sizeof(sign) >= (unsigned int)curve_size);

/* clear sign to avoid maybe-unitialized warning */
memset(sign, 0, sizeof(sign));
memcpy(pub_key, pub_key_x, key_size);
memcpy(pub_key + key_size, pub_key_y, key_size);
return uECC_verify(pub_key, sign_hash, sign);
return uECC_verify(pub_key, sign_hash, sign_hash_size, sign, uecc_curve);
}

int
Expand Down
78 changes: 75 additions & 3 deletions crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,18 @@ typedef uint8_t dtls_cipher_index_t;
typedef enum { AES128=0
} dtls_crypto_alg;

typedef enum {
DTLS_ECDH_CURVE_SECP256R1
} dtls_ecdh_curve;
/**
* Curve type as specified in the TLS supported elliptic curves
* extension (@see [RFC 8422, Section 5.1.1](https://www.rfc-editor.org/rfc/rfc8422#section-5.1.1).
*
* The only supported value so far is TLS_EXT_ELLIPTIC_CURVES_SECP256R1
*/
typedef uint16_t dtls_ecdh_curve;

/**
* @deprecated {Defined for backwards compatibility.}
*/
#define DTLS_ECDH_CURVE_SECP256R1 TLS_EXT_ELLIPTIC_CURVES_SECP256R1

/** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */
typedef struct {
Expand Down Expand Up @@ -454,15 +463,70 @@ int dtls_ecdh_pre_master_secret(unsigned char *priv_key,
unsigned char *result,
size_t result_len);

/**
* Generates the pre_master_sercet from given own private key @p
* priv_key and remote public key @p pub_key for the curve @p curve.
* This function returns the generated shared secret in @p result of
* size @p result_len. On success, the return value give the actual
* number of bytes written to @p result. The return @c 0 indicates
* an error.
*
* @param priv_key The own private key. The size of this key is
* defined by the selected @p curve and is passed
* in @p key_size.
* @param pub_key The remote public key. The size of this key is
* defined by the selected @p curve (usually twice
* @p key_size.
* @param key_size Length of @p priv_key in bytes.
* @param curve The elliptic curve to use.
* @param result The derived pre master secret.
* @param result_len The maximum length of the derived pre master secret.
* in @p result.
* @return The actual length of @p result or <= 0 on error.
*/
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);

void dtls_ecdsa_generate_key(unsigned char *priv_key,
unsigned char *pub_key_x,
unsigned char *pub_key_y,
size_t key_size);

/**
* Generates a key pair for the given curve @p curve and stores the
* private part in @p priv_key and the public part in @p pub_key. The
* storage that must be provided for @p priv_key and @p pub_key is
* determined by @p curve. Usually, @p pub_key requires 2 * @p
* key_size. This function returns the actual number of bytes written
* into @p priv_key on success, or @c 0 otherwise.
*
* @param priv_key Storage for the generated private key.
* @param pub_key Storage for the generated public key.
* @param key_size The amount of storage for @p priv_key.
* @param curve Storage for the generated public key.
* @return The number of bytes written into @p priv_key, or @c 0 on error.
*/
int dtls_ecdsa_generate_key2(unsigned char *priv_key,
unsigned char *pub_key,
size_t key_size,
dtls_ecdh_curve curve);

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]);

/**
* FIXME: document function
*/
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]);

void dtls_ecdsa_create_sig(const unsigned char *priv_key, size_t key_size,
const unsigned char *client_random, size_t client_random_size,
const unsigned char *server_random, size_t server_random_size,
Expand All @@ -474,6 +538,14 @@ int dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x,
const unsigned char *sign_hash, size_t sign_hash_size,
unsigned char *result_r, unsigned char *result_s);

/**
* FIXME: document function
*/
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);

int dtls_ecdsa_verify_sig(const unsigned char *pub_key_x,
const unsigned char *pub_key_y, size_t key_size,
const unsigned char *client_random, size_t client_random_size,
Expand Down

0 comments on commit 3dc62b1

Please sign in to comment.