summaryrefslogtreecommitdiffstats
path: root/src/tests/key-unlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/key-unlock.cpp')
-rw-r--r--src/tests/key-unlock.cpp221
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);
+}