diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:32:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:32:49 +0000 |
commit | 8053187731ae8e3eb368d8360989cf5fd6eed9f7 (patch) | |
tree | 32bada84ff5d7460cdf3934fcbdbe770d6afe4cd /src/tests/key-unlock.cpp | |
parent | Initial commit. (diff) | |
download | rnp-8053187731ae8e3eb368d8360989cf5fd6eed9f7.tar.xz rnp-8053187731ae8e3eb368d8360989cf5fd6eed9f7.zip |
Adding upstream version 0.17.0.upstream/0.17.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tests/key-unlock.cpp')
-rw-r--r-- | src/tests/key-unlock.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/tests/key-unlock.cpp b/src/tests/key-unlock.cpp new file mode 100644 index 0000000..445c704 --- /dev/null +++ b/src/tests/key-unlock.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017-2019 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../librekey/key_store_pgp.h" +#include "../librepgp/stream-ctx.h" +#include "pgp-key.h" +#include "ffi-priv-types.h" +#include "rnp_tests.h" +#include "support.h" +#include <fstream> + +TEST_F(rnp_tests, test_key_unlock_pgp) +{ + cli_rnp_t rnp = {}; + const char * data = "my test data"; + pgp_password_provider_t provider = {0}; + static const char * keyids[] = {"7bc6709b15c23a4a", // primary + "1ed63ee56fadc34d", + "1d7e8a5393c997a8", + "8a05b89fad5aded1", + "2fcadf05ffa501bb", // primary + "54505a936a4a970e", + "326ef111425d14a5"}; + + assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_GPG, "data/keyrings/1/", NULL)); + assert_true(rnp.load_keyrings(true)); + + for (size_t i = 0; i < ARRAY_SIZE(keyids); i++) { + rnp_key_handle_t handle = NULL; + assert_rnp_success(rnp_locate_key(rnp.ffi, "keyid", keyids[i], &handle)); + assert_non_null(handle); + bool locked = false; + assert_rnp_success(rnp_key_is_locked(handle, &locked)); + // all keys in this keyring are encrypted and thus should be locked initially + assert_true(locked); + rnp_key_handle_destroy(handle); + } + + std::ofstream out("dummyfile.dat"); + out << data; + out.close(); + + // try signing with a failing password provider (should fail) + assert_rnp_success( + rnp_ffi_set_pass_provider(rnp.ffi, ffi_failing_password_provider, NULL)); + rnp_cfg &cfg = rnp.cfg(); + cfg.load_defaults(); + cfg.set_bool(CFG_SIGN_NEEDED, true); + cfg.set_str(CFG_HASH, "SHA256"); + cfg.set_int(CFG_ZLEVEL, 0); + cfg.set_str(CFG_INFILE, "dummyfile.dat"); + cfg.set_str(CFG_OUTFILE, "dummyfile.dat.pgp"); + cfg.add_str(CFG_SIGNERS, keyids[0]); + assert_false(cli_rnp_protect_file(&rnp)); + + // grab the signing key to unlock + rnp_key_handle_t key = NULL; + assert_rnp_success(rnp_locate_key(rnp.ffi, "keyid", keyids[0], &key)); + assert_non_null(key); + char *alg = NULL; + // confirm that this key is indeed RSA first + assert_rnp_success(rnp_key_get_alg(key, &alg)); + assert_int_equal(strcmp(alg, "RSA"), 0); + rnp_buffer_destroy(alg); + + // confirm the secret MPIs are NULL + assert_true(mpi_empty(key->sec->material().rsa.d)); + assert_true(mpi_empty(key->sec->material().rsa.p)); + assert_true(mpi_empty(key->sec->material().rsa.q)); + assert_true(mpi_empty(key->sec->material().rsa.u)); + + // try to unlock with a failing password provider + provider.callback = failing_password_callback; + provider.userdata = NULL; + assert_false(key->sec->unlock(provider)); + bool locked = false; + assert_rnp_success(rnp_key_is_locked(key, &locked)); + assert_true(locked); + + // try to unlock with an incorrect password + provider.callback = string_copy_password_callback; + provider.userdata = (void *) "badpass"; + assert_false(key->sec->unlock(provider)); + assert_rnp_success(rnp_key_is_locked(key, &locked)); + assert_true(locked); + + // unlock the signing key + provider.callback = string_copy_password_callback; + provider.userdata = (void *) "password"; + assert_true(key->sec->unlock(provider)); + assert_rnp_success(rnp_key_is_locked(key, &locked)); + assert_false(locked); + + // confirm the secret MPIs are now filled in + assert_false(mpi_empty(key->sec->material().rsa.d)); + assert_false(mpi_empty(key->sec->material().rsa.p)); + assert_false(mpi_empty(key->sec->material().rsa.q)); + assert_false(mpi_empty(key->sec->material().rsa.u)); + + // now the signing key is unlocked, confirm that no password is required for signing + assert_rnp_success( + rnp_ffi_set_pass_provider(rnp.ffi, ffi_asserting_password_provider, NULL)); + cfg.clear(); + cfg.load_defaults(); + cfg.set_bool(CFG_SIGN_NEEDED, true); + cfg.set_str(CFG_HASH, "SHA256"); + cfg.set_int(CFG_ZLEVEL, 0); + cfg.set_str(CFG_INFILE, "dummyfile.dat"); + cfg.set_str(CFG_OUTFILE, "dummyfile.dat.pgp"); + cfg.add_str(CFG_SIGNERS, keyids[0]); + assert_true(cli_rnp_protect_file(&rnp)); + cfg.clear(); + + // verify + cfg.load_defaults(); + cfg.set_bool(CFG_OVERWRITE, true); + cfg.set_str(CFG_INFILE, "dummyfile.dat.pgp"); + cfg.set_str(CFG_OUTFILE, "dummyfile.verify"); + assert_true(cli_rnp_process_file(&rnp)); + + // verify (negative) + std::fstream verf("dummyfile.dat.pgp", + std::ios_base::binary | std::ios_base::out | std::ios_base::in); + verf.seekg(-3, std::ios::end); + char bt = verf.peek() ^ 0xff; + verf.seekp(-3, std::ios::end); + verf.write(&bt, 1); + verf.close(); + assert_false(cli_rnp_process_file(&rnp)); + + // lock the signing key + assert_rnp_success(rnp_key_lock(key)); + assert_rnp_success(rnp_key_is_locked(key, &locked)); + assert_true(locked); + + // sign, with no password (should now fail) + assert_rnp_success( + rnp_ffi_set_pass_provider(rnp.ffi, ffi_failing_password_provider, NULL)); + cfg.clear(); + cfg.load_defaults(); + cfg.set_bool(CFG_SIGN_NEEDED, true); + cfg.set_bool(CFG_OVERWRITE, true); + cfg.set_str(CFG_HASH, "SHA1"); + cfg.set_int(CFG_ZLEVEL, 0); + cfg.set_str(CFG_INFILE, "dummyfile.dat"); + cfg.set_str(CFG_OUTFILE, "dummyfile.dat.pgp"); + cfg.add_str(CFG_SIGNERS, keyids[0]); + assert_false(cli_rnp_protect_file(&rnp)); + cfg.clear(); + + // encrypt + cfg.load_defaults(); + cfg.set_bool(CFG_ENCRYPT_PK, true); + cfg.set_int(CFG_ZLEVEL, 0); + cfg.set_str(CFG_INFILE, "dummyfile.dat"); + cfg.set_str(CFG_OUTFILE, "dummyfile.dat.pgp"); + cfg.set_bool(CFG_OVERWRITE, true); + cfg.set_str(CFG_CIPHER, "AES256"); + cfg.add_str(CFG_RECIPIENTS, keyids[1]); + assert_true(cli_rnp_protect_file(&rnp)); + cfg.clear(); + + // try decrypting with a failing password provider (should fail) + cfg.load_defaults(); + cfg.set_bool(CFG_OVERWRITE, true); + cfg.set_str(CFG_INFILE, "dummyfile.dat.pgp"); + cfg.set_str(CFG_OUTFILE, "dummyfile.decrypt"); + assert_false(cli_rnp_process_file(&rnp)); + + // grab the encrypting key to unlock + rnp_key_handle_t subkey = NULL; + assert_rnp_success(rnp_locate_key(rnp.ffi, "keyid", keyids[1], &subkey)); + assert_non_null(subkey); + + // unlock the encrypting key + assert_rnp_success(rnp_key_unlock(subkey, "password")); + assert_rnp_success(rnp_key_is_locked(subkey, &locked)); + assert_false(locked); + + // decrypt, with no password + assert_true(cli_rnp_process_file(&rnp)); + + std::string decrypt = file_to_str("dummyfile.decrypt"); + assert_true(decrypt == data); + + // lock the encrypting key + assert_rnp_success(rnp_key_lock(subkey)); + assert_rnp_success(rnp_key_is_locked(subkey, &locked)); + assert_true(locked); + + // decrypt, with no password (should now fail) + assert_false(cli_rnp_process_file(&rnp)); + // cleanup + assert_rnp_success(rnp_key_handle_destroy(key)); + assert_rnp_success(rnp_key_handle_destroy(subkey)); + rnp.end(); + assert_int_equal(rnp_unlink("dummyfile.dat"), 0); +} |