Revision control

Copy as Markdown

Other Tools

/*
* 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[],
rnp::SecurityContext &global_ctx)
{
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, global_ctx);
// check secring
check_pgp_keyring_counts(
"data/keyrings/1/secring.gpg", primary_count, subkey_counts, global_ctx);
}
/* 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;
}