aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2019-02-28 17:08:25 -0500
committerPaul Selkirk <paul@psgd.org>2019-03-04 21:32:15 -0500
commit5b2d3d25f46e8c2a306d77e8d7b2e00f1b67011f (patch)
tree2cb0fa650dedd9d4c2789dd598427b013e601d2f
parentffb543fed93541680a5d94010ea6b01210151eaa (diff)
Use the hashsig pseudorandom key generation method if the key is exportable.
-rw-r--r--hashsig.c58
-rw-r--r--hashsig.h3
-rw-r--r--rpc_pkey.c2
-rw-r--r--tests/test-rpc_hashsig.c12
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);
}
}
}