From d687e6cf5a868d83e34bb2563f960627fe7c5758 Mon Sep 17 00:00:00 2001 From: Norman Ashley Date: Thu, 28 Sep 2023 13:30:50 -0400 Subject: [PATCH] Na statful sig lock (#1559) * Add mutex protection around access to stateful secret key * Formatting. * Clean up warnings * Exclude XMSS from some tests temporarily * Remove commented code. * Document use of callback functions for secret key thread safe protection and storage. --- src/sig_stfl/lms/sig_stfl_lms.c | 12 +- src/sig_stfl/lms/sig_stfl_lms_functions.c | 31 +- src/sig_stfl/sig_stfl.c | 49 +++ src/sig_stfl/sig_stfl.h | 110 +++++- tests/test_sig_stfl.c | 386 +++++++++++++++++++++- 5 files changed, 572 insertions(+), 16 deletions(-) diff --git a/src/sig_stfl/lms/sig_stfl_lms.c b/src/sig_stfl/lms/sig_stfl_lms.c index 582b50b3e4..e6c30e66d5 100644 --- a/src/sig_stfl/lms/sig_stfl_lms.c +++ b/src/sig_stfl/lms/sig_stfl_lms.c @@ -114,7 +114,17 @@ void OQS_SECRET_KEY_LMS_free(OQS_SIG_STFL_SECRET_KEY *sk) { /* 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) { - return oqs_serialize_lms_key(sk, sk_len, sk_buf_ptr); + OQS_STATUS status; + if (sk->lock_key && sk->mutex) { + sk->lock_key(sk->mutex); + } + + status = oqs_serialize_lms_key(sk, sk_len, sk_buf_ptr); + + if (sk->unlock_key && sk->mutex) { + sk->unlock_key(sk->mutex); + } + return status; } /* Insert lms byte string in an LMS secret key object */ diff --git a/src/sig_stfl/lms/sig_stfl_lms_functions.c b/src/sig_stfl/lms/sig_stfl_lms_functions.c index d918cbdac4..59265f3110 100644 --- a/src/sig_stfl/lms/sig_stfl_lms_functions.c +++ b/src/sig_stfl/lms/sig_stfl_lms_functions.c @@ -47,7 +47,7 @@ typedef struct 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) { - + OQS_STATUS status = OQS_ERROR; OQS_STATUS rc_keyupdate = OQS_ERROR; oqs_lms_key_data *lms_key_data = NULL; const OQS_SIG_STFL_SECRET_KEY *sk; @@ -59,6 +59,11 @@ OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_sign(uint8_t *signature, size_t *signatu return OQS_ERROR; } + /* Lock secret to ensure OTS use */ + if ((secret_key->lock_key) && (secret_key->mutex)) { + secret_key->lock_key(secret_key->mutex); + } + /* * Don't even attempt signing without a way to safe the updated private key */ @@ -94,16 +99,23 @@ OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_sign(uint8_t *signature, size_t *signatu goto err; } - OQS_MEM_secure_free(sk_key_buf, sk_key_buf_len); - return OQS_SUCCESS; + status = OQS_SUCCESS; + goto passed; 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; + +passed: + OQS_MEM_secure_free(sk_key_buf, sk_key_buf_len); + + /* Unlock secret to ensure OTS use */ + if ((secret_key->unlock_key) && (secret_key->mutex)) { + secret_key->unlock_key(secret_key->mutex); + } + return status; } OQS_API OQS_STATUS OQS_SIG_STFL_alg_lms_verify(const uint8_t *message, size_t message_len, @@ -128,8 +140,17 @@ OQS_API OQS_STATUS OQS_SIG_STFL_lms_sigs_left(unsigned long long *remain, const if (remain == NULL || secret_key == NULL) { return OQS_ERROR; } + /* Lock secret key to ensure data integrity use */ + if ((secret_key->lock_key) && (secret_key->mutex)) { + secret_key->lock_key(secret_key->mutex); + } remain = 0; + + /* Unlock secret key */ + if ((secret_key->unlock_key) && (secret_key->mutex)) { + secret_key->unlock_key(secret_key->mutex); + } return OQS_SUCCESS; } diff --git a/src/sig_stfl/sig_stfl.c b/src/sig_stfl/sig_stfl.c index 5480af5dd2..023d4e1df3 100644 --- a/src/sig_stfl/sig_stfl.c +++ b/src/sig_stfl/sig_stfl.c @@ -716,3 +716,52 @@ OQS_API OQS_STATUS OQS_SECRET_KEY_STFL_deserialize_key(OQS_SIG_STFL_SECRET_KEY * return sk->deserialize_key(sk, key_len, sk_buf, context); } + + + +/* OQS_SIG_STFL_SECRET_KEY_SET_lock callback function*/ +OQS_API void OQS_SIG_STFL_SECRET_KEY_SET_lock(OQS_SIG_STFL_SECRET_KEY *sk, lock_key lock) { + if (sk == NULL) { + return; + } + sk->lock_key = lock; +} + +/* OQS_SIG_STFL_SECRET_KEY_SET_unlock callback function */ +OQS_API void OQS_SIG_STFL_SECRET_KEY_SET_unlock(OQS_SIG_STFL_SECRET_KEY *sk, unlock_key unlock) { + if (sk == NULL) { + return; + } + sk->unlock_key = unlock; +} + +/* OQS_SIG_STFL_SECRET_KEY_SET_mutex */ +OQS_API void OQS_SIG_STFL_SECRET_KEY_SET_mutex(OQS_SIG_STFL_SECRET_KEY *sk, void *mutex) { + if (sk == NULL) { + return; + } + sk->mutex = mutex; +} + +/* OQS_SIG_STFL_SECRET_KEY_lock */ +OQS_API OQS_STATUS OQS_SIG_STFL_SECRET_KEY_lock(OQS_SIG_STFL_SECRET_KEY *sk) { + if (sk == NULL) { + return OQS_ERROR; + } + if (sk->lock_key == NULL) { + return OQS_SUCCESS; + } + + return (sk->lock_key(sk->mutex)); +} + +/* OQS_SIG_STFL_SECRET_KEY_unlock */ +OQS_API OQS_STATUS OQS_SIG_STFL_SECRET_KEY_unlock(OQS_SIG_STFL_SECRET_KEY *sk) { + if (sk == NULL) { + return OQS_ERROR; + } + if (sk->unlock_key == NULL) { + return OQS_SUCCESS; + } + return (sk->unlock_key(sk->mutex)); +} diff --git a/src/sig_stfl/sig_stfl.h b/src/sig_stfl/sig_stfl.h index 1320ff02d3..a9bffdfdd8 100644 --- a/src/sig_stfl/sig_stfl.h +++ b/src/sig_stfl/sig_stfl.h @@ -16,6 +16,29 @@ #include +/* + * Developer's Notes: + * Stateful signatures are based on one-time use of a secret key. A pool of secret keys are created for this purpose. + * The state of these keys are tracked to ensure that they are used only once to generate a signature. + * + * As such, product specific environments do play a role in ensuring the safety of the keys. + * Secret keys must be store securely. + * The key index/counter must be updated after each signature generation. + * Secret key must be protected in a thread-save manner. + * + * Application therefore are required to provide environment specific callback functions to + * - store private key + * - lock/unlock private key + * + * See below for details + * OQS_SIG_STFL_SECRET_KEY_SET_lock + * OQS_SIG_STFL_SECRET_KEY_SET_unlock + * OQS_SIG_STFL_SECRET_KEY_SET_mutex + * OQS_SIG_STFL_SECRET_KEY_SET_store_cb + * + */ + + #if defined(__cplusplus) extern "C" { #endif @@ -66,9 +89,25 @@ typedef struct OQS_SIG_STFL_SECRET_KEY OQS_SIG_STFL_SECRET_KEY; * @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 + * return OQS_SUCCESS if successful, otherwise OQS_ERROR + */ +typedef OQS_STATUS (*secure_store_sk)(uint8_t *sk_buf, size_t buf_len, void *context); + +/** + * Application provided function to lock secret key object serialize access + * @param[in] sk pointer to secret key object to lock + * @param[in] mutex pointer to mutex struct + * return OQS_SUCCESS if successful, otherwise OQS_ERROR + */ +typedef OQS_STATUS (*lock_key)(void *mutex); + +/** + * Application provided function to unlock secret key object + * @param[in] sk pointer to secret key object to unlock + * @param[in] mutex pointer to mutex struct + * return OQS_SUCCESS if successful, otherwise OQS_ERROR */ -typedef OQS_STATUS (*secure_store_sk)(/*const*/ uint8_t *sk_buf, size_t buf_len, void *context); +typedef OQS_STATUS (*unlock_key)(void *mutex); /** * Returns identifiers for available signature schemes in liboqs. Used with OQS_SIG_STFL_new. @@ -205,6 +244,9 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { /* The variant specific secret key data */ void *secret_key_data; + /* mutual exclusion struct */ + void *mutex; + /* Function that returns the total number of signatures for the secret key */ uint64_t (*sigs_total)(const OQS_SIG_STFL_SECRET_KEY *secret_key); @@ -237,18 +279,18 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { /** * Secret Key Locking Function * - * @param[in] sk The secret key represented as OQS_SIG_STFL_SECRET_KEY object + * @param[in] mutex application defined mutex * @return OQS_SUCCESS or OQS_ERROR */ - OQS_STATUS (*lock_key)(OQS_SIG_STFL_SECRET_KEY *sk); + OQS_STATUS (*lock_key)(void *mutex); /** * Secret Key Unlocking / Releasing Function * - * @param[in] sk The secret key represented as OQS_SIG_STFL_SECRET_KEY object + * @param[in] mutex application defined mutex * @return OQS_SUCCESS or OQS_ERROR */ - OQS_STATUS (*unlock_key)(OQS_SIG_STFL_SECRET_KEY *sk); + OQS_STATUS (*unlock_key)(void *mutex); /** * Store Secret Key Function @@ -260,7 +302,7 @@ typedef struct OQS_SIG_STFL_SECRET_KEY { * @return OQS_SUCCESS or OQS_ERROR * Idealy written to secure device */ - OQS_STATUS (*secure_store_scrt_key)(/*const*/ uint8_t *sk_buf, size_t buf_len, void *context); + OQS_STATUS (*secure_store_scrt_key)(uint8_t *sk_buf, size_t buf_len, void *context); /** * Secret Key free internal variant specific data @@ -388,6 +430,60 @@ 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_lock . + * + * Sets function to prevent multiple processes from using the sk at the same time. + * + * @param[in] sk secret key pointer to be updated + * @param[in] lock function pointer + * + */ +void OQS_SIG_STFL_SECRET_KEY_SET_lock(OQS_SIG_STFL_SECRET_KEY *sk, lock_key lock); + +/** + * OQS_SIG_STFL_SECRET_KEY_SET_unlock . + * + * Sets function to prevent multiple processes from using the sk at the same time. + * + * @param[in] sk secret key pointer to be updated + * @param[in] unlock function pointer + * + */ +void OQS_SIG_STFL_SECRET_KEY_SET_unlock(OQS_SIG_STFL_SECRET_KEY *sk, unlock_key unlock); + +/** + * OQS_SIG_STFL_SECRET_KEY_SET_mutex . + * + * Sets function to prevent multiple processes from using the sk at the same time. + * + * @param[in] sk secret key pointer to be updated + * @param[in] mutex function pointer + * + */ +void OQS_SIG_STFL_SECRET_KEY_SET_mutex(OQS_SIG_STFL_SECRET_KEY *sk, void *mutex); + +/** + * OQS_SIG_STFL_SECRET_KEY_lock . + * + * Locks sk so only one application that holds the lock can access it. + * + * @param[in] sk secret key pointer to be locked + * @return OQS_SUCCESS if successful, or OQS_ERROR if the object fails to apply the lock + * + */ +OQS_STATUS OQS_SIG_STFL_SECRET_KEY_lock(OQS_SIG_STFL_SECRET_KEY *sk); + +/** + * OQS_SIG_STFL_SECRET_KEY_unlock . + * + * Unlocks the resouces so that th enext process can access it. + * + * @param[in] sk secret key pointer + * @return OQS_SUCCESS if successful, or OQS_ERROR if the object fails to release the lock + * + */ +OQS_STATUS OQS_SIG_STFL_SECRET_KEY_unlock(OQS_SIG_STFL_SECRET_KEY *sk); /** * OQS_SIG_STFL_SECRET_KEY_SET_store_cb . diff --git a/tests/test_sig_stfl.c b/tests/test_sig_stfl.c index 0a0f08cd4b..8a3cb2252d 100644 --- a/tests/test_sig_stfl.c +++ b/tests/test_sig_stfl.c @@ -9,6 +9,9 @@ #include #include +#include +#include + #include #include "tmp_store.c" @@ -33,6 +36,18 @@ */ #define MAX_MARKER_LEN 50 +static OQS_SIG_STFL_SECRET_KEY *lock_test_sk = NULL; +static OQS_SIG_STFL *lock_test_sig_obj = NULL; +static uint8_t *lock_test_public_key = NULL; +static char *lock_test_context = NULL; +static uint8_t *signature_1 = NULL; +static uint8_t *signature_2 = NULL; +static size_t signature_len_1; +static size_t signature_len_2; +static uint8_t message_1[] = "The quick brown fox ..."; +static uint8_t message_2[] = "The quick brown fox jumped from the tree."; +static pthread_mutex_t *test_sk_lock = NULL; + /* * Write stateful secret keys to disk. */ @@ -52,6 +67,38 @@ static OQS_STATUS test_save_secret_key(uint8_t *key_buf, size_t buf_len, void *c return OQS_ERROR; } +#if OQS_USE_PTHREADS_IN_TESTS +static OQS_STATUS lock_sk_key(void *mutex) { + if (mutex == NULL) { + return OQS_ERROR; + } + + if (!(pthread_mutex_lock((pthread_mutex_t *)mutex))) { + return OQS_SUCCESS; + } + return OQS_ERROR; +} + +static OQS_STATUS unlock_sk_key(void *mutex) { + if (mutex == NULL) { + return OQS_ERROR; + } + + if (!(pthread_mutex_unlock((pthread_mutex_t *)mutex))) { + return OQS_SUCCESS; + } + return OQS_ERROR; +} +#else +static OQS_STATUS lock_sk_key(void *mutex) { + return sk != NULL ? OQS_SUCCESS : OQS_ERROR; +} + +static OQS_STATUS unlock_sk_key(void *mutex) { + return sk != NULL ? OQS_SUCCESS : OQS_ERROR; +} +#endif + // // ALLOW TO READ HEXADECIMAL ENTRY (KEYS, DATA, TEXT, etc.) // @@ -294,6 +341,10 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char size_t sk_buf_len = 0; size_t read_pk_len = 0; +#if OQS_USE_PTHREADS_IN_TESTS + pthread_mutex_t *sk_lock = NULL; +#endif + OQS_STATUS rc, ret = OQS_ERROR; //The magic numbers are random values. @@ -313,6 +364,21 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char secret_key = OQS_SIG_STFL_SECRET_KEY_new(sig->method_name); secret_key_rd = OQS_SIG_STFL_SECRET_KEY_new(sig->method_name); + + OQS_SIG_STFL_SECRET_KEY_SET_lock(secret_key, lock_sk_key); + OQS_SIG_STFL_SECRET_KEY_SET_unlock(secret_key, unlock_sk_key); + +#if OQS_USE_PTHREADS_IN_TESTS + sk_lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + if (sk_lock == NULL) { + goto err; + } + + if (0 != pthread_mutex_init(sk_lock, 0)) { + goto err; + } + OQS_SIG_STFL_SECRET_KEY_SET_mutex(secret_key, sk_lock); +#endif 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)); @@ -479,6 +545,13 @@ static OQS_STATUS sig_stfl_test_correctness(const char *method_name, const char OQS_MEM_insecure_free(read_pk_buf); OQS_MEM_insecure_free(context); + +#if OQS_USE_PTHREADS_IN_TESTS + if (sk_lock) { + pthread_mutex_destroy(sk_lock); + OQS_MEM_insecure_free(sk_lock); + } +#endif return ret; } @@ -616,7 +689,6 @@ static OQS_STATUS sig_stfl_test_secret_key(const char *method_name) { if (!sk->secret_key_data) { fprintf(stderr, "ERROR: OQS_SECRET_KEY_new incomplete.\n"); - OQS_MEM_insecure_free(public_key); goto err; } @@ -670,10 +742,240 @@ static OQS_STATUS sig_stfl_test_secret_key(const char *method_name) { return rc; } +static OQS_STATUS sig_stfl_test_query_key(const char *method_name) { + OQS_STATUS rc = OQS_SUCCESS; + + size_t message_len_1 = sizeof(message_1); + size_t message_len_2 = sizeof(message_2); + + /* + * Temporarily skip algs with long key generation times. + */ + + if (strcmp(method_name, OQS_SIG_STFL_alg_lms_sha256_n32_h5_w1) != 0) { + goto skip_test; + } else { + goto keep_going; + } + +skip_test: + printf("Skip slow alg %s.\n", method_name); + return rc; + +keep_going: + + printf("================================================================================\n"); + printf("Testing stateful Signature Verification %s\n", method_name); + printf("================================================================================\n"); + + if ( lock_test_sk == NULL || lock_test_sig_obj == NULL || signature_1 == NULL + || signature_2 == NULL || lock_test_public_key == NULL) { + return OQS_ERROR; + } + + + printf("================================================================================\n"); + printf("Sig Verify 1 %s\n", method_name); + printf("================================================================================\n"); + + rc = OQS_SIG_STFL_verify(lock_test_sig_obj, message_1, message_len_1, signature_1, signature_len_1, lock_test_public_key); + OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: lock thread test OQS_SIG_STFL_verify failed\n"); + goto err; + } + + printf("================================================================================\n"); + printf("Sig Verify 2 %s\n", method_name); + printf("================================================================================\n"); + + rc = OQS_SIG_STFL_verify(lock_test_sig_obj, message_2, message_len_2, signature_2, signature_len_2, lock_test_public_key); + OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: lock thread test OQS_SIG_STFL_verify failed\n"); + goto err; + } + rc = OQS_SUCCESS; + printf("================================================================================\n"); + printf("Stateful Signature Verification %s Passed.\n", method_name); + printf("================================================================================\n"); + goto end_it; +err: + rc = OQS_ERROR; +end_it: + + return rc; +} + +static OQS_STATUS sig_stfl_test_sig_gen(const char *method_name) { + OQS_STATUS rc = OQS_SUCCESS; + size_t message_len_1 = sizeof(message_1); + size_t message_len_2 = sizeof(message_2); + + /* + * Temporarily skip algs with long key generation times. + */ + + if (strcmp(method_name, OQS_SIG_STFL_alg_lms_sha256_n32_h5_w1) != 0) { + goto skip_test; + } else { + goto keep_going; + } + +skip_test: + printf("Skip slow alg %s.\n", method_name); + return rc; + +keep_going: + + printf("================================================================================\n"); + printf("Testing stateful Signature Generation %s\n", method_name); + printf("================================================================================\n"); + + if ( lock_test_sk == NULL || lock_test_sig_obj == NULL) { + return OQS_ERROR; + } + + + printf("================================================================================\n"); + printf("Sig Gen 1 %s\n", method_name); + printf("================================================================================\n"); + + signature_1 = malloc(lock_test_sig_obj->length_signature); + + rc = OQS_SIG_STFL_sign(lock_test_sig_obj, signature_1, &signature_len_1, message_1, message_len_1, lock_test_sk); + OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: lock thread test OQS_SIG_STFL_sign failed\n"); + goto err; + } + + sleep(3); + + printf("================================================================================\n"); + printf("Sig Gen 2 %s\n", method_name); + printf("================================================================================\n"); + + signature_2 = malloc(lock_test_sig_obj->length_signature); + + rc = OQS_SIG_STFL_sign(lock_test_sig_obj, signature_2, &signature_len_2, message_2, message_len_2, lock_test_sk); + OQS_TEST_CT_DECLASSIFY(&rc, sizeof rc); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: lock thread test OQS_SIG_STFL_sign failed\n"); + goto err; + } + rc = OQS_SUCCESS; + printf("================================================================================\n"); + printf("Stateful Key Gen %s Passed.\n", method_name); + printf("================================================================================\n"); + goto end_it; +err: + rc = OQS_ERROR; +end_it: + + return rc; +} + + +static OQS_STATUS sig_stfl_test_secret_key_lock(const char *method_name) { + OQS_STATUS rc = OQS_SUCCESS; + + /* + * Temporarily skip algs with long key generation times. + */ + + if (strcmp(method_name, OQS_SIG_STFL_alg_lms_sha256_n32_h5_w1) != 0) { + goto skip_test; + } else { + goto keep_going; + } + +skip_test: + printf("Skip slow test %s.\n", method_name); + return rc; + +keep_going: + + printf("================================================================================\n"); + printf("Testing stateful Signature locks %s\n", method_name); + printf("================================================================================\n"); + + printf("================================================================================\n"); + printf("Create stateful Signature %s\n", method_name); + printf("================================================================================\n"); + + lock_test_sig_obj = OQS_SIG_STFL_new(method_name); + if (lock_test_sig_obj == NULL) { + fprintf(stderr, "ERROR: OQS_SIG_STFL_new failed\n"); + goto err; + } + + lock_test_public_key = malloc(lock_test_sig_obj->length_public_key * sizeof(uint8_t)); + + printf("================================================================================\n"); + printf("Create stateful Secret Key %s\n", method_name); + printf("================================================================================\n"); + + lock_test_sk = OQS_SIG_STFL_SECRET_KEY_new(method_name); + if (lock_test_sk == NULL) { + fprintf(stderr, "ERROR: OQS_SECRET_KEY_new failed\n"); + goto err; + } + + OQS_SIG_STFL_SECRET_KEY_SET_lock(lock_test_sk, lock_sk_key); + OQS_SIG_STFL_SECRET_KEY_SET_unlock(lock_test_sk, unlock_sk_key); + +#if OQS_USE_PTHREADS_IN_TESTS + + test_sk_lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + if (test_sk_lock == NULL) { + goto err; + } + + if (0 != pthread_mutex_init(test_sk_lock, 0)) { + goto err; + } + OQS_SIG_STFL_SECRET_KEY_SET_mutex(lock_test_sk, test_sk_lock); +#endif + + printf("================================================================================\n"); + printf("Generate keypair %s\n", method_name); + printf("================================================================================\n"); + + rc = OQS_SIG_STFL_keypair(lock_test_sig_obj, lock_test_public_key, lock_test_sk); + + if (rc != OQS_SUCCESS) { + fprintf(stderr, "OQS STFL key gen failed.\n"); + goto err; + } + + + + if (!lock_test_sk->secret_key_data) { + fprintf(stderr, "ERROR: OQS_SECRET_KEY_new incomplete.\n"); + goto err; + } + + /* set context and secure store callback */ + if (lock_test_sk->set_scrt_key_store_cb) { + lock_test_context = strdup(((method_name))); + lock_test_sk->set_scrt_key_store_cb(lock_test_sk, test_save_secret_key, (void *)lock_test_context); + } + + printf("Test Secret Key Creator Thread created Stateful Signature and Secret Key objects.\n"); + goto end_it; + +err: + rc = OQS_ERROR; +end_it: + return rc; +} + #ifdef OQS_ENABLE_TEST_CONSTANT_TIME static void TEST_SIG_STFL_randombytes(uint8_t *random_array, size_t bytes_to_read) { // We can't make direct calls to the system randombytes on some platforms, // so we have to swap out the OQS_randombytes provider. + OQS_randombytes_switch_algorithm("system"); OQS_randombytes(random_array, bytes_to_read); OQS_randombytes_custom_algorithm(&TEST_SIG_STFL_randombytes); @@ -693,6 +995,35 @@ struct thread_data { OQS_STATUS rc1; }; +struct lock_test_data { + const char *alg_name; + OQS_STATUS rc; +}; + +void *test_query_key(void *arg) { + struct lock_test_data *td = arg; + printf("\n%s: Start Query Stateful Key info\n", __FUNCTION__); + td->rc = sig_stfl_test_query_key(td->alg_name); + printf("%s: End Query Stateful Key info\n\n", __FUNCTION__); + return NULL; +} + +void *test_sig_gen(void *arg) { + struct lock_test_data *td = arg; + printf("\n%s: Start Generate Stateful Signature\n", __FUNCTION__); + td->rc = sig_stfl_test_sig_gen(td->alg_name); + printf("%s: End Generate Stateful Signature\n\n", __FUNCTION__); + return NULL; +} + +void *test_create_keys(void *arg) { + struct lock_test_data *td = arg; + printf("\n%s: Start Generate Keys\n", __FUNCTION__); + td->rc = sig_stfl_test_secret_key_lock(td->alg_name); + printf("%s: End Generate Stateful Keys\n\n", __FUNCTION__); + return NULL; +} + void *test_wrapper(void *arg) { struct thread_data *td = arg; td->rc = sig_stfl_test_correctness(td->alg_name, td->katfile); @@ -737,13 +1068,26 @@ int main(int argc, char **argv) { OQS_randombytes_switch_algorithm("system"); #endif - OQS_STATUS rc, rc1; + OQS_STATUS rc, rc1, rc_lck, rc_sig, rc_qry; #if OQS_USE_PTHREADS_IN_TESTS #define MAX_LEN_SIG_NAME_ 64 + pthread_t thread; + pthread_t create_key_thread; + pthread_t sign_key_thread; + pthread_t query_key_thread; struct thread_data td; td.alg_name = alg_name; td.katfile = katfile; + + struct lock_test_data td_create; + struct lock_test_data td_sign; + struct lock_test_data td_query; + td_create.alg_name = alg_name; + td_sign.alg_name = alg_name; + td_query.alg_name = alg_name; + + int trc = pthread_create(&thread, NULL, test_wrapper, &td); if (trc) { fprintf(stderr, "ERROR: Creating pthread\n"); @@ -753,11 +1097,47 @@ int main(int argc, char **argv) { pthread_join(thread, NULL); rc = td.rc; rc1 = td.rc1; + + int trc_2 = pthread_create(&create_key_thread, NULL, test_create_keys, &td_create); + if (trc_2) { + fprintf(stderr, "ERROR: Creating pthread for stateful key gen test\n"); + OQS_destroy(); + return EXIT_FAILURE; + } + pthread_join(create_key_thread, NULL); + rc_lck = td_create.rc; + + int trc_3 = pthread_create(&sign_key_thread, NULL, test_sig_gen, &td_sign); + if (trc_3) { + fprintf(stderr, "ERROR: Creating pthread for sig gen test\n"); + OQS_destroy(); + return EXIT_FAILURE; + } + pthread_join(sign_key_thread, NULL); + rc_sig = td_sign.rc; + + int trc_4 = pthread_create(&query_key_thread, NULL, test_query_key, &td_query); + if (trc_4) { + fprintf(stderr, "ERROR: Creating pthread for query key test.\n"); + OQS_destroy(); + return EXIT_FAILURE; + } + pthread_join(query_key_thread, NULL); + rc_qry = td_query.rc; #else rc = sig_stfl_test_correctness(alg_name, katfile); rc1 = sig_stfl_test_secret_key(alg_name); #endif - if ((rc != OQS_SUCCESS) || (rc1 != OQS_SUCCESS)) { + + OQS_SIG_STFL_SECRET_KEY_free(lock_test_sk); + OQS_MEM_insecure_free(lock_test_public_key); + OQS_SIG_STFL_free(lock_test_sig_obj); + OQS_MEM_insecure_free(lock_test_context); + OQS_MEM_insecure_free(signature_1); + OQS_MEM_insecure_free(signature_2); + + if ((rc != OQS_SUCCESS) || (rc1 != OQS_SUCCESS) || (rc_lck != OQS_SUCCESS) || (rc_sig != OQS_SUCCESS) + || (rc_qry != OQS_SUCCESS)) { OQS_destroy(); return EXIT_FAILURE; }