From ee0a376dd02df1a939a8bfc13e6c149a9cf0bcf7 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Fri, 5 Jan 2024 14:47:00 +0200 Subject: [PATCH] Add tests for rnp_revocation_signature_create() and related functions. --- src/tests/ffi-key-sig.cpp | 139 +++++++++++++++++++++++++++++++++++++- src/tests/support.cpp | 76 +++++++++++++++++++++ src/tests/support.h | 10 +++ 3 files changed, 224 insertions(+), 1 deletion(-) diff --git a/src/tests/ffi-key-sig.cpp b/src/tests/ffi-key-sig.cpp index 54c749ecb0..1cc1c5a505 100644 --- a/src/tests/ffi-key-sig.cpp +++ b/src/tests/ffi-key-sig.cpp @@ -1749,4 +1749,141 @@ TEST_F(rnp_tests, test_ffi_add_revoker_signature) /* Check v5 key */ rnp_ffi_destroy(ffi); -} \ No newline at end of file +} + +TEST_F(rnp_tests, test_ffi_create_revocation_signature) +{ + rnp_ffi_t ffi = NULL; + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + assert_true(import_all_keys(ffi, "data/test_stream_key_load/ecc-25519-2subs-sec.asc")); + assert_true(import_pub_keys(ffi, "data/test_stream_key_load/ecc-p256-sec.asc")); + rnp_key_handle_t key = NULL; + assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-25519", &key)); + /* Create self revocation */ + rnp_signature_handle_t newsig = NULL; + assert_rnp_failure(rnp_key_revocation_signature_create(NULL, key, &newsig)); + assert_rnp_failure(rnp_key_revocation_signature_create(key, key, NULL)); + assert_rnp_failure(rnp_key_revocation_signature_create(key, NULL, NULL)); + assert_rnp_success(rnp_key_revocation_signature_create(key, NULL, &newsig)); + const char *revcode = "compromised"; + const char *revreason = "custom revocation reason"; + const char *hash = "SHA512"; + assert_rnp_failure(rnp_key_signature_set_hash(NULL, hash)); + assert_rnp_failure(rnp_key_signature_set_hash(newsig, NULL)); + assert_rnp_failure(rnp_key_signature_set_hash(newsig, "wrong")); + assert_rnp_success(rnp_key_signature_set_hash(newsig, hash)); + assert_rnp_failure(rnp_key_signature_set_revocation_reason(NULL, revcode, revreason)); + assert_rnp_success(rnp_key_signature_set_revocation_reason(newsig, NULL, NULL)); + assert_rnp_success(rnp_key_signature_set_revocation_reason(newsig, NULL, "wrong reason")); + assert_rnp_failure(rnp_key_signature_set_revocation_reason(newsig, "wrong code", NULL)); + assert_rnp_success(rnp_key_signature_set_revocation_reason(newsig, revcode, revreason)); + assert_rnp_failure(rnp_key_signature_sign(newsig)); + rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"); + assert_rnp_success(rnp_key_signature_sign(newsig)); + rnp_signature_handle_destroy(newsig); + /* Check signature parameters */ + assert_rnp_success(rnp_key_get_signature_at(key, 0, &newsig)); + assert_true(check_sig_hash(newsig, hash)); + assert_true(check_sig_type(newsig, "key revocation")); + char *sigcode = NULL; + char *sigreason = NULL; + /* Some edge cases of the new function */ + assert_rnp_failure(rnp_signature_get_revocation_reason(NULL, &sigcode, &sigreason)); + assert_rnp_success(rnp_signature_get_revocation_reason(newsig, &sigcode, NULL)); + assert_string_equal(sigcode, revcode); + rnp_buffer_destroy(sigcode); + assert_rnp_success(rnp_signature_get_revocation_reason(newsig, NULL, &sigreason)); + assert_string_equal(sigreason, revreason); + rnp_buffer_destroy(sigreason); + assert_true(check_sig_revreason(newsig, revcode, revreason)); + rnp_signature_handle_destroy(newsig); + assert_true(check_key_revoked(key, true)); + assert_true(check_key_revreason(key, revreason)); + bool compromised = false; + assert_rnp_success(rnp_key_is_compromised(key, &compromised)); + assert_true(compromised); + /* Export key and make sure data is saved */ + auto keydata = export_key(key, true); + rnp_key_handle_destroy(key); + rnp_ffi_t newffi = NULL; + assert_rnp_success(rnp_ffi_create(&newffi, "GPG", "GPG")); + assert_true(import_all_keys(newffi, keydata.data(), keydata.size())); + assert_rnp_success(rnp_locate_key(newffi, "userid", "ecc-25519", &key)); + assert_true(check_key_revoked(key, true)); + assert_true(check_key_revreason(key, revreason)); + assert_rnp_success(rnp_key_get_signature_at(key, 0, &newsig)); + assert_true(check_sig_type(newsig, "key revocation")); + rnp_signature_handle_destroy(newsig); + rnp_key_handle_destroy(key); + rnp_ffi_destroy(newffi); + /* Create revocation for other key, using the designated revoker */ + rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET); + assert_true(import_all_keys(ffi, "data/test_stream_key_load/ecc-25519-sec.asc")); + assert_true( + import_pub_keys(ffi, "data/test_stream_key_load/ecc-p256-desig-rev-1-pub.asc")); + key = get_key_by_uid(ffi, "ecc-p256"); + rnp_key_handle_t revoker = get_key_by_uid(ffi, "ecc-25519"); + assert_true(check_key_locked(revoker, true)); + assert_true(check_key_revoked(key, false)); + assert_rnp_success(rnp_key_revocation_signature_create(revoker, key, &newsig)); + assert_rnp_success(rnp_key_signature_set_hash(newsig, hash)); + assert_rnp_success(rnp_key_signature_set_revocation_reason(newsig, revcode, revreason)); + assert_rnp_success(rnp_key_signature_sign(newsig)); + assert_true(check_key_locked(revoker, true)); + rnp_signature_handle_destroy(newsig); + rnp_key_handle_destroy(revoker); + assert_true(check_key_revoked(key, true)); + assert_true(check_key_revreason(key, revreason)); + assert_rnp_success(rnp_key_is_compromised(key, &compromised)); + assert_true(compromised); + /* Export/import and check */ + keydata = export_key(key, false); + rnp_key_handle_destroy(key); + assert_rnp_success(rnp_ffi_create(&newffi, "GPG", "GPG")); + assert_true(import_all_keys(newffi, keydata.data(), keydata.size())); + assert_true(import_all_keys(newffi, "data/test_stream_key_load/ecc-25519-pub.asc")); + key = get_key_by_uid(ffi, "ecc-p256"); + assert_true(check_key_revoked(key, true)); + assert_true(check_key_revreason(key, revreason)); + assert_rnp_success(rnp_key_get_signature_at(key, 0, &newsig)); + assert_true(check_sig_type(newsig, "key revocation")); + rnp_signature_handle_destroy(newsig); + rnp_key_handle_destroy(key); + rnp_ffi_destroy(newffi); + /* Create self subkey revocation */ + rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET); + assert_true(import_all_keys(ffi, "data/test_stream_key_load/ecc-p256-sec.asc")); + key = get_key_by_uid(ffi, "ecc-p256"); + rnp_key_handle_t subkey = get_key_by_fp(ffi, "40e608afbc8d62cdcc08904f37e285e9e9851491"); + assert_rnp_success(rnp_key_revocation_signature_create(key, subkey, &newsig)); + assert_rnp_success(rnp_key_signature_sign(newsig)); + assert_true(check_key_revoked(subkey, true)); + assert_true(check_key_revreason(subkey, "No reason specified")); + assert_rnp_success(rnp_key_is_compromised(subkey, &compromised)); + assert_false(compromised); + rnp_signature_handle_destroy(newsig); + assert_rnp_success(rnp_key_get_signature_at(subkey, 0, &newsig)); + assert_true(check_sig_type(newsig, "subkey revocation")); + assert_rnp_success(rnp_signature_get_revocation_reason(newsig, &sigcode, &sigreason)); + assert_string_equal(sigcode, ""); + assert_string_equal(sigreason, ""); + rnp_signature_handle_destroy(newsig); + rnp_key_handle_destroy(subkey); + /* Export and recheck */ + keydata = export_key(key, false); + rnp_key_handle_destroy(key); + assert_rnp_success(rnp_ffi_create(&newffi, "GPG", "GPG")); + assert_true(import_all_keys(newffi, keydata.data(), keydata.size())); + subkey = get_key_by_fp(newffi, "40e608afbc8d62cdcc08904f37e285e9e9851491"); + assert_true(check_key_revoked(subkey, true)); + assert_true(check_key_revreason(subkey, "No reason specified")); + assert_rnp_success(rnp_key_is_compromised(subkey, &compromised)); + assert_false(compromised); + rnp_key_handle_destroy(subkey); + rnp_ffi_destroy(newffi); + /* Revoke other key using subkey as revoker with designated revoker */ + /* Attempt to revoke primary key using the subkey without designated revoker */ + /* Attempt to revoke primary key using the subkey with designated revoker */ + + rnp_ffi_destroy(ffi); +} diff --git a/src/tests/support.cpp b/src/tests/support.cpp index 1189aa7ffa..ec71f698f3 100644 --- a/src/tests/support.cpp +++ b/src/tests/support.cpp @@ -1106,6 +1106,16 @@ check_key_revoked(rnp_key_handle_t key, bool revoked) return rev == revoked; } +bool +check_key_locked(rnp_key_handle_t key, bool locked) +{ + bool lock = !locked; + if (rnp_key_is_locked(key, &lock)) { + return false; + } + return lock == locked; +} + uint32_t get_key_expiry(rnp_key_handle_t key) { @@ -1159,6 +1169,18 @@ check_key_fp(rnp_key_handle_t key, const std::string &expected) return res; } +bool +check_key_revreason(rnp_key_handle_t key, const char *reason) +{ + char *rstr = NULL; + if (rnp_key_get_revocation_reason(key, &rstr)) { + return false; + } + bool res = !strcmp(rstr, reason); + rnp_buffer_destroy(rstr); + return res; +} + bool check_has_key(rnp_ffi_t ffi, const std::string &id, bool secret, bool valid) { @@ -1196,6 +1218,60 @@ check_has_key(rnp_ffi_t ffi, const std::string &id, bool secret, bool valid) return res; } +bool +check_sig_hash(rnp_signature_handle_t sig, const char *hash) +{ + char *sighash = NULL; + if (rnp_signature_get_hash_alg(sig, &sighash)) { + return false; + } + bool res = !strcmp(sighash, hash); + rnp_buffer_destroy(sighash); + return res; +} + +bool +check_sig_type(rnp_signature_handle_t sig, const char *type) +{ + char *sigtype = NULL; + if (rnp_signature_get_type(sig, &sigtype)) { + return false; + } + bool res = !strcmp(sigtype, type); + rnp_buffer_destroy(sigtype); + return res; +} + +bool +check_sig_revreason(rnp_signature_handle_t sig, const char *revcode, const char *revreason) +{ + char *sigcode = NULL; + char *sigreason = NULL; + if (rnp_signature_get_revocation_reason(sig, &sigcode, &sigreason)) { + return false; + } + bool res = !strcmp(sigcode, revcode) && !strcmp(sigreason, revreason); + rnp_buffer_destroy(sigcode); + rnp_buffer_destroy(sigreason); + return res; +} + +rnp_key_handle_t +get_key_by_fp(rnp_ffi_t ffi, const char *fp) +{ + rnp_key_handle_t key = NULL; + rnp_locate_key(ffi, "fingerprint", fp, &key); + return key; +} + +rnp_key_handle_t +get_key_by_uid(rnp_ffi_t ffi, const char *uid) +{ + rnp_key_handle_t key = NULL; + rnp_locate_key(ffi, "userid", uid, &key); + return key; +} + rnp_key_handle_t bogus_key_handle(rnp_ffi_t ffi) { diff --git a/src/tests/support.h b/src/tests/support.h index a1ffa56e0a..5b4e2c54b7 100644 --- a/src/tests/support.h +++ b/src/tests/support.h @@ -251,6 +251,7 @@ void dump_key_stdout(rnp_key_handle_t key, bool secret = false); /* some shortcuts for less code */ bool check_key_valid(rnp_key_handle_t key, bool validity); bool check_key_revoked(rnp_key_handle_t key, bool revoked); +bool check_key_locked(rnp_key_handle_t key, bool locked); uint32_t get_key_expiry(rnp_key_handle_t key); size_t get_key_uids(rnp_key_handle_t key); bool check_sub_valid(rnp_key_handle_t key, size_t idx, bool validity); @@ -265,10 +266,19 @@ void check_loaded_keys(const char * format, bool secret); bool check_key_grip(rnp_key_handle_t key, const std::string &expected); bool check_key_fp(rnp_key_handle_t key, const std::string &expected); +bool check_key_revreason(rnp_key_handle_t key, const char *reason); bool check_has_key(rnp_ffi_t ffi, const std::string &id, bool secret = false, bool valid = true); +bool check_sig_hash(rnp_signature_handle_t sig, const char *hash); +bool check_sig_type(rnp_signature_handle_t sig, const char *type); +bool check_sig_revreason(rnp_signature_handle_t sig, + const char * revcode, + const char * revreason); + +rnp_key_handle_t get_key_by_fp(rnp_ffi_t ffi, const char *fp); +rnp_key_handle_t get_key_by_uid(rnp_ffi_t ffi, const char *uid); /* create bogus key handle with NULL pub/sec keys */ rnp_key_handle_t bogus_key_handle(rnp_ffi_t ffi);