From 64a941ba27e579edfa7c32c837f1a1204a25b25b Mon Sep 17 00:00:00 2001 From: Norman Ashley Date: Fri, 22 Sep 2023 12:00:43 -0400 Subject: [PATCH] Stateful sigs secret key storage callback (#1553) * Callback implemention updating secret key. * Block XMSS from secret key tests until after support code has been added. * Remove / from test file names * Format * Address SA issues * Fix mem leak * Fix mem leak * Address various comments * Fix SA issue --- src/sig_stfl/lms/sig_stfl_lms.c | 24 +- src/sig_stfl/lms/sig_stfl_lms.h | 9 +- src/sig_stfl/lms/sig_stfl_lms_functions.c | 79 ++++- src/sig_stfl/sig_stfl.c | 33 ++ src/sig_stfl/sig_stfl.h | 58 +++- src/sig_stfl/xmss/sig_stfl_xmss.h | 2 +- .../xmss/sig_stfl_xmss_secret_key_functions.c | 8 +- tests/test_sig_stfl.c | 281 ++++++++++++++---- 8 files changed, 404 insertions(+), 90 deletions(-) diff --git a/src/sig_stfl/lms/sig_stfl_lms.c b/src/sig_stfl/lms/sig_stfl_lms.c index 6ae6d1dde6..582b50b3e4 100644 --- a/src/sig_stfl/lms/sig_stfl_lms.c +++ b/src/sig_stfl/lms/sig_stfl_lms.c @@ -7,6 +7,14 @@ #include "sig_stfl_lms_wrap.h" #include "sig_stfl_lms.h" +/* Convert LMS secret key object to byte string */ +static OQS_STATUS OQS_SECRET_KEY_LMS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr); + +/* Insert lms byte string in an LMS secret key object */ +static OQS_STATUS OQS_SECRET_KEY_LMS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context); + +static void OQS_SECRET_KEY_LMS_set_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context); + // ======================== LMS-SHA256 H5/W1 ======================== // OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_sha256_h5_w1_keypair(uint8_t *public_key, OQS_SIG_STFL_SECRET_KEY *secret_key) { @@ -88,13 +96,15 @@ OQS_SIG_STFL_SECRET_KEY *OQS_SECRET_KEY_LMS_SHA256_H5_W1_new(void) { /* * Set Secret Key Saving Function */ - sk->save_secret_key = NULL; + sk->secure_store_scrt_key = NULL; /* * Set Secret Key free function */ sk->free_key = OQS_SECRET_KEY_LMS_free; + sk->set_scrt_key_store_cb = OQS_SECRET_KEY_LMS_set_store_cb; + return sk; } @@ -103,11 +113,17 @@ void OQS_SECRET_KEY_LMS_free(OQS_SIG_STFL_SECRET_KEY *sk) { } /* Convert LMS secret key object to byte string */ -OQS_STATUS OQS_SECRET_KEY_LMS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr) { +static OQS_STATUS OQS_SECRET_KEY_LMS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr) { return oqs_serialize_lms_key(sk, sk_len, sk_buf_ptr); } /* Insert lms byte string in an LMS secret key object */ -OQS_STATUS OQS_SECRET_KEY_LMS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf) { - return oqs_deserialize_lms_key(sk, sk_len, sk_buf); +static OQS_STATUS OQS_SECRET_KEY_LMS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context) { + return oqs_deserialize_lms_key(sk, sk_len, sk_buf, context); +} + +static void OQS_SECRET_KEY_LMS_set_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context) { + if (sk && store_cb && context) { + oqs_lms_key_set_store_cb(sk, store_cb, context); + } } diff --git a/src/sig_stfl/lms/sig_stfl_lms.h b/src/sig_stfl/lms/sig_stfl_lms.h index 76de39a6e3..75ce739238 100644 --- a/src/sig_stfl/lms/sig_stfl_lms.h +++ b/src/sig_stfl/lms/sig_stfl_lms.h @@ -14,12 +14,6 @@ OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_sha256_h5_w1_keypair(uint8_t *public_key OQS_SIG_STFL_SECRET_KEY *OQS_SECRET_KEY_LMS_SHA256_H5_W1_new(void); -/* Convert LMS secret key object to byte string */ -OQS_STATUS OQS_SECRET_KEY_LMS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr); - -/* Insert lms byte string in an LMS secret key object */ -OQS_STATUS OQS_SECRET_KEY_LMS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t key_len, const uint8_t *sk_buf); - OQS_SIG_STFL *OQS_SIG_STFL_alg_lms_sha256_h5_w1_new(void); OQS_API OQS_STATUS OQS_SIG_STFL_lms_sigs_left(unsigned long long *remain, const OQS_SIG_STFL_SECRET_KEY *secret_key); @@ -39,7 +33,8 @@ int oqs_sig_stfl_lms_verify(const uint8_t *m, size_t mlen, const uint8_t *sm, si void oqs_secret_lms_key_free(OQS_SIG_STFL_SECRET_KEY *sk); OQS_STATUS oqs_serialize_lms_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_key); -OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf); +OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context); +void oqs_lms_key_set_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context); // ---------------------------- FUNCTIONS INDEPENDENT OF VARIANT ----------------------------------------- diff --git a/src/sig_stfl/lms/sig_stfl_lms_functions.c b/src/sig_stfl/lms/sig_stfl_lms_functions.c index ea4f42d8af..d918cbdac4 100644 --- a/src/sig_stfl/lms/sig_stfl_lms_functions.c +++ b/src/sig_stfl/lms/sig_stfl_lms_functions.c @@ -40,25 +40,70 @@ typedef struct OQS_LMS_KEY_DATA { /* secret key data */ uint8_t *sec_key; + + /* app specific */ + void *context; } oqs_lms_key_data; OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_sign(uint8_t *signature, size_t *signature_length, const uint8_t *message, size_t message_len, OQS_SIG_STFL_SECRET_KEY *secret_key) { - if (secret_key == NULL || message == NULL || signature == NULL) { + OQS_STATUS rc_keyupdate = OQS_ERROR; + oqs_lms_key_data *lms_key_data = NULL; + const OQS_SIG_STFL_SECRET_KEY *sk; + uint8_t *sk_key_buf = NULL; + size_t sk_key_buf_len = 0; + void *context; + + if (secret_key == NULL || message == NULL || signature == NULL || signature_length == NULL) { return OQS_ERROR; } - /* TODO: Make sure we have a way to update the private key */ + /* + * Don't even attempt signing without a way to safe the updated private key + */ + if (secret_key->secure_store_scrt_key == NULL) { + goto err; + } + + lms_key_data = (oqs_lms_key_data *)secret_key->secret_key_data; + if (lms_key_data == NULL) { + goto err; + } if (oqs_sig_stfl_lms_sign(secret_key, signature, signature_length, message, message_len) != 0) { - return OQS_ERROR; + goto err; + } + + /* + * serialize and securely store the updated private key + * but, delete signature and the serialized key other wise + */ + + sk = secret_key; + rc_keyupdate = oqs_serialize_lms_key(sk, &sk_key_buf_len, &sk_key_buf); + if (rc_keyupdate != OQS_SUCCESS) { + goto err; + } + + context = lms_key_data->context; + rc_keyupdate = secret_key->secure_store_scrt_key(sk_key_buf, sk_key_buf_len, context); + if (rc_keyupdate != OQS_SUCCESS) { + goto err; } - /* TODO: Update private key */ + OQS_MEM_secure_free(sk_key_buf, sk_key_buf_len); return OQS_SUCCESS; + +err: + OQS_MEM_secure_free(sk_key_buf, sk_key_buf_len); + if (*signature_length) { + memset(signature, 0, *signature_length); + } + *signature_length = 0; + return OQS_ERROR; } OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_verify(const uint8_t *message, size_t message_len, @@ -356,11 +401,6 @@ void oqs_secret_lms_key_free(OQS_SIG_STFL_SECRET_KEY *sk) { //TODO: cleanup lock_key - if (sk->sig) { - OQS_MEM_insecure_free(sk->sig); - sk->sig = NULL; - } - if (sk->secret_key_data) { oqs_lms_key_data *key_data = (oqs_lms_key_data *)sk->secret_key_data; if (key_data) { @@ -426,7 +466,7 @@ OQS_STATUS oqs_serialize_lms_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_l * Writes secret key + aux data if present * key_len is priv key length + aux length */ -OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf) { +OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context) { oqs_lms_key_data *lms_key_data = NULL; uint8_t *lms_sk = NULL; @@ -451,11 +491,11 @@ OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_ param_set_t lm_ots_type[ MAX_HSS_LEVELS ]; // validate sk_buf for lms params - if (hss_get_parameter_set(&levels, - lm_type, - lm_ots_type, - NULL, - (void *)sk_buf)) { + if (!hss_get_parameter_set(&levels, + lm_type, + lm_ots_type, + NULL, + (void *)sk_buf)) { return OQS_ERROR; } @@ -469,6 +509,7 @@ OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_ memcpy(lms_sk, sk_buf, lms_sk_len); lms_key_data->sec_key = lms_sk; lms_key_data->len_sec_key = lms_sk_len; + lms_key_data->context = context; if (aux_buf_len) { lms_aux = malloc(aux_buf_len * sizeof(uint8_t)); @@ -494,3 +535,11 @@ OQS_STATUS oqs_deserialize_lms_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_ success: return OQS_SUCCESS; } + +void oqs_lms_key_set_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context) { + oqs_lms_key_data *lms_key_data = (oqs_lms_key_data *)sk->secret_key_data; + if (lms_key_data) { + lms_key_data->context = context; + sk->secure_store_scrt_key = store_cb; + } +} diff --git a/src/sig_stfl/sig_stfl.c b/src/sig_stfl/sig_stfl.c index c77139e20a..5480af5dd2 100644 --- a/src/sig_stfl/sig_stfl.c +++ b/src/sig_stfl/sig_stfl.c @@ -683,3 +683,36 @@ OQS_API void OQS_SIG_STFL_SECRET_KEY_free(OQS_SIG_STFL_SECRET_KEY *sk) { } OQS_MEM_secure_free(sk, sizeof(sk)); } + +OQS_API void OQS_SIG_STFL_SECRET_KEY_SET_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context) { + if (sk) { + if (sk->set_scrt_key_store_cb) { + sk->set_scrt_key_store_cb(sk, store_cb, context); + } + } +} + +/* Convert secret key object to byte string */ +OQS_API OQS_STATUS OQS_SECRET_KEY_STFL_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf) { + if ((sk == NULL) || (sk_len == NULL) || (sk_buf == NULL)) { + return 0; + } + if (sk->serialize_key) { + return sk->serialize_key(sk, sk_len, sk_buf); + } else { + return 0; + } +} + +/* Insert secret key byte string in an Stateful secret key object */ +OQS_API OQS_STATUS OQS_SECRET_KEY_STFL_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t key_len, const uint8_t *sk_buf, void *context) { + if ((sk == NULL) || (sk_buf == NULL)) { + return OQS_ERROR; + } + + if (sk->deserialize_key == NULL) { + return OQS_ERROR; + } + + return sk->deserialize_key(sk, key_len, sk_buf, context); +} diff --git a/src/sig_stfl/sig_stfl.h b/src/sig_stfl/sig_stfl.h index eb1b4088d5..1320ff02d3 100644 --- a/src/sig_stfl/sig_stfl.h +++ b/src/sig_stfl/sig_stfl.h @@ -61,6 +61,15 @@ extern "C" { typedef struct OQS_SIG_STFL_SECRET_KEY OQS_SIG_STFL_SECRET_KEY; +/** + * Application provided function to securely store data + * @param[in] sk_buf pointer to the data to be saved + * @param[in] buf_len length of the the data to be store + * @param[out] context pointer to application relevant data. + * @retrun OQS_SUCCESS if successful, otherwise OQS_ERROR + */ +typedef OQS_STATUS (*secure_store_sk)(/*const*/ uint8_t *sk_buf, size_t buf_len, void *context); + /** * Returns identifiers for available signature schemes in liboqs. Used with OQS_SIG_STFL_new. * @@ -216,13 +225,14 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { /** * set Secret Key to internal structure Function * - * @param[out] sk OQS_SIG_STFL_SECRET_KEY object - * @param[in] sk_len length of the returned byte string - * @param[in] sk_buf The secret key represented as OQS_SIG_STFL_SECRET_KEY object + * @param[in] sk OQS_SIG_STFL_SECRET_KEY object + * @param[in] key_len length of the returned byte string + * @param[in] sk_buf The secret key data to populate key obj + * @param[in] context application specific data * @returns status of the operation populated with key material none-zero length. Caller * deletes the buffer. if sk_buf is NULL the function returns the length */ - OQS_STATUS (*deserialize_key)(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf); + OQS_STATUS (*deserialize_key)(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context); /** * Secret Key Locking Function @@ -241,12 +251,16 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { OQS_STATUS (*unlock_key)(OQS_SIG_STFL_SECRET_KEY *sk); /** - * Secret Key Saving Function + * Store Secret Key Function + * Callback function used to securely store key data + * @param[in] sk_buf The serialized secret key data to secure store + * @param[in] buf_len length of data to secure + * @param[in] context aides the secure writing of data * - * @param[in] sk The secret key represented as OQS_SIG_STFL_SECRET_KEY object * @return OQS_SUCCESS or OQS_ERROR + * Idealy written to secure device */ - OQS_STATUS (*save_secret_key)(const OQS_SIG_STFL_SECRET_KEY *sk); + OQS_STATUS (*secure_store_scrt_key)(/*const*/ uint8_t *sk_buf, size_t buf_len, void *context); /** * Secret Key free internal variant specific data @@ -255,6 +269,15 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { * @return none */ void (*free_key)(OQS_SIG_STFL_SECRET_KEY *sk); + + /** + * Set Secret Key store callback Function + * + * @param[in] sk secret key pointer to be updated + * @param[in] store_cb callback pointer + * @param[in] context secret key specific data/identifier + */ + void (*set_scrt_key_store_cb)(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context); } OQS_SIG_STFL_SECRET_KEY; /** @@ -281,7 +304,7 @@ OQS_API OQS_SIG_STFL *OQS_SIG_STFL_new(const char *method_name); * @param[out] secret_key The secret key represented as a byte string. * @return OQS_SUCCESS or OQS_ERROR */ -OQS_API OQS_STATUS OQS_SIG_STFL_keypair(const OQS_SIG_STFL *sig, uint8_t *pk, OQS_SIG_STFL_SECRET_KEY *sk); +OQS_API OQS_STATUS OQS_SIG_STFL_keypair(const OQS_SIG_STFL *sig, uint8_t *public_key, OQS_SIG_STFL_SECRET_KEY *secret_key); /** * Signature generation algorithm. @@ -365,6 +388,25 @@ void OQS_SECRET_KEY_XMSS_free(OQS_SIG_STFL_SECRET_KEY *sk); */ OQS_API void OQS_SIG_STFL_SECRET_KEY_free(OQS_SIG_STFL_SECRET_KEY *sk); + +/** + * OQS_SIG_STFL_SECRET_KEY_SET_store_cb . + * + * Can be called after creating a new stateful secret key has been generated. + * Allows the lib to securely store and update secret key after a sign operation. + * + * @param[in] sk secret key pointer to be updated + * @param[in] store_cb callback pointer + * @param[in] context secret key specific data/identifier + * + */ +void OQS_SIG_STFL_SECRET_KEY_SET_store_cb(OQS_SIG_STFL_SECRET_KEY *sk, secure_store_sk store_cb, void *context); + +OQS_API OQS_STATUS OQS_SECRET_KEY_STFL_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf); + +/* Insert lms byte string in an LMS secret key object */ +OQS_API OQS_STATUS OQS_SECRET_KEY_STFL_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, size_t key_len, const uint8_t *sk_buf, void *context); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/src/sig_stfl/xmss/sig_stfl_xmss.h b/src/sig_stfl/xmss/sig_stfl_xmss.h index d0f6ae6300..54006043e1 100644 --- a/src/sig_stfl/xmss/sig_stfl_xmss.h +++ b/src/sig_stfl/xmss/sig_stfl_xmss.h @@ -501,6 +501,6 @@ OQS_API OQS_STATUS OQS_SIG_STFL_alg_xmssmt_shake128_h60_12_sigs_total(unsigned l OQS_STATUS OQS_SECRET_KEY_XMSS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr); /* Deserialize XMSS byte string into an XMSS secret key data */ -OQS_STATUS OQS_SECRET_KEY_XMSS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf); +OQS_STATUS OQS_SECRET_KEY_XMSS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, void *context); #endif /* OQS_SIG_STFL_XMSS_H */ diff --git a/src/sig_stfl/xmss/sig_stfl_xmss_secret_key_functions.c b/src/sig_stfl/xmss/sig_stfl_xmss_secret_key_functions.c index 9f50754ed2..4a47c938c3 100644 --- a/src/sig_stfl/xmss/sig_stfl_xmss_secret_key_functions.c +++ b/src/sig_stfl/xmss/sig_stfl_xmss_secret_key_functions.c @@ -4,6 +4,12 @@ #include #include "sig_stfl_xmss.h" +#if defined(__GNUC__) || defined(__clang__) +#define XMSS_UNUSED_ATT __attribute__((unused)) +#else +#define XMSS_UNUSED_ATT +#endif + /* Serialize XMSS secret key data into a byte string */ OQS_STATUS OQS_SECRET_KEY_XMSS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, size_t *sk_len, uint8_t **sk_buf_ptr) { if (sk == NULL || sk_len == NULL || sk_buf_ptr == NULL) { @@ -25,7 +31,7 @@ OQS_STATUS OQS_SECRET_KEY_XMSS_serialize_key(const OQS_SIG_STFL_SECRET_KEY *sk, } /* Deserialize XMSS byte string into an XMSS secret key data */ -OQS_STATUS OQS_SECRET_KEY_XMSS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf) { +OQS_STATUS OQS_SECRET_KEY_XMSS_deserialize_key(OQS_SIG_STFL_SECRET_KEY *sk, const size_t sk_len, const uint8_t *sk_buf, XMSS_UNUSED_ATT void *context) { if (sk == NULL || sk_buf == NULL || (sk_len != sk->length_secret_key)) { return OQS_ERROR; } diff --git a/tests/test_sig_stfl.c b/tests/test_sig_stfl.c index b496457b99..0a0f08cd4b 100644 --- a/tests/test_sig_stfl.c +++ b/tests/test_sig_stfl.c @@ -10,6 +10,7 @@ #include #include +#include "tmp_store.c" #if OQS_USE_PTHREADS_IN_TESTS #include @@ -32,6 +33,25 @@ */ #define MAX_MARKER_LEN 50 +/* + * Write stateful secret keys to disk. + */ +static OQS_STATUS test_save_secret_key(uint8_t *key_buf, size_t buf_len, void *context) { + uint8_t *kb = key_buf; + + if (key_buf && context && buf_len != 0) { + if (oqs_fstore("sk", (const char *)context, kb, buf_len) == OQS_SUCCESS) { + printf("\n================================================================================\n"); + printf("Updated STFL SK <%s>.\n", (const char *)context); + printf("================================================================================\n"); + return OQS_SUCCESS; + } else { + return OQS_ERROR; + } + } + return OQS_ERROR; +} + // // ALLOW TO READ HEXADECIMAL ENTRY (KEYS, DATA, TEXT, etc.) // @@ -126,6 +146,11 @@ int ReadHex(FILE *infile, unsigned char *a, unsigned long Length, char *str) { OQS_STATUS sig_stfl_keypair_from_keygen(OQS_SIG_STFL *sig, uint8_t *public_key, OQS_SIG_STFL_SECRET_KEY *secret_key) { OQS_STATUS rc; + + if ((sig == NULL) || (public_key == NULL) || (secret_key == NULL)) { + return OQS_ERROR; + } + rc = OQS_SIG_STFL_keypair(sig, public_key, secret_key); OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); if (rc != OQS_SUCCESS) { @@ -255,10 +280,20 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char OQS_SIG_STFL *sig = NULL; uint8_t *public_key = NULL; OQS_SIG_STFL_SECRET_KEY *secret_key = NULL; + const OQS_SIG_STFL_SECRET_KEY *sk = NULL; + OQS_SIG_STFL_SECRET_KEY *secret_key_rd = NULL; uint8_t *message = NULL; size_t message_len = 100; uint8_t *signature = NULL; size_t signature_len; + + uint8_t *sk_buf = NULL; + uint8_t *read_pk_buf = NULL; + char *context = NULL; + const char *file_store = NULL; + size_t sk_buf_len = 0; + size_t read_pk_len = 0; + OQS_STATUS rc, ret = OQS_ERROR; //The magic numbers are random values. @@ -277,6 +312,7 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char printf("================================================================================\n"); secret_key = OQS_SIG_STFL_SECRET_KEY_new(sig->method_name); + secret_key_rd = OQS_SIG_STFL_SECRET_KEY_new(sig->method_name); public_key = malloc(sig->length_public_key + 2 * sizeof(magic_t)); message = malloc(message_len + 2 * sizeof(magic_t)); signature = malloc(sig->length_signature + 2 * sizeof(magic_t)); @@ -307,12 +343,67 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char * Some keypair generation is fast, so we only read keypair from KATs for slow XMSS parameters */ rc = sig_stfl_KATs_keygen(sig, public_key, secret_key, katfile); + sk = secret_key; OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_SIG_STFL_keypair failed\n"); goto err; } + rc = OQS_SECRET_KEY_STFL_serialize_key(sk, &sk_buf_len, &sk_buf); + if (rc != OQS_SUCCESS) { + goto err; + } + + if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h20_2) == 0) { + file_store = "XMSSMT-SHA2_20-2_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h20_4) == 0) { + file_store = "XMSSMT-SHA2_20-4_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h40_2) == 0) { + file_store = "XMSSMT-SHA2_40-2_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h40_4) == 0) { + file_store = "XMSSMT-SHA2_40-4_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h40_8) == 0) { + file_store = "XMSSMT-SHA2_40-8_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h60_3) == 0) { + file_store = "XMSSMT-SHA2_60-3_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h60_6) == 0) { + file_store = "XMSSMT-SHA2_60-6_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h60_12) == 0) { + file_store = "XMSSMT-SHA2_60-12_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h20_2) == 0) { + file_store = "XMSSMT-SHAKE_20-2_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h20_4) == 0) { + file_store = "XMSSMT-SHAKE_20-4_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h40_2) == 0) { + file_store = "XMSSMT-SHAKE_40-2_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h40_4) == 0) { + file_store = "XMSSMT-SHAKE_40-4_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h40_8) == 0) { + file_store = "XMSSMT-SHAKE_40-8_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h60_3) == 0) { + file_store = "XMSSMT-SHAKE_60-3_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h60_6) == 0) { + file_store = "XMSSMT-SHAKE_60-6_256"; + } else if (strcmp(sig->method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h60_12) == 0) { + file_store = "XMSSMT-SHAKE_60-12_256"; + } else { + file_store = sig->method_name; + } + + /* write key pair to disk */ + if (oqs_fstore("sk", file_store, sk_buf, sk_buf_len) != OQS_SUCCESS) { + goto err; + } + + if (oqs_fstore("pk", file_store, public_key, sig->length_public_key) != OQS_SUCCESS) { + goto err; + } + + /* set context and secure store callback */ + context = strdup(((file_store))); + OQS_SIG_STFL_SECRET_KEY_SET_store_cb(secret_key, test_save_secret_key, (void *)context); + rc = OQS_SIG_STFL_sign(sig, signature, &signature_len, message, message_len, secret_key); OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); if (rc != OQS_SUCCESS) { @@ -329,6 +420,17 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char goto err; } + /* Read public key and re-test verify.*/ + read_pk_buf = malloc(sig->length_public_key); + if (oqs_fload("pk", file_store, read_pk_buf, sig->length_public_key, &read_pk_len) != OQS_SUCCESS) { + goto err; + } + rc = OQS_SIG_STFL_verify(sig, message, message_len, signature, signature_len, read_pk_buf); + OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: 2nd Verify with restored public key OQS_SIG_STFL_verify failed\n"); + } + /* modify the signature to invalidate it */ OQS_randombytes(signature, signature_len); OQS_TEST_CT_DECLASSIFY(signature, signature_len); @@ -362,6 +464,7 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char cleanup: OQS_SIG_STFL_SECRET_KEY_free(secret_key); + OQS_SIG_STFL_SECRET_KEY_free(secret_key_rd); if (public_key) { OQS_MEM_insecure_free(public_key - sizeof(magic_t)); } @@ -371,80 +474,97 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char if (signature) { OQS_MEM_insecure_free(signature - sizeof(magic_t)); } + OQS_MEM_secure_free(sk_buf, sk_buf_len); OQS_SIG_STFL_free(sig); + OQS_MEM_insecure_free(read_pk_buf); + OQS_MEM_insecure_free(context); return ret; } static OQS_STATUS sig_stfl_test_secret_key(const char *method_name) { OQS_STATUS rc = OQS_SUCCESS; OQS_SIG_STFL_SECRET_KEY *sk = NULL; + OQS_SIG_STFL_SECRET_KEY *sk_frm_file = NULL; OQS_SIG_STFL *sig_obj = NULL; uint8_t *public_key = NULL; + uint8_t *frm_file_sk_buf = NULL; + uint8_t *to_file_sk_buf = NULL; + size_t frm_file_sk_len = 0; + size_t to_file_sk_len = 0; + char *context = NULL; + char *context_2 = NULL; /* * Temporarily skip algs with long key generation times. */ - if (0) { - -#ifdef OQS_ENABLE_SIG_STFL_xmss_sha256_h16 - } else if (strcmp(method_name, OQS_SIG_STFL_alg_xmss_sha256_h16) == 0) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmss_sha256_h20 - } else if (strcmp(method_name, OQS_SIG_STFL_alg_xmss_sha256_h20) == 0) { - goto skip_test; -#endif - -#ifdef OQS_ENABLE_SIG_STFL_xmss_shake128_h16 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake128_h16)) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmss_shake128_h20 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake128_h20)) { - goto skip_test; -#endif - -#ifdef OQS_ENABLE_SIG_STFL_xmss_sha512_h16 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_sha512_h16)) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmss_sha512_h20 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_sha512_h20)) { + if (strcmp(method_name, OQS_SIG_STFL_alg_lms_sha256_n32_h5_w1) != 0) { goto skip_test; -#endif - -#ifdef OQS_ENABLE_SIG_STFL_xmss_shake256_h16 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake256_h16)) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmss_shake256_h20 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake256_h20)) { - goto skip_test; -#endif - -#ifdef OQS_ENABLE_SIG_STFL_xmssmt_sha256_h40_2 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h40_2)) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmssmt_sha256_h60_3 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h60_3)) { - goto skip_test; -#endif - -#ifdef OQS_ENABLE_SIG_STFL_xmssmt_shake128_h40_2 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h40_2)) { - goto skip_test; -#endif -#ifdef OQS_ENABLE_SIG_STFL_xmssmt_shake128_h60_3 - } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h60_3)) { - goto skip_test; -#endif } else { goto keep_going; } + +// if (0) { +// +//#ifdef OQS_ENABLE_SIG_STFL_xmss_sha256_h16 +// } else if (strcmp(method_name, OQS_SIG_STFL_alg_xmss_sha256_h16) == 0) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmss_sha256_h20 +// } else if (strcmp(method_name, OQS_SIG_STFL_alg_xmss_sha256_h20) == 0) { +// goto skip_test; +//#endif +// +//#ifdef OQS_ENABLE_SIG_STFL_xmss_shake128_h16 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake128_h16)) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmss_shake128_h20 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake128_h20)) { +// goto skip_test; +//#endif +// +//#ifdef OQS_ENABLE_SIG_STFL_xmss_sha512_h16 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_sha512_h16)) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmss_sha512_h20 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_sha512_h20)) { +// goto skip_test; +//#endif +// +//#ifdef OQS_ENABLE_SIG_STFL_xmss_shake256_h16 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake256_h16)) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmss_shake256_h20 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmss_shake256_h20)) { +// goto skip_test; +//#endif +// +//#ifdef OQS_ENABLE_SIG_STFL_xmssmt_sha256_h40_2 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h40_2)) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmssmt_sha256_h60_3 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_sha256_h60_3)) { +// goto skip_test; +//#endif +// +//#ifdef OQS_ENABLE_SIG_STFL_xmssmt_shake128_h40_2 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h40_2)) { +// goto skip_test; +//#endif +//#ifdef OQS_ENABLE_SIG_STFL_xmssmt_shake128_h60_3 +// } else if (0 == strcasecmp(method_name, OQS_SIG_STFL_alg_xmssmt_shake128_h60_3)) { +// goto skip_test; +//#endif +// } else { +// goto keep_going; +// } + skip_test: printf("Skip slow test %s.\n", method_name); return rc; @@ -479,12 +599,58 @@ static OQS_STATUS sig_stfl_test_secret_key(const char *method_name) { rc = OQS_SIG_STFL_keypair(sig_obj, public_key, sk); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "OQS STFL key gen failed.\n"); + goto err; + } + + /* write sk key to disk */ + rc = OQS_SECRET_KEY_STFL_serialize_key(sk, &to_file_sk_len, &to_file_sk_buf); + if (rc != OQS_SUCCESS) { + goto err; + } + + if (oqs_fstore("sk", sig_obj->method_name, to_file_sk_buf, to_file_sk_len) != OQS_SUCCESS) { + goto err; + } + if (!sk->secret_key_data) { fprintf(stderr, "ERROR: OQS_SECRET_KEY_new incomplete.\n"); OQS_MEM_insecure_free(public_key); goto err; } + /* set context and secure store callback */ + if (sk->set_scrt_key_store_cb) { + context = strdup(((method_name))); + sk->set_scrt_key_store_cb(sk, test_save_secret_key, (void *)context); + } + + + /* read secret key from disk */ + frm_file_sk_buf = malloc(to_file_sk_len); + if (oqs_fload("sk", method_name, frm_file_sk_buf, to_file_sk_len, &frm_file_sk_len) != OQS_SUCCESS) { + goto err; + } + if (to_file_sk_len != frm_file_sk_len) { + fprintf(stderr, "ERROR: OQS_SECRET_KEY_new stored length not equal read length\n"); + goto err; + } + + sk_frm_file = OQS_SIG_STFL_SECRET_KEY_new(method_name); + if (sk_frm_file == NULL) { + fprintf(stderr, "ERROR: 2nd OQS_SECRET_KEY_new failed\n"); + goto err; + } + + context_2 = strdup(((method_name))); + rc = OQS_SECRET_KEY_STFL_deserialize_key(sk_frm_file, frm_file_sk_len, frm_file_sk_buf, (void *)context_2); + + if (rc != OQS_SUCCESS) { + fprintf(stderr, "OQS restore %s from file failed.\n", method_name); + goto err; + } + printf("Secret Key created as expected.\n"); goto end_it; @@ -493,8 +659,14 @@ static OQS_STATUS sig_stfl_test_secret_key(const char *method_name) { end_it: OQS_SIG_STFL_SECRET_KEY_free(sk); + OQS_SIG_STFL_SECRET_KEY_free(sk_frm_file); + OQS_MEM_insecure_free(public_key); + OQS_MEM_secure_free(to_file_sk_buf, to_file_sk_len); + OQS_MEM_secure_free(frm_file_sk_buf, frm_file_sk_len); OQS_SIG_STFL_free(sig_obj); + OQS_MEM_insecure_free(context); + OQS_MEM_insecure_free(context_2); return rc; } @@ -531,6 +703,7 @@ void *test_wrapper(void *arg) { int main(int argc, char **argv) { OQS_init(); + oqs_fstore_init(); printf("Testing stateful signature algorithms using liboqs version %s\n", OQS_version());