diff options
Diffstat (limited to 'ecdsa.c')
-rw-r--r-- | ecdsa.c | 290 |
1 files changed, 152 insertions, 138 deletions
@@ -83,6 +83,10 @@ #define HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM 0 #endif +#ifdef RPC_CLIENT +#define hal_get_random(core, buffer, length) hal_rpc_get_random(buffer, length) +#endif + /* * Whether we want debug output. */ @@ -150,8 +154,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 +185,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 +234,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 +851,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 +862,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 +879,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 +893,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 +949,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 +961,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 +986,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 +1000,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 +1072,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 +1080,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 +1123,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 +1212,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 +1225,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 +1235,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 +1268,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 +1301,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 +1460,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 +1528,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 +1546,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 +1578,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 |