/* * 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; }