mirror of
https://github.com/Mbed-TLS/mbedtls-framework.git
synced 2026-08-28 13:59:54 +00:00
Merge pull request #8924 from Ryan-Everett-arm/threading-same-key-tests
Add testing for concurrently loading/using/destroying the same key
This commit is contained in:
@@ -123,6 +123,9 @@
|
||||
* \param input2 The first input to pass.
|
||||
* \param input2_length The length of \p input2 in bytes.
|
||||
* \param capacity The capacity to set.
|
||||
* \param key_destroyable If set to 1, a failure due to the key not existing
|
||||
* or the key being destroyed mid-operation will only
|
||||
* be reported if the error code is unexpected.
|
||||
*
|
||||
* \return \c 1 on success, \c 0 on failure.
|
||||
*/
|
||||
@@ -132,7 +135,7 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
psa_algorithm_t alg,
|
||||
const unsigned char *input1, size_t input1_length,
|
||||
const unsigned char *input2, size_t input2_length,
|
||||
size_t capacity);
|
||||
size_t capacity, int key_destroyable);
|
||||
|
||||
/** Perform a key agreement using the given key pair against its public key
|
||||
* using psa_raw_key_agreement().
|
||||
@@ -143,12 +146,15 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
*
|
||||
* \param alg A key agreement algorithm compatible with \p key.
|
||||
* \param key A key that allows key agreement with \p alg.
|
||||
* \param key_destroyable If set to 1, a failure due to the key not existing
|
||||
* or the key being destroyed mid-operation will only
|
||||
* be reported if the error code is unexpected.
|
||||
*
|
||||
* \return \c 1 on success, \c 0 on failure.
|
||||
*/
|
||||
psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
|
||||
psa_algorithm_t alg,
|
||||
mbedtls_svc_key_id_t key);
|
||||
mbedtls_svc_key_id_t key, int key_destroyable);
|
||||
|
||||
/** Perform a key agreement using the given key pair against its public key
|
||||
* using psa_key_derivation_raw_key().
|
||||
@@ -162,12 +168,15 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
|
||||
* \p key.
|
||||
* \param key A key pair object that is suitable for a key
|
||||
* agreement with \p operation.
|
||||
* \param key_destroyable If set to 1, a failure due to the key not existing
|
||||
* or the key being destroyed mid-operation will only
|
||||
* be reported if the error code is unexpected.
|
||||
*
|
||||
* \return \c 1 on success, \c 0 on failure.
|
||||
*/
|
||||
psa_status_t mbedtls_test_psa_key_agreement_with_self(
|
||||
psa_key_derivation_operation_t *operation,
|
||||
mbedtls_svc_key_id_t key);
|
||||
mbedtls_svc_key_id_t key, int key_destroyable);
|
||||
|
||||
/** Perform sanity checks on the given key representation.
|
||||
*
|
||||
@@ -209,18 +218,34 @@ int mbedtls_test_psa_exported_key_sanity_check(
|
||||
* ```
|
||||
* if( ! exercise_key( ... ) ) goto exit;
|
||||
* ```
|
||||
* To use this function for multi-threaded tests where the key
|
||||
* may be destroyed at any point: call this function with key_destroyable set
|
||||
* to 1, while another thread calls psa_destroy_key on the same key;
|
||||
* this will test whether destroying the key in use leads to any corruption.
|
||||
*
|
||||
* \param key The key to exercise. It should be capable of performing
|
||||
* \p alg.
|
||||
* \param usage The usage flags to assume.
|
||||
* \param alg The algorithm to exercise.
|
||||
* There cannot be a set of concurrent calls:
|
||||
* `mbedtls_test_psa_exercise_key(ki,...)` such that each ki is a unique
|
||||
* persistent key not loaded into any key slot, and i is greater than the
|
||||
* number of free key slots.
|
||||
* This is because such scenarios can lead to unsupported
|
||||
* `PSA_ERROR_INSUFFICIENT_MEMORY` return codes.
|
||||
*
|
||||
*
|
||||
* \param key The key to exercise. It should be capable of performing
|
||||
* \p alg.
|
||||
* \param usage The usage flags to assume.
|
||||
* \param alg The algorithm to exercise.
|
||||
* \param key_destroyable If set to 1, a failure due to the key not existing
|
||||
* or the key being destroyed mid-operation will only
|
||||
* be reported if the error code is unexpected.
|
||||
*
|
||||
* \retval 0 The key failed the smoke tests.
|
||||
* \retval 1 The key passed the smoke tests.
|
||||
*/
|
||||
int mbedtls_test_psa_exercise_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg);
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable);
|
||||
|
||||
psa_key_usage_t mbedtls_test_psa_usage_to_exercise(psa_key_type_t type,
|
||||
psa_algorithm_t alg);
|
||||
|
||||
+316
-141
@@ -38,7 +38,8 @@ static int lifetime_is_dynamic_secure_element(psa_key_lifetime_t lifetime)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_key_attributes_sanity(mbedtls_svc_key_id_t key)
|
||||
static int check_key_attributes_sanity(mbedtls_svc_key_id_t key,
|
||||
int key_destroyable)
|
||||
{
|
||||
int ok = 0;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
@@ -46,8 +47,13 @@ static int check_key_attributes_sanity(mbedtls_svc_key_id_t key)
|
||||
mbedtls_svc_key_id_t id;
|
||||
psa_key_type_t type;
|
||||
size_t bits;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
psa_reset_key_attributes(&attributes);
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
lifetime = psa_get_key_lifetime(&attributes);
|
||||
id = psa_get_key_id(&attributes);
|
||||
type = psa_get_key_type(&attributes);
|
||||
@@ -66,17 +72,20 @@ static int check_key_attributes_sanity(mbedtls_svc_key_id_t key)
|
||||
(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(id) <= PSA_KEY_ID_USER_MAX));
|
||||
}
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
/* randomly-generated 64-bit constant, should never appear in test data */
|
||||
psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21;
|
||||
psa_status_t status = psa_get_key_slot_number(&attributes, &slot_number);
|
||||
if (lifetime_is_dynamic_secure_element(lifetime)) {
|
||||
/* Mbed TLS currently always exposes the slot number to
|
||||
* applications. This is not mandated by the PSA specification
|
||||
* and may change in future versions. */
|
||||
TEST_EQUAL(status, 0);
|
||||
TEST_ASSERT(slot_number != 0xec94d4a5058a1a21);
|
||||
} else {
|
||||
TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT);
|
||||
/* MBEDTLS_PSA_CRYPTO_SE_C does not support thread safety. */
|
||||
if (key_destroyable == 0) {
|
||||
/* randomly-generated 64-bit constant, should never appear in test data */
|
||||
psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21;
|
||||
status = psa_get_key_slot_number(&attributes, &slot_number);
|
||||
if (lifetime_is_dynamic_secure_element(lifetime)) {
|
||||
/* Mbed TLS currently always exposes the slot number to
|
||||
* applications. This is not mandated by the PSA specification
|
||||
* and may change in future versions. */
|
||||
TEST_EQUAL(status, 0);
|
||||
TEST_ASSERT(slot_number != 0xec94d4a5058a1a21);
|
||||
} else {
|
||||
TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -110,20 +119,27 @@ exit:
|
||||
|
||||
static int exercise_mac_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
|
||||
const unsigned char input[] = "foo";
|
||||
unsigned char mac[PSA_MAC_MAX_SIZE] = { 0 };
|
||||
size_t mac_length = sizeof(mac);
|
||||
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
/* Convert wildcard algorithm to exercisable algorithm */
|
||||
if (alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) {
|
||||
alg = PSA_ALG_TRUNCATED_MAC(alg, PSA_MAC_TRUNCATED_LENGTH(alg));
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_SIGN_HASH) {
|
||||
PSA_ASSERT(psa_mac_sign_setup(&operation, key, alg));
|
||||
status = psa_mac_sign_setup(&operation, key, alg);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
PSA_ASSERT(psa_mac_abort(&operation));
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_mac_update(&operation,
|
||||
input, sizeof(input)));
|
||||
PSA_ASSERT(psa_mac_sign_finish(&operation,
|
||||
@@ -136,7 +152,13 @@ static int exercise_mac_key(mbedtls_svc_key_id_t key,
|
||||
(usage & PSA_KEY_USAGE_SIGN_HASH ?
|
||||
PSA_SUCCESS :
|
||||
PSA_ERROR_INVALID_SIGNATURE);
|
||||
PSA_ASSERT(psa_mac_verify_setup(&operation, key, alg));
|
||||
status = psa_mac_verify_setup(&operation, key, alg);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
PSA_ASSERT(psa_mac_abort(&operation));
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_mac_update(&operation,
|
||||
input, sizeof(input)));
|
||||
TEST_EQUAL(psa_mac_verify_finish(&operation, mac, mac_length),
|
||||
@@ -152,7 +174,8 @@ exit:
|
||||
|
||||
static int exercise_cipher_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
|
||||
unsigned char iv[PSA_CIPHER_IV_MAX_SIZE] = { 0 };
|
||||
@@ -164,13 +187,20 @@ static int exercise_cipher_key(mbedtls_svc_key_id_t key,
|
||||
size_t ciphertext_length = sizeof(ciphertext);
|
||||
unsigned char decrypted[sizeof(ciphertext)];
|
||||
size_t part_length;
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
key_type = psa_get_key_type(&attributes);
|
||||
iv_length = PSA_CIPHER_IV_LENGTH(key_type, alg);
|
||||
|
||||
if (usage & PSA_KEY_USAGE_ENCRYPT) {
|
||||
PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg));
|
||||
status = psa_cipher_encrypt_setup(&operation, key, alg);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
PSA_ASSERT(psa_cipher_abort(&operation));
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
if (iv_length != 0) {
|
||||
PSA_ASSERT(psa_cipher_generate_iv(&operation,
|
||||
iv, sizeof(iv),
|
||||
@@ -188,12 +218,17 @@ static int exercise_cipher_key(mbedtls_svc_key_id_t key,
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_DECRYPT) {
|
||||
psa_status_t status;
|
||||
int maybe_invalid_padding = 0;
|
||||
if (!(usage & PSA_KEY_USAGE_ENCRYPT)) {
|
||||
maybe_invalid_padding = !PSA_ALG_IS_STREAM_CIPHER(alg);
|
||||
}
|
||||
PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg));
|
||||
status = psa_cipher_decrypt_setup(&operation, key, alg);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
PSA_ASSERT(psa_cipher_abort(&operation));
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
if (iv_length != 0) {
|
||||
PSA_ASSERT(psa_cipher_set_iv(&operation,
|
||||
iv, iv_length));
|
||||
@@ -227,7 +262,8 @@ exit:
|
||||
|
||||
static int exercise_aead_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
unsigned char nonce[PSA_AEAD_NONCE_MAX_SIZE] = { 0 };
|
||||
size_t nonce_length;
|
||||
@@ -237,6 +273,7 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key,
|
||||
unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)";
|
||||
size_t ciphertext_length = sizeof(ciphertext);
|
||||
size_t plaintext_length = sizeof(ciphertext);
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
||||
/* Convert wildcard algorithm to exercisable algorithm */
|
||||
if (alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) {
|
||||
@@ -248,12 +285,17 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key,
|
||||
nonce_length = PSA_AEAD_NONCE_LENGTH(key_type, alg);
|
||||
|
||||
if (usage & PSA_KEY_USAGE_ENCRYPT) {
|
||||
PSA_ASSERT(psa_aead_encrypt(key, alg,
|
||||
nonce, nonce_length,
|
||||
NULL, 0,
|
||||
plaintext, sizeof(plaintext),
|
||||
ciphertext, sizeof(ciphertext),
|
||||
&ciphertext_length));
|
||||
status = psa_aead_encrypt(key, alg,
|
||||
nonce, nonce_length,
|
||||
NULL, 0,
|
||||
plaintext, sizeof(plaintext),
|
||||
ciphertext, sizeof(ciphertext),
|
||||
&ciphertext_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_DECRYPT) {
|
||||
@@ -261,13 +303,17 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key,
|
||||
(usage & PSA_KEY_USAGE_ENCRYPT ?
|
||||
PSA_SUCCESS :
|
||||
PSA_ERROR_INVALID_SIGNATURE);
|
||||
TEST_EQUAL(psa_aead_decrypt(key, alg,
|
||||
nonce, nonce_length,
|
||||
NULL, 0,
|
||||
ciphertext, ciphertext_length,
|
||||
plaintext, sizeof(plaintext),
|
||||
&plaintext_length),
|
||||
verify_status);
|
||||
status = psa_aead_decrypt(key, alg,
|
||||
nonce, nonce_length,
|
||||
NULL, 0,
|
||||
ciphertext, ciphertext_length,
|
||||
plaintext, sizeof(plaintext),
|
||||
&plaintext_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
TEST_ASSERT(status == verify_status);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -291,7 +337,8 @@ static int can_sign_or_verify_message(psa_key_usage_t usage,
|
||||
|
||||
static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
/* If the policy allows signing with any hash, just pick one. */
|
||||
psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
|
||||
@@ -305,6 +352,7 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
TEST_FAIL("No hash algorithm for hash-and-sign testing");
|
||||
#endif
|
||||
}
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
||||
if (usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH) &&
|
||||
PSA_ALG_IS_SIGN_HASH(alg)) {
|
||||
@@ -321,10 +369,15 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_SIGN_HASH) {
|
||||
PSA_ASSERT(psa_sign_hash(key, alg,
|
||||
payload, payload_length,
|
||||
signature, sizeof(signature),
|
||||
&signature_length));
|
||||
status = psa_sign_hash(key, alg,
|
||||
payload, payload_length,
|
||||
signature, sizeof(signature),
|
||||
&signature_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_VERIFY_HASH) {
|
||||
@@ -332,10 +385,14 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
(usage & PSA_KEY_USAGE_SIGN_HASH ?
|
||||
PSA_SUCCESS :
|
||||
PSA_ERROR_INVALID_SIGNATURE);
|
||||
TEST_EQUAL(psa_verify_hash(key, alg,
|
||||
payload, payload_length,
|
||||
signature, signature_length),
|
||||
verify_status);
|
||||
status = psa_verify_hash(key, alg,
|
||||
payload, payload_length,
|
||||
signature, signature_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
TEST_ASSERT(status == verify_status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,10 +403,15 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
size_t signature_length = sizeof(signature);
|
||||
|
||||
if (usage & PSA_KEY_USAGE_SIGN_MESSAGE) {
|
||||
PSA_ASSERT(psa_sign_message(key, alg,
|
||||
message, message_length,
|
||||
signature, sizeof(signature),
|
||||
&signature_length));
|
||||
status = psa_sign_message(key, alg,
|
||||
message, message_length,
|
||||
signature, sizeof(signature),
|
||||
&signature_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_VERIFY_MESSAGE) {
|
||||
@@ -357,10 +419,14 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key,
|
||||
(usage & PSA_KEY_USAGE_SIGN_MESSAGE ?
|
||||
PSA_SUCCESS :
|
||||
PSA_ERROR_INVALID_SIGNATURE);
|
||||
TEST_EQUAL(psa_verify_message(key, alg,
|
||||
message, message_length,
|
||||
signature, signature_length),
|
||||
verify_status);
|
||||
status = psa_verify_message(key, alg,
|
||||
message, message_length,
|
||||
signature, signature_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
TEST_ASSERT(status == verify_status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +438,8 @@ exit:
|
||||
|
||||
static int exercise_asymmetric_encryption_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
unsigned char plaintext[PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE] =
|
||||
"Hello, world...";
|
||||
@@ -380,22 +447,30 @@ static int exercise_asymmetric_encryption_key(mbedtls_svc_key_id_t key,
|
||||
"(wabblewebblewibblewobblewubble)";
|
||||
size_t ciphertext_length = sizeof(ciphertext);
|
||||
size_t plaintext_length = 16;
|
||||
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
if (usage & PSA_KEY_USAGE_ENCRYPT) {
|
||||
PSA_ASSERT(psa_asymmetric_encrypt(key, alg,
|
||||
plaintext, plaintext_length,
|
||||
NULL, 0,
|
||||
ciphertext, sizeof(ciphertext),
|
||||
&ciphertext_length));
|
||||
status = psa_asymmetric_encrypt(key, alg,
|
||||
plaintext, plaintext_length,
|
||||
NULL, 0,
|
||||
ciphertext, sizeof(ciphertext),
|
||||
&ciphertext_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
}
|
||||
|
||||
if (usage & PSA_KEY_USAGE_DECRYPT) {
|
||||
psa_status_t status =
|
||||
psa_asymmetric_decrypt(key, alg,
|
||||
ciphertext, ciphertext_length,
|
||||
NULL, 0,
|
||||
plaintext, sizeof(plaintext),
|
||||
&plaintext_length);
|
||||
status = psa_asymmetric_decrypt(key, alg,
|
||||
ciphertext, ciphertext_length,
|
||||
NULL, 0,
|
||||
plaintext, sizeof(plaintext),
|
||||
&plaintext_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
TEST_ASSERT(status == PSA_SUCCESS ||
|
||||
((usage & PSA_KEY_USAGE_ENCRYPT) == 0 &&
|
||||
(status == PSA_ERROR_INVALID_ARGUMENT ||
|
||||
@@ -414,16 +489,22 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
psa_algorithm_t alg,
|
||||
const unsigned char *input1, size_t input1_length,
|
||||
const unsigned char *input2, size_t input2_length,
|
||||
size_t capacity)
|
||||
size_t capacity, int key_destroyable)
|
||||
{
|
||||
PSA_ASSERT(psa_key_derivation_setup(operation, alg));
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
if (PSA_ALG_IS_HKDF(alg)) {
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SALT,
|
||||
input1, input1_length));
|
||||
PSA_ASSERT(psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key));
|
||||
status = psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_INFO,
|
||||
input2,
|
||||
@@ -432,13 +513,23 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SALT,
|
||||
input1, input1_length));
|
||||
PSA_ASSERT(psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key));
|
||||
status = psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
} else if (PSA_ALG_IS_HKDF_EXPAND(alg)) {
|
||||
PSA_ASSERT(psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key));
|
||||
status = psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_INFO,
|
||||
input2,
|
||||
@@ -448,9 +539,14 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SEED,
|
||||
input1, input1_length));
|
||||
PSA_ASSERT(psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key));
|
||||
status = psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
key);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_LABEL,
|
||||
input2, input2_length));
|
||||
@@ -462,9 +558,14 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
|
||||
PSA_KEY_DERIVATION_INPUT_SALT,
|
||||
input2,
|
||||
input2_length));
|
||||
PSA_ASSERT(psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_PASSWORD,
|
||||
key));
|
||||
status = psa_key_derivation_input_key(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_PASSWORD,
|
||||
key);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
} else if (alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) {
|
||||
PSA_ASSERT(psa_key_derivation_input_bytes(operation,
|
||||
PSA_KEY_DERIVATION_INPUT_SECRET,
|
||||
@@ -486,7 +587,8 @@ exit:
|
||||
|
||||
static int exercise_key_derivation_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
|
||||
unsigned char input1[] = "Input 1";
|
||||
@@ -500,14 +602,20 @@ static int exercise_key_derivation_key(mbedtls_svc_key_id_t key,
|
||||
if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, key, alg,
|
||||
input1, input1_length,
|
||||
input2, input2_length,
|
||||
capacity)) {
|
||||
capacity, key_destroyable)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_key_derivation_output_bytes(&operation,
|
||||
output,
|
||||
capacity));
|
||||
PSA_ASSERT(psa_key_derivation_abort(&operation));
|
||||
psa_status_t status = psa_key_derivation_output_bytes(&operation,
|
||||
output,
|
||||
capacity);
|
||||
if (key_destroyable && status == PSA_ERROR_BAD_STATE) {
|
||||
/* The key has been destroyed. */
|
||||
PSA_ASSERT(psa_key_derivation_abort(&operation));
|
||||
} else {
|
||||
PSA_ASSERT(status);
|
||||
PSA_ASSERT(psa_key_derivation_abort(&operation));
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -520,31 +628,45 @@ exit:
|
||||
* private key against its own public key. */
|
||||
psa_status_t mbedtls_test_psa_key_agreement_with_self(
|
||||
psa_key_derivation_operation_t *operation,
|
||||
mbedtls_svc_key_id_t key)
|
||||
mbedtls_svc_key_id_t key, int key_destroyable)
|
||||
{
|
||||
psa_key_type_t private_key_type;
|
||||
psa_key_type_t public_key_type;
|
||||
size_t key_bits;
|
||||
uint8_t *public_key = NULL;
|
||||
size_t public_key_length;
|
||||
/* Return GENERIC_ERROR if something other than the final call to
|
||||
* psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
|
||||
* but it's good enough: callers will report it as a failed test anyway. */
|
||||
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
psa_reset_key_attributes(&attributes);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
|
||||
private_key_type = psa_get_key_type(&attributes);
|
||||
key_bits = psa_get_key_bits(&attributes);
|
||||
public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(private_key_type);
|
||||
public_key_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits);
|
||||
TEST_CALLOC(public_key, public_key_length);
|
||||
PSA_ASSERT(psa_export_public_key(key, public_key, public_key_length,
|
||||
&public_key_length));
|
||||
status = psa_export_public_key(key, public_key, public_key_length,
|
||||
&public_key_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
status = PSA_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
|
||||
status = psa_key_derivation_key_agreement(
|
||||
operation, PSA_KEY_DERIVATION_INPUT_SECRET, key,
|
||||
public_key, public_key_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
status = PSA_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
/*
|
||||
* Key attributes may have been returned by psa_get_key_attributes()
|
||||
@@ -560,7 +682,8 @@ exit:
|
||||
* private key against its own public key. */
|
||||
psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
|
||||
psa_algorithm_t alg,
|
||||
mbedtls_svc_key_id_t key)
|
||||
mbedtls_svc_key_id_t key,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_key_type_t private_key_type;
|
||||
psa_key_type_t public_key_type;
|
||||
@@ -569,25 +692,39 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
|
||||
size_t public_key_length;
|
||||
uint8_t output[1024];
|
||||
size_t output_length;
|
||||
/* Return GENERIC_ERROR if something other than the final call to
|
||||
* psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
|
||||
* but it's good enough: callers will report it as a failed test anyway. */
|
||||
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
psa_reset_key_attributes(&attributes);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
|
||||
private_key_type = psa_get_key_type(&attributes);
|
||||
key_bits = psa_get_key_bits(&attributes);
|
||||
public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(private_key_type);
|
||||
public_key_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits);
|
||||
TEST_CALLOC(public_key, public_key_length);
|
||||
PSA_ASSERT(psa_export_public_key(key,
|
||||
public_key, public_key_length,
|
||||
&public_key_length));
|
||||
status = psa_export_public_key(key,
|
||||
public_key, public_key_length,
|
||||
&public_key_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
status = PSA_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
|
||||
status = psa_raw_key_agreement(alg, key,
|
||||
public_key, public_key_length,
|
||||
output, sizeof(output), &output_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
status = PSA_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
if (status == PSA_SUCCESS) {
|
||||
TEST_ASSERT(output_length <=
|
||||
PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(private_key_type,
|
||||
@@ -609,14 +746,16 @@ exit:
|
||||
|
||||
static int exercise_raw_key_agreement_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
if (usage & PSA_KEY_USAGE_DERIVE) {
|
||||
/* We need two keys to exercise key agreement. Exercise the
|
||||
* private key against its own public key. */
|
||||
PSA_ASSERT(mbedtls_test_psa_raw_key_agreement_with_self(alg, key));
|
||||
PSA_ASSERT(mbedtls_test_psa_raw_key_agreement_with_self(alg, key,
|
||||
key_destroyable));
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
@@ -626,7 +765,8 @@ exit:
|
||||
|
||||
static int exercise_key_agreement_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
|
||||
unsigned char input[1] = { 0 };
|
||||
@@ -657,7 +797,12 @@ static int exercise_key_agreement_key(mbedtls_svc_key_id_t key,
|
||||
hash length. Otherwise test should fail with INVALID_ARGUMENT. */
|
||||
if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) {
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
ok = 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
size_t key_bits = psa_get_key_bits(&attributes);
|
||||
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg);
|
||||
|
||||
@@ -666,7 +811,8 @@ static int exercise_key_agreement_key(mbedtls_svc_key_id_t key,
|
||||
}
|
||||
}
|
||||
|
||||
TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self(&operation, key),
|
||||
TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self(&operation, key,
|
||||
key_destroyable),
|
||||
expected_key_agreement_status);
|
||||
|
||||
if (expected_key_agreement_status != PSA_SUCCESS) {
|
||||
@@ -857,7 +1003,8 @@ exit:
|
||||
}
|
||||
|
||||
static int exercise_export_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage)
|
||||
psa_key_usage_t usage,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
uint8_t *exported = NULL;
|
||||
@@ -865,25 +1012,31 @@ static int exercise_export_key(mbedtls_svc_key_id_t key,
|
||||
size_t exported_length = 0;
|
||||
int ok = 0;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
psa_reset_key_attributes(&attributes);
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
|
||||
exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
|
||||
psa_get_key_type(&attributes),
|
||||
psa_get_key_bits(&attributes));
|
||||
TEST_CALLOC(exported, exported_size);
|
||||
|
||||
if ((usage & PSA_KEY_USAGE_EXPORT) == 0 &&
|
||||
!PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes))) {
|
||||
TEST_EQUAL(psa_export_key(key, exported,
|
||||
exported_size, &exported_length),
|
||||
PSA_ERROR_NOT_PERMITTED);
|
||||
status = psa_export_key(key, exported, exported_size, &exported_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
ok = 1;
|
||||
goto exit;
|
||||
} else if ((usage & PSA_KEY_USAGE_EXPORT) == 0 &&
|
||||
!PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes))) {
|
||||
TEST_EQUAL(status, PSA_ERROR_NOT_PERMITTED);
|
||||
ok = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_export_key(key,
|
||||
exported, exported_size,
|
||||
&exported_length));
|
||||
PSA_ASSERT(status);
|
||||
ok = mbedtls_test_psa_exported_key_sanity_check(
|
||||
psa_get_key_type(&attributes), psa_get_key_bits(&attributes),
|
||||
exported, exported_length);
|
||||
@@ -899,7 +1052,8 @@ exit:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int exercise_export_public_key(mbedtls_svc_key_id_t key)
|
||||
static int exercise_export_public_key(mbedtls_svc_key_id_t key,
|
||||
int key_destroyable)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_type_t public_type;
|
||||
@@ -908,16 +1062,27 @@ static int exercise_export_public_key(mbedtls_svc_key_id_t key)
|
||||
size_t exported_length = 0;
|
||||
int ok = 0;
|
||||
|
||||
PSA_ASSERT(psa_get_key_attributes(key, &attributes));
|
||||
psa_status_t status = psa_get_key_attributes(key, &attributes);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
psa_reset_key_attributes(&attributes);
|
||||
return 1;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
if (!PSA_KEY_TYPE_IS_ASYMMETRIC(psa_get_key_type(&attributes))) {
|
||||
exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
|
||||
psa_get_key_type(&attributes),
|
||||
psa_get_key_bits(&attributes));
|
||||
TEST_CALLOC(exported, exported_size);
|
||||
|
||||
TEST_EQUAL(psa_export_public_key(key, exported,
|
||||
exported_size, &exported_length),
|
||||
PSA_ERROR_INVALID_ARGUMENT);
|
||||
status = psa_export_public_key(key, exported,
|
||||
exported_size, &exported_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
ok = 1;
|
||||
goto exit;
|
||||
}
|
||||
TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT);
|
||||
ok = 1;
|
||||
goto exit;
|
||||
}
|
||||
@@ -928,9 +1093,14 @@ static int exercise_export_public_key(mbedtls_svc_key_id_t key)
|
||||
psa_get_key_bits(&attributes));
|
||||
TEST_CALLOC(exported, exported_size);
|
||||
|
||||
PSA_ASSERT(psa_export_public_key(key,
|
||||
exported, exported_size,
|
||||
&exported_length));
|
||||
status = psa_export_public_key(key, exported,
|
||||
exported_size, &exported_length);
|
||||
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
|
||||
/* The key has been destroyed. */
|
||||
ok = 1;
|
||||
goto exit;
|
||||
}
|
||||
PSA_ASSERT(status);
|
||||
ok = mbedtls_test_psa_exported_key_sanity_check(
|
||||
public_type, psa_get_key_bits(&attributes),
|
||||
exported, exported_length);
|
||||
@@ -948,38 +1118,43 @@ exit:
|
||||
|
||||
int mbedtls_test_psa_exercise_key(mbedtls_svc_key_id_t key,
|
||||
psa_key_usage_t usage,
|
||||
psa_algorithm_t alg)
|
||||
psa_algorithm_t alg,
|
||||
int key_destroyable)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
if (!check_key_attributes_sanity(key)) {
|
||||
if (!check_key_attributes_sanity(key, key_destroyable)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (alg == 0) {
|
||||
ok = 1; /* If no algorithm, do nothing (used for raw data "keys"). */
|
||||
} else if (PSA_ALG_IS_MAC(alg)) {
|
||||
ok = exercise_mac_key(key, usage, alg);
|
||||
ok = exercise_mac_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_CIPHER(alg)) {
|
||||
ok = exercise_cipher_key(key, usage, alg);
|
||||
ok = exercise_cipher_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_AEAD(alg)) {
|
||||
ok = exercise_aead_key(key, usage, alg);
|
||||
ok = exercise_aead_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_SIGN(alg)) {
|
||||
ok = exercise_signature_key(key, usage, alg);
|
||||
ok = exercise_signature_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg)) {
|
||||
ok = exercise_asymmetric_encryption_key(key, usage, alg);
|
||||
ok = exercise_asymmetric_encryption_key(key, usage, alg,
|
||||
key_destroyable);
|
||||
} else if (PSA_ALG_IS_KEY_DERIVATION(alg)) {
|
||||
ok = exercise_key_derivation_key(key, usage, alg);
|
||||
ok = exercise_key_derivation_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) {
|
||||
ok = exercise_raw_key_agreement_key(key, usage, alg);
|
||||
ok = exercise_raw_key_agreement_key(key, usage, alg, key_destroyable);
|
||||
} else if (PSA_ALG_IS_KEY_AGREEMENT(alg)) {
|
||||
ok = exercise_key_agreement_key(key, usage, alg);
|
||||
ok = exercise_key_agreement_key(key, usage, alg, key_destroyable);
|
||||
} else {
|
||||
TEST_FAIL("No code to exercise this category of algorithm");
|
||||
}
|
||||
|
||||
ok = ok && exercise_export_key(key, usage);
|
||||
ok = ok && exercise_export_public_key(key);
|
||||
ok = ok && exercise_export_key(key,
|
||||
usage,
|
||||
key_destroyable);
|
||||
ok = ok && exercise_export_public_key(key,
|
||||
key_destroyable);
|
||||
|
||||
exit:
|
||||
return ok;
|
||||
|
||||
Reference in New Issue
Block a user