From 5b2d3d25f46e8c2a306d77e8d7b2e00f1b67011f Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Thu, 28 Feb 2019 17:08:25 -0500 Subject: Use the hashsig pseudorandom key generation method if the key is exportable. --- hashsig.c | 58 +++++++++++++++++++++++++++++++++++++++--------- hashsig.h | 3 ++- rpc_pkey.c | 2 +- tests/test-rpc_hashsig.c | 12 +++++++--- 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/hashsig.c b/hashsig.c index 9c48805..65a9a8b 100644 --- a/hashsig.c +++ b/hashsig.c @@ -48,7 +48,7 @@ typedef struct { uint8_t bytes[16]; } bytestring16; #define u32str(X) htonl(X) #define u16str(X) htons(X) -#define u8str(X) (X & 0xff) +#define u8str(X) ((X) & 0xff) #define check(op) do { hal_error_t _err = (op); if (_err != HAL_OK) return _err; } while (0) @@ -239,7 +239,7 @@ static inline size_t lmots_signature_len(lmots_parameter_t * const lmots) * public key components (x and K). * Let the caller worry about storage. */ -static hal_error_t lmots_generate(lmots_key_t * const key) +static hal_error_t lmots_generate(lmots_key_t * const key, bytestring32 *seed) { if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMOTS || key->lmots == NULL || key->x == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -252,13 +252,36 @@ static hal_error_t lmots_generate(lmots_key_t * const key) size_t p = key->lmots->p; size_t w = key->lmots->w; + if (seed == NULL) { // 4. compute the array x as follows: // for ( i = 0; i < p; i = i + 1 ) { // set x[i] to a uniformly random n-byte string // } - for (size_t i = 0; i < p; ++i) - check(hal_rpc_get_random(&key->x[i], n)); + for (size_t i = 0; i < p; ++i) + check(hal_rpc_get_random(&key->x[i], n)); + } + + else { + for (size_t i = 0; i < p; ++i) { +// Appendix A. Pseudorandom Key Generation +// x_q[i] = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED) + + uint8_t statebuf[512]; + hal_hash_state_t *state = NULL; + uint32_t l; + uint16_t s; + uint8_t b; + + check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf))); + check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I))); + l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l))); + s = u16str(i); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s))); + b = u8str(0xff); check(hal_hash_update(state, (const uint8_t *)&b, sizeof(b))); + check(hal_hash_update(state, (const uint8_t *)seed, sizeof(bytestring32))); + check(hal_hash_finalize(state, (uint8_t *)&key->x[i], sizeof(bytestring32))); + } + } // Algorithm 1: Generating a One Time Signature Public Key From a // Private Key @@ -711,7 +734,7 @@ static inline size_t lms_signature_len(lms_parameter_t * const lms, lmots_parame * public key components. * Let the caller worry about storage. */ -static hal_error_t lms_generate(lms_key_t *key) +static hal_error_t lms_generate(lms_key_t *key, bytestring32 *seed) { if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMS || key->lms == NULL || key->lmots == NULL || key->lmots_keys == NULL || key->T == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -744,7 +767,7 @@ static hal_error_t lms_generate(lms_key_t *key) for (size_t q = 0; q < h2; ++q) { /* generate the lmots private and public key components */ lmots_key.q = q; - check(lmots_generate(&lmots_key)); + check(lmots_generate(&lmots_key, seed)); /* store the lmots key */ uint8_t der[lmots_private_key_to_der_len(&lmots_key)]; @@ -1189,6 +1212,7 @@ struct hal_hashsig_key { lmots_parameter_t *lmots; bytestring16 I; bytestring32 T1; + bytestring32 seed; lms_key_t *lms_keys; }; @@ -1336,7 +1360,8 @@ hal_error_t hal_hashsig_key_gen(hal_core_t *core, hal_hashsig_key_t **key_, const size_t L, const hal_lms_algorithm_t lms_type, - const hal_lmots_algorithm_t lmots_type) + const hal_lmots_algorithm_t lmots_type, + const hal_key_flags_t flags) { /* hss_alloc does most of the checks */ @@ -1359,7 +1384,17 @@ hal_error_t hal_hashsig_key_gen(hal_core_t *core, for (size_t i = 0; i < L; ++i) { lms_key_t * lms_key = &key->lms_keys[i]; - check(lms_generate(lms_key)); + if (flags & HAL_KEY_FLAG_EXPORTABLE && i == 0) { + bytestring32 *seed = &key->seed; + check(hal_rpc_get_random(seed, sizeof(*seed))); + check(lms_generate(lms_key, seed)); + } + else { + /* hss_alloc zeroes out the allocation, so we know seed == {0} + * for later use (store/restore) + */ + check(lms_generate(lms_key, NULL)); + } if (i > 0) /* sign this tree with the previous */ @@ -1467,7 +1502,7 @@ hal_error_t hal_hashsig_sign(hal_core_t *core, * any additional memory. */ check(lms_delete(lms_key)); - check(lms_generate(lms_key)); + check(lms_generate(lms_key, NULL)); check(lms_sign(&key->lms_keys[d-1], (const uint8_t * const)lms_key->pubkey, lms_key->pubkey_len, lms_key->signature, NULL, lms_key->signature_len)); @@ -1623,6 +1658,7 @@ hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key, check(hal_asn1_encode_lmots_algorithm(key->lmots->type, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_bytestring16(&key->I, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_bytestring32(&key->T1, NULL, &len, 0)); vlen += len; + check(hal_asn1_encode_bytestring32(&key->seed, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0)); @@ -1646,6 +1682,7 @@ hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key, check(hal_asn1_encode_lmots_algorithm(key->lmots->type, d, &len, vlen)); d += len; vlen -= len; check(hal_asn1_encode_bytestring16(&key->I, d, &len, vlen)); d += len; vlen -= len; check(hal_asn1_encode_bytestring32(&key->T1, d, &len, vlen)); d += len; vlen -= len; + check(hal_asn1_encode_bytestring32(&key->seed, d, &len, vlen)); d += len; vlen -= len; return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len, NULL, 0, der, d - der, der, der_len, der_max); @@ -1700,6 +1737,7 @@ hal_error_t hal_hashsig_private_key_from_der(hal_hashsig_key_t **key_, key->lmots = lmots_select_parameter_set(lmots_type); check(hal_asn1_decode_bytestring16(&key->I, d, &n, vlen)); d += n; vlen -= n; check(hal_asn1_decode_bytestring32(&key->T1, d, &n, vlen)); d += n; vlen -= n; + check(hal_asn1_decode_bytestring32(&key->seed, d, &n, vlen)); d += n; vlen -= n; if (d != privkey + privkey_len) return HAL_ERROR_ASN1_PARSE_FAILED; @@ -2108,7 +2146,7 @@ hal_error_t hal_hashsig_ks_init(void) /* generate the lower-level lms keys */ for (size_t i = 1; i < hss_key->L; ++i) { lms_key_t * lms_key = &hss_key->lms_keys[i]; - if (lms_generate(lms_key) != HAL_OK) + if (lms_generate(lms_key, NULL) != HAL_OK) goto fail; /* store the lms key */ diff --git a/hashsig.h b/hashsig.h index ef8be42..505d0f3 100644 --- a/hashsig.h +++ b/hashsig.h @@ -43,7 +43,8 @@ extern hal_error_t hal_hashsig_key_gen(hal_core_t *core, hal_hashsig_key_t **key_, const size_t hss_levels, const hal_lms_algorithm_t lms_type, - const hal_lmots_algorithm_t lmots_type); + const hal_lmots_algorithm_t lmots_type, + const hal_key_flags_t flags); extern hal_error_t hal_hashsig_key_delete(const hal_hashsig_key_t * const key); diff --git a/rpc_pkey.c b/rpc_pkey.c index fe80a90..138dd73 100644 --- a/rpc_pkey.c +++ b/rpc_pkey.c @@ -555,7 +555,7 @@ static hal_error_t pkey_local_generate_hashsig(const hal_client_handle_t client, slot->curve = HAL_CURVE_NONE; slot->flags = flags; - if ((err = hal_hashsig_key_gen(NULL, &key, hss_levels, lms_type, lmots_type)) != HAL_OK) { + if ((err = hal_hashsig_key_gen(NULL, &key, hss_levels, lms_type, lmots_type, flags)) != HAL_OK) { slot->type = HAL_KEY_TYPE_NONE; return err; } diff --git a/tests/test-rpc_hashsig.c b/tests/test-rpc_hashsig.c index 8b9e509..2de5dfb 100644 --- a/tests/test-rpc_hashsig.c +++ b/tests/test-rpc_hashsig.c @@ -261,6 +261,7 @@ static hal_error_t dump_hss_signature(const uint8_t * const sig, const size_t le static int test_hashsig_sign(const size_t L, const hal_lms_algorithm_t lms_type, const hal_lmots_algorithm_t lmots_type, + hal_key_flags_t flags, size_t iterations, int save, int keep) { @@ -285,7 +286,7 @@ static int test_hashsig_sign(const size_t L, lose("Error closing %s: %s\n", save_name, strerror(errno)); } - hal_key_flags_t flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN; + flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN; printf("Starting hashsig key test: L %lu, lms type %u (h=%lu), lmots type %u (w=%lu)\n", L, lms_type, lms_type_to_h(lms_type), lmots_type, lmots_type_to_w(lmots_type)); @@ -461,6 +462,7 @@ int main(int argc, char *argv[]) size_t lms_lo = 5, lms_hi = 0; size_t lmots_lo = 3, lmots_hi = 0; int save = 0, keep = 0; + hal_key_flags_t flags = 0; char *p; hal_error_t err; int ok = 1; @@ -478,10 +480,11 @@ Usage: %s [-d] [-i] [-p pin] [-t] [-L n] [-l n] [-o n] [-n n] [-s] [-r file]\n\ -s: save generated public key and signatures\n\ -k: keep (don't delete) the generated keys on the hsm\n\ -r: read and pretty-print a saved signature file\n\ + -x: mark key as exportable\n\ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; int opt; - while ((opt = getopt(argc, argv, "ditp:L:l:o:n:skr:h?")) != -1) { + while ((opt = getopt(argc, argv, "ditp:L:l:o:n:skr:xh?")) != -1) { switch (opt) { case 'd': debug = 1; @@ -534,6 +537,9 @@ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; ok &= read_sig(optarg); do_default = 0; break; + case 'x': + flags = HAL_KEY_FLAG_EXPORTABLE; + break; case 'h': case '?': fprintf(stdout, usage, argv[0]); @@ -576,7 +582,7 @@ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; for (size_t L = L_lo; L <= L_hi; ++L) { for (hal_lms_algorithm_t lms_type = lms_lo; lms_type <= lms_hi; ++lms_type) { for (hal_lmots_algorithm_t lmots_type = lmots_lo; lmots_type <= lmots_hi; ++lmots_type) { - ok &= test_hashsig_sign(L, lms_type, lmots_type, iterations, save, keep); + ok &= test_hashsig_sign(L, lms_type, lmots_type, flags, iterations, save, keep); } } } -- cgit v1.2.3