summaryrefslogtreecommitdiffstats
path: root/src/tests/load-pgp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/load-pgp.cpp')
-rw-r--r--src/tests/load-pgp.cpp985
1 files changed, 985 insertions, 0 deletions
diff --git a/src/tests/load-pgp.cpp b/src/tests/load-pgp.cpp
new file mode 100644
index 0000000..560ed3d
--- /dev/null
+++ b/src/tests/load-pgp.cpp
@@ -0,0 +1,985 @@
+/*
+ * Copyright (c) 2017-2020 [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-packet.h"
+#include "../librepgp/stream-sig.h"
+#include "pgp-key.h"
+#include "utils.h"
+
+#include "rnp_tests.h"
+#include "support.h"
+
+/* This test loads a .gpg pubring with a single V3 key,
+ * and confirms that appropriate key flags are set.
+ */
+TEST_F(rnp_tests, test_load_v3_keyring_pgp)
+{
+ pgp_source_t src = {};
+
+ rnp_key_store_t *key_store = new rnp_key_store_t(global_ctx);
+
+ // load pubring in to the key store
+ assert_rnp_success(init_file_src(&src, "data/keyrings/2/pubring.gpg"));
+ assert_rnp_success(rnp_key_store_pgp_read_from_src(key_store, &src));
+ src_close(&src);
+ assert_int_equal(1, rnp_key_store_get_key_count(key_store));
+
+ // find the key by keyid
+ const pgp_key_t *key = rnp_tests_get_key_by_id(key_store, "DC70C124A50283F1");
+ assert_non_null(key);
+
+ // confirm the key flags are correct
+ assert_int_equal(key->flags(),
+ PGP_KF_ENCRYPT | PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH);
+
+ // confirm that key expiration is correct
+ assert_int_equal(key->expiration(), 0);
+
+ // cleanup
+ delete key_store;
+
+ // load secret keyring and decrypt the key
+ key_store = new rnp_key_store_t(global_ctx);
+
+ assert_rnp_success(init_file_src(&src, "data/keyrings/4/secring.pgp"));
+ assert_rnp_success(rnp_key_store_pgp_read_from_src(key_store, &src));
+ src_close(&src);
+ assert_int_equal(1, rnp_key_store_get_key_count(key_store));
+
+ key = rnp_tests_get_key_by_id(key_store, "7D0BC10E933404C9");
+ assert_non_null(key);
+
+ // confirm the key flags are correct
+ assert_int_equal(key->flags(),
+ PGP_KF_ENCRYPT | PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH);
+
+ // check if the key is secret and is locked
+ assert_true(key->is_secret());
+ assert_true(key->is_locked());
+
+ // decrypt the key
+ pgp_key_pkt_t *seckey = pgp_decrypt_seckey_pgp(key->rawpkt(), key->pkt(), "password");
+#if defined(ENABLE_IDEA)
+ assert_non_null(seckey);
+#else
+ assert_null(seckey);
+#endif
+
+ // cleanup
+ delete seckey;
+ delete key_store;
+}
+
+/* This test loads a .gpg pubring with multiple V4 keys,
+ * finds a particular key of interest, and confirms that
+ * the appropriate key flags are set.
+ */
+TEST_F(rnp_tests, test_load_v4_keyring_pgp)
+{
+ pgp_source_t src = {};
+
+ rnp_key_store_t *key_store = new rnp_key_store_t(global_ctx);
+
+ // load it in to the key store
+ assert_rnp_success(init_file_src(&src, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_key_store_pgp_read_from_src(key_store, &src));
+ src_close(&src);
+ assert_int_equal(7, rnp_key_store_get_key_count(key_store));
+
+ // find the key by keyid
+ static const std::string keyid = "8a05b89fad5aded1";
+ const pgp_key_t * key = rnp_tests_get_key_by_id(key_store, keyid);
+ assert_non_null(key);
+
+ // confirm the key flags are correct
+ assert_int_equal(key->flags(), PGP_KF_ENCRYPT);
+
+ // cleanup
+ delete key_store;
+}
+
+/* Just a helper for the below test */
+static void
+check_pgp_keyring_counts(const char * path,
+ unsigned primary_count,
+ const unsigned subkey_counts[])
+{
+ pgp_source_t src = {};
+ rnp_key_store_t *key_store = new rnp_key_store_t(global_ctx);
+
+ // load it in to the key store
+ assert_rnp_success(init_file_src(&src, path));
+ assert_rnp_success(rnp_key_store_pgp_read_from_src(key_store, &src));
+ src_close(&src);
+
+ // count primary keys first
+ unsigned total_primary_count = 0;
+ for (auto &key : key_store->keys) {
+ if (key.is_primary()) {
+ total_primary_count++;
+ }
+ }
+ assert_int_equal(primary_count, total_primary_count);
+
+ // now count subkeys in each primary key
+ unsigned total_subkey_count = 0;
+ unsigned primary = 0;
+ for (auto &key : key_store->keys) {
+ if (key.is_primary()) {
+ // check the subkey count for this primary key
+ assert_int_equal(key.subkey_count(), subkey_counts[primary++]);
+ } else if (key.is_subkey()) {
+ total_subkey_count++;
+ }
+ }
+
+ // check the total (not really needed)
+ assert_int_equal(rnp_key_store_get_key_count(key_store),
+ total_primary_count + total_subkey_count);
+
+ // cleanup
+ delete key_store;
+}
+
+/* This test loads a pubring.gpg and secring.gpg and confirms
+ * that it contains the expected number of primary keys
+ * and the expected number of subkeys for each primary key.
+ */
+TEST_F(rnp_tests, test_load_keyring_and_count_pgp)
+{
+ unsigned int primary_count = 2;
+ unsigned int subkey_counts[2] = {3, 2};
+
+ // check pubring
+ check_pgp_keyring_counts("data/keyrings/1/pubring.gpg", primary_count, subkey_counts);
+
+ // check secring
+ check_pgp_keyring_counts("data/keyrings/1/secring.gpg", primary_count, subkey_counts);
+}
+
+/* This test loads a V4 keyring and confirms that certain
+ * bitfields and time fields are set correctly.
+ */
+TEST_F(rnp_tests, test_load_check_bitfields_and_times)
+{
+ const pgp_key_t * key;
+ const pgp_signature_t *sig = NULL;
+
+ // load keyring
+ rnp_key_store_t *key_store =
+ new rnp_key_store_t(PGP_KEY_STORE_GPG, "data/keyrings/1/pubring.gpg", global_ctx);
+ assert_true(rnp_key_store_load_from_path(key_store, NULL));
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "7BC6709B15C23A4A");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 3);
+ // check subsig properties
+ for (size_t i = 0; i < key->sig_count(); i++) {
+ sig = &key->get_sig(i).sig;
+ static const time_t expected_creation_times[] = {1500569820, 1500569836, 1500569846};
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "7BC6709B15C23A4A"));
+ // check SS_CREATION_TIME
+ assert_int_equal(sig->creation(), expected_creation_times[i]);
+ // check SS_EXPIRATION_TIME
+ assert_int_equal(sig->expiration(), 0);
+ }
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 0);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "1ED63EE56FADC34D");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "7BC6709B15C23A4A"));
+ // check SS_CREATION_TIME [0]
+ assert_int_equal(sig->creation(), 1500569820);
+ assert_int_equal(sig->creation(), key->creation());
+ // check SS_EXPIRATION_TIME [0]
+ assert_int_equal(sig->expiration(), 0);
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 0);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "1D7E8A5393C997A8");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "7BC6709B15C23A4A"));
+ // check SS_CREATION_TIME [0]
+ assert_int_equal(sig->creation(), 1500569851);
+ assert_int_equal(sig->creation(), key->creation());
+ // check SS_EXPIRATION_TIME [0]
+ assert_int_equal(sig->expiration(), 0);
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 123 * 24 * 60 * 60 /* 123 days */);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "8A05B89FAD5ADED1");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "7BC6709B15C23A4A"));
+ // check SS_CREATION_TIME [0]
+ assert_int_equal(sig->creation(), 1500569896);
+ assert_int_equal(sig->creation(), key->creation());
+ // check SS_EXPIRATION_TIME [0]
+ assert_int_equal(sig->expiration(), 0);
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 0);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "2FCADF05FFA501BB");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 3);
+ // check subsig properties
+ for (size_t i = 0; i < key->sig_count(); i++) {
+ sig = &key->get_sig(i).sig;
+ static const time_t expected_creation_times[] = {1501372449, 1500570153, 1500570147};
+
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "2FCADF05FFA501BB"));
+ // check SS_CREATION_TIME
+ assert_int_equal(sig->creation(), expected_creation_times[i]);
+ // check SS_EXPIRATION_TIME
+ assert_int_equal(sig->expiration(), 0);
+ }
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 2076663808);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "54505A936A4A970E");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "2FCADF05FFA501BB"));
+ // check SS_CREATION_TIME [0]
+ assert_int_equal(sig->creation(), 1500569946);
+ assert_int_equal(sig->creation(), key->creation());
+ // check SS_EXPIRATION_TIME [0]
+ assert_int_equal(sig->expiration(), 0);
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 2076663808);
+
+ // find
+ key = NULL;
+ key = rnp_tests_get_key_by_id(key_store, "326EF111425D14A5");
+ assert_non_null(key);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check SS_ISSUER_KEY_ID
+ assert_true(cmp_keyid(sig->keyid(), "2FCADF05FFA501BB"));
+ // check SS_CREATION_TIME [0]
+ assert_int_equal(sig->creation(), 1500570165);
+ assert_int_equal(sig->creation(), key->creation());
+ // check SS_EXPIRATION_TIME [0]
+ assert_int_equal(sig->expiration(), 0);
+ // check SS_KEY_EXPIRY
+ assert_int_equal(key->expiration(), 0);
+
+ // cleanup
+ delete key_store;
+}
+
+/* This test loads a V3 keyring and confirms that certain
+ * bitfields and time fields are set correctly.
+ */
+TEST_F(rnp_tests, test_load_check_bitfields_and_times_v3)
+{
+ pgp_key_id_t keyid = {};
+ const pgp_key_t * key;
+ const pgp_signature_t *sig = NULL;
+
+ // load keyring
+ rnp_key_store_t *key_store =
+ new rnp_key_store_t(PGP_KEY_STORE_GPG, "data/keyrings/2/pubring.gpg", global_ctx);
+ assert_true(rnp_key_store_load_from_path(key_store, NULL));
+
+ // find
+ key = NULL;
+ assert_true(rnp::hex_decode("DC70C124A50283F1", keyid.data(), keyid.size()));
+ key = rnp_tests_get_key_by_id(key_store, "DC70C124A50283F1");
+ assert_non_null(key);
+ // check key version
+ assert_int_equal(key->version(), PGP_V3);
+ // check subsig count
+ assert_int_equal(key->sig_count(), 1);
+ sig = &key->get_sig(0).sig;
+ // check signature version
+ assert_int_equal(sig->version, 3);
+ // check issuer
+ assert_true(rnp::hex_decode("DC70C124A50283F1", keyid.data(), keyid.size()));
+ assert_true(keyid == sig->keyid());
+ // check creation time
+ assert_int_equal(sig->creation(), 1005209227);
+ assert_int_equal(sig->creation(), key->creation());
+ // check signature expiration time (V3 sigs have none)
+ assert_int_equal(sig->expiration(), 0);
+ // check key expiration
+ assert_int_equal(key->expiration(), 0); // only for V4 keys
+ assert_int_equal(key->pkt().v3_days, 0);
+
+ // cleanup
+ delete key_store;
+}
+
+#define MERGE_PATH "data/test_stream_key_merge/"
+
+TEST_F(rnp_tests, test_load_armored_pub_sec)
+{
+ rnp_key_store_t *key_store =
+ new rnp_key_store_t(PGP_KEY_STORE_GPG, MERGE_PATH "key-both.asc", global_ctx);
+ assert_true(rnp_key_store_load_from_path(key_store, NULL));
+
+ /* we must have 1 main key and 2 subkeys */
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+
+ pgp_key_t *key = NULL;
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, "9747D2A6B3A63124"));
+ assert_true(key->valid());
+ assert_true(key->is_primary());
+ assert_true(key->is_secret());
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_SECRET_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, "AF1114A47F5F5B28"));
+ assert_true(key->valid());
+ assert_true(key->is_subkey());
+ assert_true(key->is_secret());
+ assert_int_equal(key->rawpkt_count(), 2);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, "16CD16F267CCDD4F"));
+ assert_true(key->valid());
+ assert_true(key->is_subkey());
+ assert_true(key->is_secret());
+ assert_int_equal(key->rawpkt_count(), 2);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ /* make sure half of keyid doesn't work */
+ assert_null(key = rnp_tests_get_key_by_id(key_store, "0000000016CD16F2"));
+ assert_null(key = rnp_tests_get_key_by_id(key_store, "67CCDD4F00000000"));
+ assert_null(key = rnp_tests_get_key_by_id(key_store, "0000000067CCDD4F"));
+
+ /* both user ids should be present */
+ assert_non_null(rnp_tests_key_search(key_store, "key-merge-uid-1"));
+ assert_non_null(rnp_tests_key_search(key_store, "key-merge-uid-2"));
+
+ delete key_store;
+}
+
+static bool
+load_transferable_key(pgp_transferable_key_t *key, const char *fname)
+{
+ pgp_source_t src = {};
+ bool res = !init_file_src(&src, fname) && !process_pgp_key(src, *key, false);
+ src_close(&src);
+ return res;
+}
+
+static bool
+load_transferable_subkey(pgp_transferable_subkey_t *key, const char *fname)
+{
+ pgp_source_t src = {};
+ bool res = !init_file_src(&src, fname) && !process_pgp_subkey(src, *key, false);
+ src_close(&src);
+ return res;
+}
+
+static bool
+load_keystore(rnp_key_store_t *keystore, const char *fname)
+{
+ pgp_source_t src = {};
+ bool res = !init_file_src(&src, fname) && !rnp_key_store_pgp_read_from_src(keystore, &src);
+ src_close(&src);
+ return res;
+}
+
+static bool
+check_subkey_fp(pgp_key_t *key, pgp_key_t *subkey, size_t index)
+{
+ if (key->get_subkey_fp(index) != subkey->fp()) {
+ return false;
+ }
+ if (!subkey->has_primary_fp()) {
+ return false;
+ }
+ return key->fp() == subkey->primary_fp();
+}
+
+TEST_F(rnp_tests, test_load_merge)
+{
+ pgp_key_t * key, *skey1, *skey2;
+ pgp_transferable_key_t tkey = {};
+ pgp_transferable_subkey_t tskey = {};
+ pgp_password_provider_t provider = {};
+ provider.callback = string_copy_password_callback;
+ provider.userdata = (void *) "password";
+
+ rnp_key_store_t *key_store = new rnp_key_store_t(PGP_KEY_STORE_GPG, "", global_ctx);
+ std::string keyid = "9747D2A6B3A63124";
+ std::string sub1id = "AF1114A47F5F5B28";
+ std::string sub2id = "16CD16F267CCDD4F";
+
+ /* load just key packet */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-just-key.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 1);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_false(key->valid());
+ assert_int_equal(key->rawpkt_count(), 1);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+
+ /* load key + user id 1 without sigs */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-uid-1-no-sigs.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 1);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_false(key->valid());
+ assert_int_equal(key->uid_count(), 1);
+ assert_int_equal(key->rawpkt_count(), 2);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_null(rnp_tests_key_search(key_store, "key-merge-uid-1"));
+ assert_true(key == rnp_tests_get_key_by_id(key_store, "9747D2A6B3A63124"));
+
+ /* load key + user id 1 with sigs */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-uid-1.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 1);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_true(key->valid());
+ assert_int_equal(key->uid_count(), 1);
+ assert_int_equal(key->rawpkt_count(), 3);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_true(key == rnp_tests_key_search(key_store, "key-merge-uid-1"));
+
+ /* load key + user id 2 with sigs */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-uid-2.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ /* try to add it twice */
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 1);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_true(key->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_true(key == rnp_tests_key_search(key_store, "key-merge-uid-1"));
+ assert_true(key == rnp_tests_key_search(key_store, "key-merge-uid-2"));
+
+ /* load key + subkey 1 without sigs */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-subkey-1-no-sigs.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 2);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_true(key->valid());
+ assert_false(skey1->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->subkey_count(), 1);
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey1->uid_count(), 0);
+ assert_int_equal(skey1->rawpkt_count(), 1);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+
+ /* load just subkey 1 but with signature */
+ assert_true(load_transferable_subkey(&tskey, MERGE_PATH "key-pub-no-key-subkey-1.pgp"));
+ assert_true(rnp_key_store_add_transferable_subkey(key_store, &tskey, key));
+ /* try to add it twice */
+ assert_true(rnp_key_store_add_transferable_subkey(key_store, &tskey, key));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 2);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_true(key->valid());
+ assert_true(skey1->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->subkey_count(), 1);
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey1->uid_count(), 0);
+ assert_int_equal(skey1->rawpkt_count(), 2);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_int_equal(skey1->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ /* load key + subkey 2 with signature */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub-subkey-2.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ /* try to add it twice */
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_true(key->valid());
+ assert_true(skey1->valid());
+ assert_true(skey2->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->subkey_count(), 2);
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_true(check_subkey_fp(key, skey2, 1));
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey1->uid_count(), 0);
+ assert_int_equal(skey1->rawpkt_count(), 2);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_int_equal(skey1->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey2->uid_count(), 0);
+ assert_int_equal(skey2->rawpkt_count(), 2);
+ assert_int_equal(skey2->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_int_equal(skey2->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ /* load secret key & subkeys */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-sec-no-uid-no-sigs.pgp"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ /* try to add it twice */
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_true(key->valid());
+ assert_true(skey1->valid());
+ assert_true(skey2->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->subkey_count(), 2);
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_true(check_subkey_fp(key, skey2, 1));
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_SECRET_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey1->uid_count(), 0);
+ assert_int_equal(skey1->rawpkt_count(), 2);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(skey1->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey2->uid_count(), 0);
+ assert_int_equal(skey2->rawpkt_count(), 2);
+ assert_int_equal(skey2->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(skey2->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+
+ assert_true(key->unlock(provider));
+ assert_true(skey1->unlock(provider));
+ assert_true(skey2->unlock(provider));
+
+ /* load the whole public + secret key */
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-pub.asc"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_true(load_transferable_key(&tkey, MERGE_PATH "key-sec.asc"));
+ assert_true(rnp_key_store_add_transferable_key(key_store, &tkey));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_true(key->valid());
+ assert_true(skey1->valid());
+ assert_true(skey2->valid());
+ assert_int_equal(key->uid_count(), 2);
+ assert_int_equal(key->subkey_count(), 2);
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_true(check_subkey_fp(key, skey2, 1));
+ assert_int_equal(key->rawpkt_count(), 5);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_SECRET_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(key->get_uid(1).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(1).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey1->uid_count(), 0);
+ assert_int_equal(skey1->rawpkt_count(), 2);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(skey1->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_int_equal(skey2->uid_count(), 0);
+ assert_int_equal(skey2->rawpkt_count(), 2);
+ assert_int_equal(skey2->rawpkt().tag, PGP_PKT_SECRET_SUBKEY);
+ assert_int_equal(skey2->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_true(key == rnp_tests_key_search(key_store, "key-merge-uid-1"));
+ assert_true(key == rnp_tests_key_search(key_store, "key-merge-uid-2"));
+
+ delete key_store;
+}
+
+TEST_F(rnp_tests, test_load_public_from_secret)
+{
+ rnp_key_store_t *secstore =
+ new rnp_key_store_t(PGP_KEY_STORE_GPG, MERGE_PATH "key-sec.asc", global_ctx);
+ assert_true(rnp_key_store_load_from_path(secstore, NULL));
+ rnp_key_store_t *pubstore =
+ new rnp_key_store_t(PGP_KEY_STORE_GPG, "pubring.gpg", global_ctx);
+
+ std::string keyid = "9747D2A6B3A63124";
+ std::string sub1id = "AF1114A47F5F5B28";
+ std::string sub2id = "16CD16F267CCDD4F";
+
+ pgp_key_t *key = NULL, *skey1 = NULL, *skey2 = NULL;
+ assert_non_null(key = rnp_tests_get_key_by_id(secstore, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(secstore, sub1id));
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(secstore, sub2id));
+
+ /* copy the secret key */
+ pgp_key_t keycp = pgp_key_t(*key, false);
+ assert_true(keycp.is_secret());
+ assert_int_equal(keycp.subkey_count(), 2);
+ assert_true(keycp.get_subkey_fp(0) == skey1->fp());
+ assert_true(keycp.get_subkey_fp(1) == skey2->fp());
+ assert_true(keycp.grip() == key->grip());
+ assert_int_equal(keycp.rawpkt().tag, PGP_PKT_SECRET_KEY);
+
+ /* copy the public part */
+ keycp = pgp_key_t(*key, true);
+ assert_false(keycp.is_secret());
+ assert_int_equal(keycp.subkey_count(), 2);
+ assert_true(check_subkey_fp(&keycp, skey1, 0));
+ assert_true(check_subkey_fp(&keycp, skey2, 1));
+ assert_true(keycp.grip() == key->grip());
+ assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_null(keycp.pkt().sec_data);
+ assert_int_equal(keycp.pkt().sec_len, 0);
+ assert_false(keycp.pkt().material.secret);
+ rnp_key_store_add_key(pubstore, &keycp);
+ /* subkey 1 */
+ keycp = pgp_key_t(*skey1, true);
+ assert_false(keycp.is_secret());
+ assert_int_equal(keycp.subkey_count(), 0);
+ assert_true(check_subkey_fp(key, &keycp, 0));
+ assert_true(keycp.grip() == skey1->grip());
+ assert_true(cmp_keyid(keycp.keyid(), sub1id));
+ assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_null(keycp.pkt().sec_data);
+ assert_int_equal(keycp.pkt().sec_len, 0);
+ assert_false(keycp.pkt().material.secret);
+ rnp_key_store_add_key(pubstore, &keycp);
+ /* subkey 2 */
+ keycp = pgp_key_t(*skey2, true);
+ assert_false(keycp.is_secret());
+ assert_int_equal(keycp.subkey_count(), 0);
+ assert_true(check_subkey_fp(key, &keycp, 1));
+ assert_true(keycp.grip() == skey2->grip());
+ assert_true(cmp_keyid(keycp.keyid(), sub2id));
+ assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_null(keycp.pkt().sec_data);
+ assert_int_equal(keycp.pkt().sec_len, 0);
+ assert_false(keycp.pkt().material.secret);
+ rnp_key_store_add_key(pubstore, &keycp);
+ /* save pubring */
+ assert_true(rnp_key_store_write_to_path(pubstore));
+ delete pubstore;
+ /* reload */
+ pubstore = new rnp_key_store_t(PGP_KEY_STORE_GPG, "pubring.gpg", global_ctx);
+ assert_true(rnp_key_store_load_from_path(pubstore, NULL));
+ assert_non_null(key = rnp_tests_get_key_by_id(pubstore, keyid));
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(pubstore, sub1id));
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(pubstore, sub2id));
+
+ delete pubstore;
+ delete secstore;
+}
+
+TEST_F(rnp_tests, test_key_import)
+{
+ cli_rnp_t rnp = {};
+ pgp_transferable_key_t tkey = {};
+ pgp_transferable_subkey_t *tskey = NULL;
+ pgp_transferable_userid_t *tuid = NULL;
+
+ assert_int_equal(RNP_MKDIR(".rnp", S_IRWXU), 0);
+ assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_GPG, ".rnp", NULL));
+
+ /* import just the public key */
+ rnp_cfg &cfg = rnp.cfg();
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-pub-just-key.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ size_t keycount = 0;
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 1);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 0);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_true(tkey.subkeys.empty());
+ assert_true(tkey.signatures.empty());
+ assert_true(tkey.userids.empty());
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+
+ /* import public key + 1 userid */
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-pub-uid-1-no-sigs.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 1);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 0);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_true(tkey.subkeys.empty());
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 1);
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_true(tuid->signatures.empty());
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+
+ /* import public key + 1 userid + signature */
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-pub-uid-1.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 1);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 0);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_true(tkey.subkeys.empty());
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 1);
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+
+ /* import public key + 1 subkey */
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-pub-subkey-1.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 2);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 0);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_int_equal(tkey.subkeys.size(), 1);
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 1);
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tskey = &tkey.subkeys.front());
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_PUBLIC_SUBKEY);
+
+ /* import secret key with 1 uid and 1 subkey */
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-sec-uid-1-subkey-1.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 2);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 2);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_int_equal(tkey.subkeys.size(), 1);
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 1);
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tskey = &tkey.subkeys.front());
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_PUBLIC_SUBKEY);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/secring.gpg"));
+ assert_int_equal(tkey.subkeys.size(), 1);
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 1);
+ assert_int_equal(tkey.key.tag, PGP_PKT_SECRET_KEY);
+ assert_rnp_success(decrypt_secret_key(&tkey.key, "password"));
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tskey = &tkey.subkeys.front());
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_SECRET_SUBKEY);
+ assert_rnp_success(decrypt_secret_key(&tskey->subkey, "password"));
+
+ /* import secret key with 2 uids and 2 subkeys */
+ cfg.set_str(CFG_KEYFILE, MERGE_PATH "key-sec.pgp");
+ assert_true(cli_rnp_add_key(&rnp));
+ assert_true(cli_rnp_save_keyrings(&rnp));
+ assert_rnp_success(rnp_get_public_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 3);
+ assert_rnp_success(rnp_get_secret_key_count(rnp.ffi, &keycount));
+ assert_int_equal(keycount, 3);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/pubring.gpg"));
+ assert_int_equal(tkey.subkeys.size(), 2);
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 2);
+ assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY);
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tuid = &tkey.userids[1]);
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-2", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tskey = &tkey.subkeys.front());
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_non_null(tskey = &tkey.subkeys[1]);
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_PUBLIC_SUBKEY);
+
+ assert_true(load_transferable_key(&tkey, ".rnp/secring.gpg"));
+ assert_int_equal(tkey.subkeys.size(), 2);
+ assert_true(tkey.signatures.empty());
+ assert_int_equal(tkey.userids.size(), 2);
+ assert_int_equal(tkey.key.tag, PGP_PKT_SECRET_KEY);
+ assert_rnp_success(decrypt_secret_key(&tkey.key, "password"));
+ assert_non_null(tuid = &tkey.userids.front());
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tuid = &tkey.userids[1]);
+ assert_int_equal(tuid->signatures.size(), 1);
+ assert_false(memcmp(tuid->uid.uid, "key-merge-uid-2", 15));
+ assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID);
+ assert_non_null(tskey = &tkey.subkeys.front());
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_SECRET_SUBKEY);
+ assert_rnp_success(decrypt_secret_key(&tskey->subkey, "password"));
+ assert_non_null(tskey = &tkey.subkeys[1]);
+ assert_int_equal(tskey->signatures.size(), 1);
+ assert_int_equal(tskey->subkey.tag, PGP_PKT_SECRET_SUBKEY);
+ assert_rnp_success(decrypt_secret_key(&tskey->subkey, "password"));
+
+ rnp.end();
+}
+
+TEST_F(rnp_tests, test_load_subkey)
+{
+ rnp_key_store_t *key_store = new rnp_key_store_t(PGP_KEY_STORE_GPG, "", global_ctx);
+ std::string keyid = "9747D2A6B3A63124";
+ std::string sub1id = "AF1114A47F5F5B28";
+ std::string sub2id = "16CD16F267CCDD4F";
+
+ /* load first subkey with signature */
+ pgp_key_t *key = NULL, *skey1 = NULL, *skey2 = NULL;
+ assert_true(load_keystore(key_store, MERGE_PATH "key-pub-just-subkey-1.pgp"));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 1);
+ assert_non_null(skey1 = rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_false(skey1->valid());
+ assert_int_equal(skey1->rawpkt_count(), 2);
+ assert_int_equal(skey1->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_int_equal(skey1->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_false(skey1->has_primary_fp());
+
+ /* load second subkey, without signature */
+ assert_true(load_keystore(key_store, MERGE_PATH "key-pub-just-subkey-2-no-sigs.pgp"));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 2);
+ assert_non_null(skey2 = rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_false(skey2->valid());
+ assert_int_equal(skey2->rawpkt_count(), 1);
+ assert_int_equal(skey2->rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY);
+ assert_false(skey2->has_primary_fp());
+ assert_false(skey1 == skey2);
+
+ /* load primary key without subkey signatures */
+ assert_true(load_keystore(key_store, MERGE_PATH "key-pub-uid-1.pgp"));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+ assert_non_null(key = rnp_tests_get_key_by_id(key_store, keyid));
+ assert_true(key->valid());
+ assert_int_equal(key->rawpkt_count(), 3);
+ assert_int_equal(key->rawpkt().tag, PGP_PKT_PUBLIC_KEY);
+ assert_int_equal(key->get_uid(0).rawpkt.tag, PGP_PKT_USER_ID);
+ assert_int_equal(key->get_sig(0).rawpkt.tag, PGP_PKT_SIGNATURE);
+ assert_true(skey1 == rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_true(skey2 == rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_true(skey1->has_primary_fp());
+ assert_true(check_subkey_fp(key, skey1, 0));
+ assert_int_equal(key->subkey_count(), 1);
+ assert_true(skey1->valid());
+ assert_false(skey2->valid());
+
+ /* load second subkey with signature */
+ assert_true(load_keystore(key_store, MERGE_PATH "key-pub-just-subkey-2.pgp"));
+ assert_int_equal(rnp_key_store_get_key_count(key_store), 3);
+ assert_true(key == rnp_tests_get_key_by_id(key_store, keyid));
+ assert_true(skey1 == rnp_tests_get_key_by_id(key_store, sub1id));
+ assert_true(skey2 == rnp_tests_get_key_by_id(key_store, sub2id));
+ assert_true(skey2->has_primary_fp());
+ assert_true(check_subkey_fp(key, skey2, 1));
+ assert_int_equal(key->subkey_count(), 2);
+ assert_true(skey2->valid());
+
+ delete key_store;
+}