aboutsummaryrefslogtreecommitdiff
path: root/ecdsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ecdsa.c')
-rw-r--r--ecdsa.c286
1 files changed, 148 insertions, 138 deletions
diff --git a/ecdsa.c b/ecdsa.c
index de382fd..429f05c 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -150,8 +150,8 @@ typedef struct {
} ec_point_t;
struct hal_ecdsa_key {
- hal_ecdsa_key_type_t type; /* Public or private is */
- hal_ecdsa_curve_t curve; /* Curve descriptor */
+ hal_key_type_t type; /* Public or private */
+ hal_curve_name_t curve; /* Curve descriptor */
ec_point_t Q[1]; /* Public key */
fp_int d[1]; /* Private key */
};
@@ -181,7 +181,7 @@ const size_t hal_ecdsa_key_t_size = sizeof(struct hal_ecdsa_key);
* first time anything asks for any of them.
*/
-static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve)
+static const ecdsa_curve_t * const get_curve(const hal_curve_name_t curve)
{
static ecdsa_curve_t curve_p256, curve_p384, curve_p521;
static int initialized = 0;
@@ -230,13 +230,29 @@ static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve)
}
switch (curve) {
- case HAL_ECDSA_CURVE_P256: return &curve_p256;
- case HAL_ECDSA_CURVE_P384: return &curve_p384;
- case HAL_ECDSA_CURVE_P521: return &curve_p521;
- default: return NULL;
+ case HAL_CURVE_P256: return &curve_p256;
+ case HAL_CURVE_P384: return &curve_p384;
+ case HAL_CURVE_P521: return &curve_p521;
+ default: return NULL;
}
}
+static inline const ecdsa_curve_t * oid_to_curve(hal_curve_name_t *curve_name,
+ const uint8_t * const oid,
+ const size_t oid_len)
+{
+ assert(curve_name != NULL && oid != NULL);
+
+ const ecdsa_curve_t *curve = NULL;
+ *curve_name = HAL_CURVE_NONE;
+
+ while ((curve = get_curve(++*curve_name)) != NULL)
+ if (oid_len == curve->oid_len && memcmp(oid, curve->oid, oid_len) == 0)
+ return curve;
+
+ return NULL;
+}
+
/*
* Finite field operations (hence "ff_"). These are basically just
* the usual bignum operations, constrained by the field modulus.
@@ -831,7 +847,7 @@ static int point_is_on_curve(const ec_point_t * const P,
hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
hal_ecdsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
- const hal_ecdsa_curve_t curve_)
+ const hal_curve_name_t curve_)
{
const ecdsa_curve_t * const curve = get_curve(curve_);
hal_ecdsa_key_t *key = keybuf;
@@ -842,7 +858,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
memset(keybuf, 0, keybuf_len);
- key->type = HAL_ECDSA_PRIVATE;
+ key->type = HAL_KEY_TYPE_EC_PRIVATE;
key->curve = curve_;
if ((err = point_pick_random(curve, key->d, key->Q)) != HAL_OK)
@@ -859,7 +875,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
*/
hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
- hal_ecdsa_key_type_t *key_type)
+ hal_key_type_t *key_type)
{
if (key == NULL || key_type == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -873,7 +889,7 @@ hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
*/
hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key,
- hal_ecdsa_curve_t *curve)
+ hal_curve_name_t *curve)
{
if (key == NULL || curve == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -929,7 +945,7 @@ void hal_ecdsa_key_clear(hal_ecdsa_key_t *key)
hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
- const hal_ecdsa_curve_t curve_,
+ const hal_curve_name_t curve_,
const uint8_t * const x, const size_t x_len,
const uint8_t * const y, const size_t y_len)
{
@@ -941,7 +957,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
memset(keybuf, 0, keybuf_len);
- key->type = HAL_ECDSA_PUBLIC;
+ key->type = HAL_KEY_TYPE_EC_PUBLIC;
key->curve = curve_;
fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(x), x_len);
@@ -966,7 +982,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
- const hal_ecdsa_curve_t curve_,
+ const hal_curve_name_t curve_,
const uint8_t * const x, const size_t x_len,
const uint8_t * const y, const size_t y_len,
const uint8_t * const d, const size_t d_len)
@@ -980,7 +996,7 @@ hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_,
if ((err = hal_ecdsa_key_load_public(key_, keybuf, keybuf_len, curve_, x, x_len, y, y_len)) != HAL_OK)
return err;
- key->type = HAL_ECDSA_PRIVATE;
+ key->type = HAL_KEY_TYPE_EC_PRIVATE;
fp_read_unsigned_bin(key->d, unconst_uint8_t(d), d_len);
return HAL_OK;
}
@@ -1052,7 +1068,7 @@ size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key)
hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len,
- const hal_ecdsa_curve_t curve)
+ const hal_curve_name_t curve)
{
hal_ecdsa_key_t *key = keybuf;
@@ -1060,7 +1076,7 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
return HAL_ERROR_BAD_ARGUMENTS;
memset(keybuf, 0, keybuf_len);
- key->type = HAL_ECDSA_PUBLIC;
+ key->type = HAL_KEY_TYPE_EC_PUBLIC;
key->curve = curve;
size_t hlen, vlen;
@@ -1103,10 +1119,10 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
* probably be using an ASN.1 compiler like asn1c instead.
*/
-hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
- uint8_t *der, size_t *der_len, const size_t der_max)
+hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
{
- if (key == NULL || key->type != HAL_ECDSA_PRIVATE)
+ if (key == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE)
return HAL_ERROR_BAD_ARGUMENTS;
const ecdsa_curve_t * const curve = get_curve(key->curve);
@@ -1192,10 +1208,10 @@ hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
* take if encoded as DER.
*/
-size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key)
+size_t hal_ecdsa_private_key_to_der_len(const hal_ecdsa_key_t * const key)
{
size_t len;
- return hal_ecdsa_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+ return hal_ecdsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
}
/*
@@ -1205,9 +1221,9 @@ size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key)
* probably be using an ASN.1 compiler like asn1c instead.
*/
-hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
- void *keybuf, const size_t keybuf_len,
- const uint8_t * const der, const size_t der_len)
+hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len)
{
hal_ecdsa_key_t *key = keybuf;
@@ -1215,7 +1231,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
return HAL_ERROR_BAD_ARGUMENTS;
memset(keybuf, 0, keybuf_len);
- key->type = HAL_ECDSA_PRIVATE;
+ key->type = HAL_KEY_TYPE_EC_PRIVATE;
size_t hlen, vlen;
hal_error_t err;
@@ -1248,10 +1264,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, vlen, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- for (key->curve = (hal_ecdsa_curve_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++)
- if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0)
- break;
- if (curve == NULL)
+ if ((curve = oid_to_curve(&key->curve, d, vlen)) == NULL)
lose(HAL_ERROR_ASN1_PARSE_FAILED);
d += vlen;
@@ -1284,6 +1297,104 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
}
/*
+ * Write public key in SubjectPublicKeyInfo format, see RFCS 5280 and 5480.
+ */
+
+static const uint8_t oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 };
+
+hal_error_t hal_ecdsa_public_key_to_der(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || (key->type != HAL_KEY_TYPE_EC_PRIVATE &&
+ key->type != HAL_KEY_TYPE_EC_PUBLIC))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const ecdsa_curve_t * const curve = get_curve(key->curve);
+ if (curve == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ const size_t q_len = fp_unsigned_bin_size(unconst_fp_int(curve->q));
+ const size_t Qx_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->x));
+ const size_t Qy_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->y));
+ const size_t ecpoint_len = q_len * 2 + 1;
+ assert(q_len >= Qx_len && q_len >= Qy_len);
+
+ if (der != NULL && ecpoint_len < der_max) {
+ memset(der, 0, ecpoint_len);
+
+ uint8_t *d = der;
+ *d++ = 0x04; /* Uncompressed */
+
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->x), d + q_len - Qx_len);
+ d += q_len;
+
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->y), d + q_len - Qy_len);
+ d += q_len;
+
+ assert(d < der + der_max);
+ }
+
+ return hal_asn1_encode_spki(oid_ecPublicKey, sizeof(oid_ecPublicKey),
+ curve->oid, curve->oid_len,
+ der, ecpoint_len,
+ der, der_len, der_max);
+}
+
+/*
+ * Convenience wrapper to return how many bytes a public key would
+ * take if encoded as DER.
+ */
+
+size_t hal_ecdsa_public_key_to_der_len(const hal_ecdsa_key_t * const key)
+{
+ size_t len;
+ return hal_ecdsa_public_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+/*
+ * Read public key in SubjectPublicKeyInfo format, see RFCS 5280 and 5480.
+ */
+
+hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len)
+{
+ hal_ecdsa_key_t *key = keybuf;
+
+ if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+ key->type = HAL_KEY_TYPE_EC_PUBLIC;
+
+ const uint8_t *alg_oid = NULL, *curve_oid = NULL, *pubkey = NULL;
+ size_t alg_oid_len, curve_oid_len, pubkey_len;
+ const ecdsa_curve_t *curve;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, &pubkey, &pubkey_len,
+ der, der_len)) != HAL_OK)
+ return err;
+
+ if (alg_oid == NULL || curve_oid == NULL || pubkey == NULL ||
+ alg_oid_len != sizeof(oid_ecPublicKey) || memcmp(alg_oid, oid_ecPublicKey, alg_oid_len) != 0 ||
+ (curve = oid_to_curve(&key->curve, curve_oid, curve_oid_len)) == NULL ||
+ pubkey_len < 3 || (pubkey_len & 1) == 0 || pubkey[0] != 0x04 ||
+ pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(curve->q)))
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ const uint8_t * const Qx = pubkey + 1;
+ const uint8_t * const Qy = Qx + pubkey_len / 2;
+
+ fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(Qx), pubkey_len / 2);
+ fp_read_unsigned_bin(key->Q->y, unconst_uint8_t(Qy), pubkey_len / 2);
+ fp_set(key->Q->z, 1);
+
+ *key_ = key;
+ return HAL_OK;
+}
+
+/*
* Encode a signature in PKCS #11 format: an octet string consisting
* of concatenated values for r and s, each padded (if necessary) out
* to the byte length of the order of the base point.
@@ -1345,89 +1456,15 @@ static hal_error_t decode_signature_pkcs11(const ecdsa_curve_t * const curve,
}
/*
- * Encode a signature in ASN.1 format SEQUENCE { INTEGER r, INTEGER s }.
- */
-
-static hal_error_t encode_signature_asn1(const ecdsa_curve_t * const curve,
- const fp_int * const r, const fp_int * const s,
- uint8_t *signature, size_t *signature_len, const size_t signature_max)
-{
- assert(curve != NULL && r != NULL && s != NULL);
-
- size_t hlen, r_len, s_len;
- hal_error_t err;
-
- if ((err = hal_asn1_encode_integer(r, NULL, &r_len, 0)) != HAL_OK ||
- (err = hal_asn1_encode_integer(s, NULL, &s_len, 0)) != HAL_OK)
- return err;
-
- const size_t vlen = r_len + s_len;
-
- err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, signature, &hlen, signature_max);
-
- if (signature_len != NULL)
- *signature_len = hlen + vlen;
-
- if (signature == NULL || err != HAL_OK)
- return err;
-
- uint8_t * const r_out = signature + hlen;
- uint8_t * const s_out = r_out + r_len;
-
- if ((err = hal_asn1_encode_integer(r, r_out, NULL, signature_max - (r_out - signature))) != HAL_OK ||
- (err = hal_asn1_encode_integer(s, s_out, NULL, signature_max - (s_out - signature))) != HAL_OK)
- return err;
-
- return HAL_OK;
-}
-
-/*
- * Decode a signature from ASN.1 format SEQUENCE { INTEGER r, INTEGER s }.
- */
-
-static hal_error_t decode_signature_asn1(const ecdsa_curve_t * const curve,
- fp_int *r, fp_int *s,
- const uint8_t * const signature, const size_t signature_len)
-{
- assert(curve != NULL && r != NULL && s != NULL);
-
- if (signature == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- size_t len1, len2;
- hal_error_t err;
-
- if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, signature, signature_len, &len1, &len2)) != HAL_OK)
- return err;
-
- const uint8_t * der = signature + len1;
- const uint8_t * const der_end = der + len2;
-
- if ((err = hal_asn1_decode_integer(r, der, &len1, der_end - der)) != HAL_OK)
- return err;
- der += len1;
-
- if ((err = hal_asn1_decode_integer(s, der, &len1, der_end - der)) != HAL_OK)
- return err;
- der += len1;
-
- if (der != der_end)
- return HAL_ERROR_ASN1_PARSE_FAILED;
-
- return HAL_OK;
-}
-
-/*
* Sign a caller-supplied hash.
*/
hal_error_t hal_ecdsa_sign(const hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
- uint8_t *signature, size_t *signature_len, const size_t signature_max,
- const hal_ecdsa_signature_format_t signature_format)
+ uint8_t *signature, size_t *signature_len, const size_t signature_max)
{
- if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_ECDSA_PRIVATE)
+ if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE)
return HAL_ERROR_BAD_ARGUMENTS;
const ecdsa_curve_t * const curve = get_curve(key->curve);
@@ -1487,21 +1524,8 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core,
* Encode the signature, then we're done.
*/
- switch (signature_format) {
-
- case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
- if ((err = encode_signature_asn1(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
- goto fail;
- break;
-
- case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
- if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
- goto fail;
- break;
-
- default:
- lose(HAL_ERROR_BAD_ARGUMENTS);
- }
+ if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
+ goto fail;
err = HAL_OK;
@@ -1518,8 +1542,7 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core,
hal_error_t hal_ecdsa_verify(const hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
- const uint8_t * const signature, const size_t signature_len,
- const hal_ecdsa_signature_format_t signature_format)
+ const uint8_t * const signature, const size_t signature_len)
{
assert(key != NULL && hash != NULL && signature != NULL);
@@ -1551,21 +1574,8 @@ hal_error_t hal_ecdsa_verify(const hal_core_t *core,
* Start by decoding the signature.
*/
- switch (signature_format) {
-
- case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
- if ((err = decode_signature_asn1(curve, r, s, signature, signature_len)) != HAL_OK)
- return err;
- break;
-
- case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
- if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK)
- return err;
- break;
-
- default:
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK)
+ return err;
/*
* Check that r and s are in the allowed range, read the hash, then