Revision control

Copy as Markdown

Other Tools

/*
* Copyright (c) 2022-2023 [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 <rnp/rnp.h>
#include "rnp_tests.h"
#include "support.h"
#include <librepgp/stream-ctx.h>
#include "pgp-key.h"
#include "ffi-priv-types.h"
#include "str-utils.h"
#ifndef RNP_USE_STD_REGEX
#include <regex.h>
#else
#include <regex>
#endif
static void
check_key_properties(rnp_key_handle_t key,
bool primary_exptected,
bool have_public_expected,
bool have_secret_expected)
{
bool isprimary = !primary_exptected;
assert_rnp_success(rnp_key_is_primary(key, &isprimary));
assert_true(isprimary == primary_exptected);
bool issub = primary_exptected;
assert_rnp_success(rnp_key_is_sub(key, &issub));
assert_true(issub == !primary_exptected);
bool have_public = !have_public_expected;
assert_rnp_success(rnp_key_have_public(key, &have_public));
assert_true(have_public == have_public_expected);
bool have_secret = !have_secret_expected;
assert_rnp_success(rnp_key_have_secret(key, &have_secret));
assert_true(have_secret == have_secret_expected);
}
TEST_F(rnp_tests, test_ffi_keygen_json_pair)
{
rnp_ffi_t ffi = NULL;
char * results = NULL;
size_t count = 0;
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "abc"));
// load our JSON
auto json = file_to_str("data/test_ffi_json/generate-pair.json");
// generate the keys
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// parse the results JSON
json_object *parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle for the primary
rnp_key_handle_t primary = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "primary", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &primary));
assert_non_null(primary);
}
// get a handle for the sub
rnp_key_handle_t sub = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "sub", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &sub));
assert_non_null(sub);
}
// cleanup
json_object_put(parsed_results);
// check the key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(2, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(2, count);
// check some key properties
check_key_properties(primary, true, true, true);
check_key_properties(sub, false, true, true);
// check sub bit length
uint32_t length = 0;
assert_rnp_success(rnp_key_get_bits(sub, &length));
assert_int_equal(1024, length);
// cleanup
rnp_key_handle_destroy(primary);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_keygen_json_pair_dsa_elg)
{
rnp_ffi_t ffi = NULL;
char * results = NULL;
size_t count = 0;
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "abc"));
// load our JSON
auto json = file_to_str("data/test_ffi_json/generate-pair-dsa-elg.json");
// generate the keys
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// parse the results JSON
json_object *parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle for the primary
rnp_key_handle_t primary = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "primary", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &primary));
assert_non_null(primary);
}
// get a handle for the sub
rnp_key_handle_t sub = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "sub", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &sub));
assert_non_null(sub);
}
// cleanup
json_object_put(parsed_results);
// check the key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(2, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(2, count);
// check some key properties
check_key_properties(primary, true, true, true);
check_key_properties(sub, false, true, true);
// check bit lengths
uint32_t length = 0;
assert_rnp_success(rnp_key_get_bits(primary, &length));
assert_int_equal(length, 1024);
assert_rnp_success(rnp_key_get_bits(sub, &length));
assert_int_equal(length, 1536);
// cleanup
rnp_key_handle_destroy(primary);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_keygen_json_primary)
{
rnp_ffi_t ffi = NULL;
char * results = NULL;
size_t count = 0;
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(rnp_ffi_set_pass_provider(ffi, unused_getpasscb, NULL));
// load our JSON
auto json = file_to_str("data/test_ffi_json/generate-primary.json");
// generate the keys
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// parse the results JSON
json_object *parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle for the primary
rnp_key_handle_t primary = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "primary", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &primary));
assert_non_null(primary);
}
// cleanup
json_object_put(parsed_results);
parsed_results = NULL;
// check the key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(1, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(1, count);
// check some key properties
check_key_properties(primary, true, true, true);
// cleanup
rnp_key_handle_destroy(primary);
rnp_ffi_destroy(ffi);
}
/* This test generates a primary key, and then a subkey (separately).
*/
TEST_F(rnp_tests, test_ffi_keygen_json_sub)
{
char * results = NULL;
size_t count = 0;
rnp_ffi_t ffi = NULL;
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(rnp_ffi_set_pass_provider(ffi, unused_getpasscb, NULL));
// generate our primary key
auto json = file_to_str("data/test_ffi_json/generate-primary.json");
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
// check key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(1, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(1, count);
// parse the results JSON
json_object *parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle+grip for the primary
rnp_key_handle_t primary = NULL;
char * primary_grip = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "primary", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
primary_grip = strdup(json_object_get_string(jsogrip));
assert_non_null(primary_grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", primary_grip, &primary));
assert_non_null(primary);
}
// cleanup
json_object_put(parsed_results);
parsed_results = NULL;
// load our JSON template
json = file_to_str("data/test_ffi_json/generate-sub.json");
// modify our JSON
{
// parse
json_object *jso = json_tokener_parse(json.c_str());
assert_non_null(jso);
// find the relevant fields
json_object *jsosub = NULL;
json_object *jsoprimary = NULL;
assert_true(json_object_object_get_ex(jso, "sub", &jsosub));
assert_non_null(jsosub);
assert_true(json_object_object_get_ex(jsosub, "primary", &jsoprimary));
assert_non_null(jsoprimary);
// replace the placeholder grip with the correct one
json_object_object_del(jsoprimary, "grip");
json_object_object_add(jsoprimary, "grip", json_object_new_string(primary_grip));
assert_int_equal(1, json_object_object_length(jsoprimary));
json = json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY);
assert_false(json.empty());
json_object_put(jso);
}
// cleanup
rnp_buffer_destroy(primary_grip);
primary_grip = NULL;
// generate the subkey
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// parse the results JSON
parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle for the sub
rnp_key_handle_t sub = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "sub", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &sub));
assert_non_null(sub);
}
// cleanup
json_object_put(parsed_results);
parsed_results = NULL;
// check the key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(2, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(2, count);
// check some key properties
check_key_properties(primary, true, true, true);
check_key_properties(sub, false, true, true);
// check sub bit length
uint32_t length = 0;
assert_rnp_success(rnp_key_get_bits(sub, &length));
assert_int_equal(length, 1024);
// cleanup
rnp_key_handle_destroy(primary);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_keygen_json_edge_cases)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* Attempt to generate with invalid parameters */
std::string json = "";
char * results = NULL;
assert_rnp_failure(rnp_generate_key_json(NULL, json.c_str(), &results));
assert_rnp_failure(rnp_generate_key_json(ffi, NULL, &results));
assert_rnp_failure(rnp_generate_key_json(ffi, "{ something, wrong }", &results));
assert_rnp_failure(rnp_generate_key_json(ffi, "{ }", &results));
assert_rnp_failure(
rnp_generate_key_json(ffi, "{ \"primary\": { }, \"wrong\": {} }", &results));
assert_rnp_failure(
rnp_generate_key_json(ffi, "{ \"primary\": { }, \"PRIMARY\": { } }", &results));
/* Json-C puts stuff under the same key into the single object */
assert_rnp_success(
rnp_generate_key_json(ffi, "{ \"primary\": { }, \"primary\": { } }", &results));
rnp_buffer_destroy(results);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
/* Generate key with an empty description */
assert_rnp_success(rnp_generate_key_json(ffi, "{ \"priMary\": {} }", &results));
assert_non_null(results);
rnp_buffer_destroy(results);
size_t count = 0;
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(count, 1);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
/* Generate with wrong preferences */
json = file_to_str("data/test_ffi_json/generate-eddsa-wrong-prefs.json");
assert_rnp_failure(rnp_generate_key_json(ffi, json.c_str(), &results));
/* Generate with wrong PK algorithm */
json = file_to_str("data/test_ffi_json/generate-bad-pk-alg.json");
results = NULL;
assert_rnp_failure(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_null(results);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(count, 0);
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(count, 0);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_generate_misc)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* make sure we do not leak key handle and do not access NULL */
assert_rnp_success(rnp_generate_key_rsa(ffi, 1024, 1024, "rsa", NULL, NULL));
/* make sure we do not leak password on failed key generation */
rnp_key_handle_t key = NULL;
assert_rnp_failure(rnp_generate_key_rsa(ffi, 768, 2048, "rsa_768", "password", &key));
assert_rnp_failure(rnp_generate_key_rsa(ffi, 1024, 768, "rsa_768", "password", &key));
/* make sure we behave correctly and do not leak data on wrong parameters to _generate_ex
* function */
assert_rnp_failure(rnp_generate_key_ex(
ffi, "RSA", "RSA", 1024, 1024, "Curve", NULL, "userid", "password", &key));
assert_rnp_failure(rnp_generate_key_ex(
ffi, "RSA", "RSA", 1024, 1024, "Curve", NULL, NULL, "password", &key));
assert_rnp_failure(rnp_generate_key_ex(
ffi, "RSA", "RSA", 1024, 768, NULL, "Curve", NULL, "password", &key));
assert_rnp_failure(rnp_generate_key_ex(
ffi, "ECDSA", "ECDH", 1024, 0, "Unknown", "Curve", NULL, NULL, &key));
assert_rnp_failure(rnp_generate_key_ex(
ffi, "ECDSA", "ECDH", 0, 1024, "Unknown", "Curve", NULL, "password", &key));
/* generate RSA-RSA key without password */
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "abc"));
assert_rnp_success(rnp_generate_key_rsa(ffi, 1024, 1024, "rsa_1024", NULL, &key));
assert_non_null(key);
bool locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_false(locked);
/* check key and subkey flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
uint32_t expiration = 0;
assert_rnp_success(rnp_key_get_expiration(key, &expiration));
assert_int_equal(expiration, 2 * 365 * 24 * 60 * 60);
uint32_t creation = 0;
assert_rnp_success(rnp_key_get_creation(key, &creation));
uint32_t till = 0;
assert_rnp_success(rnp_key_valid_till(key, &till));
assert_int_equal(till, creation + expiration);
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
expiration = 0;
assert_rnp_success(rnp_key_get_expiration(subkey, &expiration));
assert_int_equal(expiration, 2 * 365 * 24 * 60 * 60);
creation = 0;
assert_rnp_success(rnp_key_get_creation(key, &creation));
till = 0;
assert_rnp_success(rnp_key_valid_till(key, &till));
assert_int_equal(till, creation + expiration);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate encrypted RSA-RSA key */
assert_rnp_success(rnp_generate_key_rsa(ffi, 1024, 1024, "rsa_1024", "123", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
/* make sure it can be unlocked with correct password */
assert_rnp_success(rnp_key_unlock(key, "123"));
/* do the same for subkey */
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_key_is_locked(subkey, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_unlock(subkey, "123"));
/* cleanup */
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate encrypted RSA key (primary only) */
key = NULL;
assert_rnp_success(
rnp_generate_key_ex(ffi, "RSA", NULL, 1024, 0, NULL, NULL, "rsa_1024", "123", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
bool prot = false;
assert_rnp_success(rnp_key_is_protected(key, &prot));
assert_true(prot);
/* cleanup */
rnp_key_handle_destroy(key);
/* generate key with signing subkey */
rnp_op_generate_t op = NULL;
assert_rnp_success(rnp_op_generate_create(&op, ffi, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(op, "secp256k1"));
assert_rnp_success(rnp_op_generate_set_userid(op, "ecdsa_ecdsa"));
assert_rnp_success(rnp_op_generate_add_usage(op, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(op, "certify"));
assert_rnp_success(rnp_op_generate_set_expiration(op, 0));
assert_rnp_success(rnp_op_generate_execute(op));
rnp_key_handle_t primary = NULL;
assert_rnp_success(rnp_op_generate_get_key(op, &primary));
rnp_op_generate_destroy(op);
char *keyid = NULL;
assert_rnp_success(rnp_key_get_keyid(primary, &keyid));
rnp_op_generate_t subop = NULL;
assert_rnp_success(rnp_op_generate_subkey_create(&subop, ffi, primary, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(subop, "NIST P-256"));
assert_rnp_success(rnp_op_generate_add_usage(subop, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(subop, "certify"));
assert_rnp_success(rnp_op_generate_set_expiration(subop, 0));
assert_rnp_success(rnp_op_generate_execute(subop));
assert_rnp_success(rnp_op_generate_get_key(subop, &subkey));
rnp_op_generate_destroy(subop);
char *subid = NULL;
assert_rnp_success(rnp_key_get_keyid(subkey, &subid));
rnp_output_t output = NULL;
rnp_output_to_memory(&output, 0);
assert_rnp_success(
rnp_key_export(primary,
output,
RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_SUBKEYS));
rnp_key_handle_destroy(primary);
rnp_key_handle_destroy(subkey);
uint8_t *buf = NULL;
size_t len = 0;
rnp_output_memory_get_buf(output, &buf, &len, false);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, buf, len));
assert_rnp_success(rnp_locate_key(ffi, "keyid", keyid, &primary));
assert_non_null(primary);
assert_true(primary->pub->valid());
bool valid = false;
assert_rnp_failure(rnp_key_is_valid(primary, NULL));
assert_rnp_failure(rnp_key_is_valid(NULL, &valid));
assert_rnp_success(rnp_key_is_valid(primary, &valid));
assert_true(valid);
till = 0;
assert_rnp_failure(rnp_key_valid_till(primary, NULL));
assert_rnp_failure(rnp_key_valid_till(NULL, &till));
assert_rnp_success(rnp_key_valid_till(primary, &till));
assert_int_equal(till, 0xffffffff);
uint64_t till64 = 0;
assert_rnp_failure(rnp_key_valid_till64(primary, NULL));
assert_rnp_failure(rnp_key_valid_till64(NULL, &till64));
assert_rnp_success(rnp_key_valid_till64(primary, &till64));
assert_int_equal(till64, UINT64_MAX);
rnp_key_handle_destroy(primary);
assert_rnp_success(rnp_locate_key(ffi, "keyid", subid, &subkey));
assert_non_null(subkey);
assert_true(subkey->pub->valid());
valid = false;
assert_rnp_success(rnp_key_is_valid(subkey, &valid));
assert_true(valid);
till = 0;
assert_rnp_success(rnp_key_valid_till(subkey, &till));
assert_int_equal(till, 0xffffffff);
assert_rnp_success(rnp_key_valid_till64(subkey, &till64));
assert_int_equal(till64, UINT64_MAX);
rnp_key_handle_destroy(subkey);
rnp_buffer_destroy(keyid);
rnp_buffer_destroy(subid);
rnp_output_destroy(output);
/* cleanup */
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_sec_key_offline_operations)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* generate subkey for offline secret key */
assert_true(import_all_keys(ffi, "data/test_key_edge_cases/alice-s2k-101-1-subs.pgp"));
rnp_key_handle_t primary = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &primary));
rnp_op_generate_t subop = NULL;
assert_rnp_failure(rnp_op_generate_subkey_create(&subop, ffi, primary, "ECDSA"));
/* unlock/unprotect offline secret key */
assert_rnp_failure(rnp_key_unlock(primary, "password"));
assert_rnp_failure(rnp_key_unprotect(primary, "password"));
/* add userid */
assert_int_equal(rnp_key_add_uid(primary, "new_uid", "SHA256", 2147317200, 0x00, false),
RNP_ERROR_NO_SUITABLE_KEY);
rnp_key_handle_destroy(primary);
/* generate subkey for offline secret key on card */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_all_keys(ffi, "data/test_key_edge_cases/alice-s2k-101-2-card.pgp"));
primary = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &primary));
subop = NULL;
assert_rnp_failure(rnp_op_generate_subkey_create(&subop, ffi, primary, "ECDSA"));
rnp_key_handle_destroy(primary);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_generate_rsa)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* make sure we fail to generate too small and too large keys/subkeys */
rnp_key_handle_t key = NULL;
assert_rnp_failure(rnp_generate_key_rsa(ffi, 768, 2048, "rsa_768", NULL, &key));
assert_rnp_failure(rnp_generate_key_rsa(ffi, 1024, 768, "rsa_768", NULL, &key));
assert_rnp_failure(rnp_generate_key_rsa(ffi, 20480, 1024, "rsa_20480", NULL, &key));
assert_rnp_failure(rnp_generate_key_rsa(ffi, 1024, 20480, "rsa_20480", NULL, &key));
/* generate RSA-RSA key */
assert_rnp_success(rnp_generate_key_rsa(ffi, 1024, 2048, "rsa_1024", NULL, &key));
assert_non_null(key);
/* check properties of the generated key */
bool boolres = false;
assert_rnp_success(rnp_key_is_primary(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_public(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(key, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(key, &boolres));
assert_false(boolres);
/* algorithm */
char *alg = NULL;
assert_rnp_success(rnp_key_get_alg(key, &alg));
assert_int_equal(strcasecmp(alg, "RSA"), 0);
rnp_buffer_destroy(alg);
/* key bits */
uint32_t bits = 0;
assert_rnp_failure(rnp_key_get_bits(key, NULL));
assert_rnp_success(rnp_key_get_bits(key, &bits));
assert_int_equal(bits, 1024);
assert_rnp_failure(rnp_key_get_dsa_qbits(key, &bits));
/* key flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* curve - must fail */
char *curve = NULL;
assert_rnp_failure(rnp_key_get_curve(key, NULL));
assert_rnp_failure(rnp_key_get_curve(key, &curve));
assert_null(curve);
/* user ids */
size_t uids = 0;
char * uid = NULL;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
assert_rnp_failure(rnp_key_get_uid_at(key, 1, &uid));
assert_null(uid);
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "rsa_1024");
rnp_buffer_destroy(uid);
/* subkey */
size_t subkeys = 0;
assert_rnp_failure(rnp_key_get_subkey_count(key, NULL));
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 1);
rnp_key_handle_t subkey = NULL;
assert_rnp_failure(rnp_key_get_subkey_at(key, 1, &subkey));
assert_rnp_failure(rnp_key_get_subkey_at(key, 0, NULL));
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
/* check properties of the generated subkey */
assert_rnp_success(rnp_key_is_primary(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_have_public(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(subkey, &boolres));
assert_false(boolres);
/* algorithm */
assert_rnp_success(rnp_key_get_alg(subkey, &alg));
assert_int_equal(strcasecmp(alg, "RSA"), 0);
rnp_buffer_destroy(alg);
/* key bits */
assert_rnp_success(rnp_key_get_bits(subkey, &bits));
assert_int_equal(bits, 2048);
/* subkey flags */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
/* cleanup */
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
/* generate RSA key without the subkey */
assert_rnp_success(rnp_generate_key_rsa(ffi, 1024, 0, "rsa_1024", NULL, &key));
assert_non_null(key);
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 0);
/* cleanup */
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_dsa)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* try to generate keys with invalid sizes */
rnp_key_handle_t key = NULL;
assert_rnp_failure(rnp_generate_key_dsa_eg(ffi, 768, 2048, "dsa_768", NULL, &key));
assert_rnp_failure(rnp_generate_key_dsa_eg(ffi, 1024, 768, "dsa_768", NULL, &key));
assert_rnp_failure(rnp_generate_key_dsa_eg(ffi, 4096, 1024, "dsa_20480", NULL, &key));
assert_rnp_failure(rnp_generate_key_dsa_eg(ffi, 1024, 20480, "dsa_20480", NULL, &key));
/* generate DSA-ElGamal keypair */
assert_rnp_success(rnp_generate_key_dsa_eg(ffi, 1024, 1024, "dsa_1024", NULL, &key));
assert_non_null(key);
/* check properties of the generated key */
bool boolres = false;
assert_rnp_success(rnp_key_is_primary(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_public(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(key, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(key, &boolres));
assert_false(boolres);
/* algorithm */
char *alg = NULL;
assert_rnp_success(rnp_key_get_alg(key, &alg));
assert_int_equal(strcasecmp(alg, "DSA"), 0);
rnp_buffer_destroy(alg);
/* key bits */
uint32_t bits = 0;
assert_rnp_success(rnp_key_get_bits(key, &bits));
assert_int_equal(bits, 1024);
assert_rnp_success(rnp_key_get_dsa_qbits(key, &bits));
assert_int_equal(bits, 160);
/* key flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* user ids */
size_t uids = 0;
char * uid = NULL;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "dsa_1024");
rnp_buffer_destroy(uid);
/* subkey */
size_t subkeys = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 1);
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
/* check properties of the generated subkey */
assert_rnp_success(rnp_key_is_primary(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_have_public(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(subkey, &boolres));
assert_false(boolres);
/* algorithm */
assert_rnp_success(rnp_key_get_alg(subkey, &alg));
assert_int_equal(strcasecmp(alg, "ELGAMAL"), 0);
rnp_buffer_destroy(alg);
/* key bits */
assert_rnp_success(rnp_key_get_bits(subkey, &bits));
assert_int_equal(bits, 1024);
/* subkey flags */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
/* cleanup */
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
/* generate DSA key without the subkey */
assert_rnp_success(rnp_generate_key_dsa_eg(ffi, 1024, 0, "dsa_1024", NULL, &key));
assert_non_null(key);
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 0);
/* cleanup */
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_ecdsa)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* try to generate key with invalid curve */
rnp_key_handle_t key = NULL;
assert_rnp_failure(rnp_generate_key_ec(ffi, "curve_wrong", "wrong", NULL, &key));
assert_null(key);
/* generate secp256k1 key */
assert_rnp_success(rnp_generate_key_ec(ffi, "secp256k1", "ec_256k1", NULL, &key));
assert_non_null(key);
/* check properties of the generated key */
bool boolres = false;
assert_rnp_success(rnp_key_is_primary(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_public(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(key, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(key, &boolres));
assert_false(boolres);
/* algorithm */
char *alg = NULL;
assert_rnp_success(rnp_key_get_alg(key, &alg));
assert_int_equal(strcasecmp(alg, "ECDSA"), 0);
rnp_buffer_destroy(alg);
/* key bits */
uint32_t bits = 0;
assert_rnp_success(rnp_key_get_bits(key, &bits));
assert_int_equal(bits, 256);
assert_rnp_failure(rnp_key_get_dsa_qbits(key, &bits));
/* curve */
char *curve = NULL;
assert_rnp_failure(rnp_key_get_curve(key, NULL));
assert_rnp_success(rnp_key_get_curve(key, &curve));
assert_int_equal(strcasecmp(curve, "secp256k1"), 0);
rnp_buffer_destroy(curve);
/* key flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* user ids */
size_t uids = 0;
char * uid = NULL;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "ec_256k1");
rnp_buffer_destroy(uid);
/* subkey */
size_t subkeys = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 1);
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
/* check properties of the generated subkey */
assert_rnp_success(rnp_key_is_primary(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_have_public(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(subkey, &boolres));
assert_false(boolres);
/* algorithm */
assert_rnp_success(rnp_key_get_alg(subkey, &alg));
assert_int_equal(strcasecmp(alg, "ECDH"), 0);
rnp_buffer_destroy(alg);
/* bits */
assert_rnp_success(rnp_key_get_bits(subkey, &bits));
assert_int_equal(bits, 256);
/* curve */
curve = NULL;
assert_rnp_success(rnp_key_get_curve(subkey, &curve));
assert_int_equal(strcasecmp(curve, "secp256k1"), 0);
rnp_buffer_destroy(curve);
/* subkey flags */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_eddsa)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* generate key with subkey */
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_generate_key_25519(ffi, "eddsa_25519", NULL, &key));
assert_non_null(key);
/* check properties of the generated key */
bool boolres = false;
assert_rnp_success(rnp_key_is_primary(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_public(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(key, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(key, &boolres));
assert_false(boolres);
/* algorithm */
char *alg = NULL;
assert_rnp_success(rnp_key_get_alg(key, &alg));
assert_int_equal(strcasecmp(alg, "EDDSA"), 0);
rnp_buffer_destroy(alg);
/* key bits */
uint32_t bits = 0;
assert_rnp_success(rnp_key_get_bits(key, &bits));
assert_int_equal(bits, 255);
/* curve */
char *curve = NULL;
assert_rnp_success(rnp_key_get_curve(key, &curve));
assert_int_equal(strcasecmp(curve, "ed25519"), 0);
rnp_buffer_destroy(curve);
/* key flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* user ids */
size_t uids = 0;
char * uid = NULL;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "eddsa_25519");
rnp_buffer_destroy(uid);
/* subkey */
size_t subkeys = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 1);
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
/* check properties of the generated subkey */
assert_rnp_success(rnp_key_is_primary(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_have_public(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(subkey, &boolres));
assert_false(boolres);
/* algorithm */
assert_rnp_success(rnp_key_get_alg(subkey, &alg));
assert_int_equal(strcasecmp(alg, "ECDH"), 0);
rnp_buffer_destroy(alg);
/* key bits */
assert_rnp_success(rnp_key_get_bits(subkey, &bits));
assert_int_equal(bits, 255);
/* curve */
curve = NULL;
assert_rnp_success(rnp_key_get_curve(subkey, &curve));
assert_int_equal(strcasecmp(curve, "Curve25519"), 0);
rnp_buffer_destroy(curve);
/* subkey flags */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_sm2)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
/* generate sm2 key */
rnp_key_handle_t key = NULL;
if (!sm2_enabled()) {
assert_rnp_failure(rnp_generate_key_sm2(ffi, "sm2", NULL, &key));
assert_rnp_success(rnp_ffi_destroy(ffi));
return;
}
assert_rnp_success(rnp_generate_key_sm2(ffi, "sm2", NULL, &key));
assert_non_null(key);
/* check properties of the generated key */
bool boolres = false;
assert_rnp_success(rnp_key_is_primary(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_public(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(key, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(key, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(key, &boolres));
assert_false(boolres);
/* algorithm */
char *alg = NULL;
assert_rnp_success(rnp_key_get_alg(key, &alg));
assert_int_equal(strcasecmp(alg, "SM2"), 0);
rnp_buffer_destroy(alg);
/* key bits */
uint32_t bits = 0;
assert_rnp_success(rnp_key_get_bits(key, &bits));
assert_int_equal(bits, 256);
/* curve */
char *curve = NULL;
assert_rnp_success(rnp_key_get_curve(key, &curve));
assert_int_equal(strcasecmp(curve, "SM2 P-256"), 0);
rnp_buffer_destroy(curve);
/* key flags */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* user ids */
size_t uids = 0;
char * uid = NULL;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "sm2");
rnp_buffer_destroy(uid);
/* subkey */
size_t subkeys = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &subkeys));
assert_int_equal(subkeys, 1);
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
/* check properties of the generated subkey */
assert_rnp_success(rnp_key_is_primary(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_have_public(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_have_secret(subkey, &boolres));
assert_true(boolres);
assert_rnp_success(rnp_key_is_protected(subkey, &boolres));
assert_false(boolres);
assert_rnp_success(rnp_key_is_locked(subkey, &boolres));
assert_false(boolres);
/* algorithm */
assert_rnp_success(rnp_key_get_alg(subkey, &alg));
assert_int_equal(strcasecmp(alg, "SM2"), 0);
rnp_buffer_destroy(alg);
/* key bits */
assert_rnp_success(rnp_key_get_bits(subkey, &bits));
assert_int_equal(bits, 256);
/* curve */
curve = NULL;
assert_rnp_success(rnp_key_get_curve(subkey, &curve));
assert_int_equal(strcasecmp(curve, "SM2 P-256"), 0);
rnp_buffer_destroy(curve);
/* subkey flags */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_ex)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "123"));
/* Generate RSA key with misc options set */
rnp_op_generate_t keygen = NULL;
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_failure(rnp_op_generate_set_dsa_qbits(keygen, 256));
/* key usage */
assert_rnp_success(rnp_op_generate_clear_usage(keygen));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "usage"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "encrypt"));
/* preferred ciphers */
assert_rnp_success(rnp_op_generate_clear_pref_ciphers(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_cipher(keygen, "unknown"));
assert_true(!rnp_op_generate_add_pref_cipher(keygen, "BLOWFISH") == blowfish_enabled());
assert_rnp_success(rnp_op_generate_clear_pref_ciphers(keygen));
assert_rnp_success(rnp_op_generate_add_pref_cipher(keygen, "CAMELLIA256"));
assert_rnp_success(rnp_op_generate_add_pref_cipher(keygen, "AES256"));
/* preferred compression algorithms */
assert_rnp_success(rnp_op_generate_clear_pref_compression(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_compression(keygen, "unknown"));
assert_rnp_success(rnp_op_generate_add_pref_compression(keygen, "zlib"));
assert_rnp_success(rnp_op_generate_clear_pref_compression(keygen));
assert_rnp_success(rnp_op_generate_add_pref_compression(keygen, "zip"));
assert_rnp_success(rnp_op_generate_add_pref_compression(keygen, "zlib"));
/* preferred hash algorithms */
assert_rnp_success(rnp_op_generate_clear_pref_hashes(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_hash(keygen, "unknown"));
assert_rnp_success(rnp_op_generate_add_pref_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_clear_pref_hashes(keygen));
assert_rnp_success(rnp_op_generate_add_pref_hash(keygen, "SHA512"));
assert_rnp_success(rnp_op_generate_add_pref_hash(keygen, "SHA256"));
/* key expiration */
assert_rnp_success(rnp_op_generate_set_expiration(keygen, 60 * 60 * 24 * 100));
assert_rnp_success(rnp_op_generate_set_expiration(keygen, 60 * 60 * 24 * 300));
/* preferred key server */
assert_rnp_success(rnp_op_generate_set_pref_keyserver(keygen, NULL));
assert_rnp_success(rnp_op_generate_set_pref_keyserver(keygen, "hkp://first.server/"));
assert_rnp_success(rnp_op_generate_set_pref_keyserver(keygen, "hkp://second.server/"));
/* user id */
assert_rnp_failure(rnp_op_generate_set_userid(keygen, NULL));
assert_rnp_success(rnp_op_generate_set_userid(keygen, "userid_cleared"));
assert_rnp_success(rnp_op_generate_set_userid(keygen, "userid"));
/* protection */
assert_rnp_failure(rnp_op_generate_set_protection_cipher(keygen, NULL));
assert_rnp_failure(rnp_op_generate_set_protection_cipher(keygen, "unknown"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES256"));
assert_rnp_failure(rnp_op_generate_set_protection_hash(keygen, NULL));
assert_rnp_failure(rnp_op_generate_set_protection_hash(keygen, "unknown"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA256"));
assert_rnp_success(rnp_op_generate_set_protection_iterations(keygen, 65536));
assert_rnp_failure(rnp_op_generate_set_protection_mode(keygen, NULL));
assert_rnp_failure(rnp_op_generate_set_protection_mode(keygen, "unknown"));
assert_rnp_success(rnp_op_generate_set_protection_mode(keygen, "cfb"));
/* now execute keygen operation */
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check key usage */
bool flag = false;
assert_rnp_success(rnp_key_allows_usage(key, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(key, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(key, "authenticate", &flag));
assert_false(flag);
/* check key creation and expiration */
uint32_t create = 0;
assert_rnp_success(rnp_key_get_creation(key, &create));
assert_true((create != 0) && (create <= time(NULL)));
uint32_t expiry = 0;
assert_rnp_success(rnp_key_get_expiration(key, &expiry));
assert_true(expiry == 60 * 60 * 24 * 300);
uint32_t till = 0;
assert_rnp_success(rnp_key_valid_till(key, &till));
assert_int_equal(till, create + expiry);
/* check whether key is encrypted */
assert_rnp_success(rnp_key_is_protected(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(key, "123"));
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_lock(key));
/* generate DSA subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "DSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1536));
assert_rnp_success(rnp_op_generate_set_dsa_qbits(keygen, 224));
/* key flags */
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "certify"));
/* these should not work for subkey */
assert_rnp_failure(rnp_op_generate_clear_pref_ciphers(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_cipher(keygen, "AES256"));
assert_rnp_failure(rnp_op_generate_clear_pref_compression(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_compression(keygen, "zlib"));
assert_rnp_failure(rnp_op_generate_clear_pref_hashes(keygen));
assert_rnp_failure(rnp_op_generate_add_pref_hash(keygen, "unknown"));
assert_rnp_failure(rnp_op_generate_set_pref_keyserver(keygen, "hkp://first.server/"));
assert_rnp_failure(rnp_op_generate_set_userid(keygen, "userid"));
/* key expiration */
assert_rnp_success(rnp_op_generate_set_expiration(keygen, 60 * 60 * 24 * 300));
/* key protection */
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES256"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA256"));
assert_rnp_success(rnp_op_generate_set_protection_iterations(keygen, 65536));
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
/* now generate the subkey */
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
/* check subkey creation and expiration */
create = 0;
assert_rnp_success(rnp_key_get_creation(subkey, &create));
assert_true((create != 0) && (create <= time(NULL)));
expiry = 0;
assert_rnp_success(rnp_key_get_expiration(subkey, &expiry));
assert_true(expiry == 60 * 60 * 24 * 300);
/* check whether subkey is encrypted */
assert_rnp_success(rnp_key_is_protected(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(subkey, "123"));
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_lock(subkey));
/* destroy key handle */
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate RSA sign/encrypt subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_expiration(keygen, 0));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
/* set bits for iterations instead of exact iterations number */
assert_rnp_success(rnp_op_generate_set_protection_iterations(keygen, 12));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
/* check whether subkey is encrypted - it should not */
assert_rnp_success(rnp_key_is_protected(subkey, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate ElGamal subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ELGAMAL"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_expiration(keygen, 0));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate ECDSA subkeys for each curve */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_failure(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_failure(rnp_op_generate_set_dsa_qbits(keygen, 1024));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-256"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-384"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-521"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP256r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP256r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP384r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP384r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP512r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP512r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "secp256k1"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* These curves will not work with ECDSA*/
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Ed25519"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Curve25519"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDSA"));
if (!sm2_enabled()) {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "SM2 P-256"));
} else {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "SM2 P-256"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
}
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* Add EDDSA subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "EDDSA"));
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "secp256k1"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add ECDH subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDH"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-256"));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add ECDH x25519 subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ECDH"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Curve25519"));
assert_rnp_failure(rnp_op_generate_add_usage(keygen, "sign"));
assert_rnp_success(rnp_op_generate_add_usage(keygen, "encrypt"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* now check subkey usage */
assert_rnp_success(rnp_key_allows_usage(subkey, "sign", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "certify", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "encrypt", &flag));
assert_true(flag);
assert_rnp_success(rnp_key_allows_usage(subkey, "authenticate", &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add SM2 subkey */
if (!sm2_enabled()) {
keygen = NULL;
assert_rnp_failure(rnp_op_generate_subkey_create(&keygen, ffi, key, "SM2"));
} else {
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "SM2"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "AES128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "SHA1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_key_handle_destroy(subkey));
}
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_expiry_32bit)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "123"));
/* Generate RSA key with creation + expiration > 32 bit */
rnp_op_generate_t keygen = NULL;
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
/* key expiration */
assert_rnp_success(rnp_op_generate_set_expiration(keygen, UINT32_MAX));
/* now execute keygen operation */
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* check key creation and expiration */
uint32_t create = 0;
assert_rnp_success(rnp_key_get_creation(key, &create));
assert_true((create != 0) && (create <= time(NULL)));
uint32_t expiry = 0;
assert_rnp_success(rnp_key_get_expiration(key, &expiry));
assert_true(expiry == UINT32_MAX);
uint32_t till = 0;
assert_rnp_success(rnp_key_valid_till(key, &till));
assert_int_equal(till, UINT32_MAX - 1);
uint64_t till64 = 0;
assert_rnp_success(rnp_key_valid_till64(key, &till64));
assert_int_equal(till64, (uint64_t) create + expiry);
assert_rnp_success(rnp_key_handle_destroy(key));
/* Load key with creation + expiration == UINT32_MAX */
assert_true(import_pub_keys(ffi, "data/test_key_edge_cases/key-create-expiry-32bit.asc"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "60eac9ddf0d9ac9f", &key));
/* check key creation and expiration */
create = 0;
assert_rnp_success(rnp_key_get_creation(key, &create));
assert_int_equal(create, 1619611313);
expiry = 0;
assert_rnp_success(rnp_key_get_expiration(key, &expiry));
assert_true(expiry == UINT32_MAX - create);
till = 0;
assert_rnp_success(rnp_key_valid_till(key, &till));
assert_int_equal(till, UINT32_MAX - 1);
till64 = 0;
assert_rnp_success(rnp_key_valid_till64(key, &till64));
assert_int_equal(till64, UINT32_MAX);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_algnamecase)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "123"));
/* Generate RSA key with misc options set */
rnp_op_generate_t keygen = NULL;
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "rsa"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* generate DSA subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "dsa"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1536));
/* now generate the subkey */
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* destroy key handle */
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate ElGamal subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "elgamal"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* generate ECDSA subkeys for each curve */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_failure(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-256"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-384"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-521"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP256r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP256r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP384r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP384r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
if (brainpool_enabled()) {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "brainpoolP512r1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
} else {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "brainpoolP512r1"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
}
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "secp256k1"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* These curves will not work with ECDSA */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Ed25519"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Curve25519"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdsa"));
if (!sm2_enabled()) {
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "SM2 P-256"));
} else {
assert_rnp_success(rnp_op_generate_set_curve(keygen, "SM2 P-256"));
assert_rnp_failure(rnp_op_generate_execute(keygen));
}
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* Add EDDSA subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "eddsa"));
assert_rnp_failure(rnp_op_generate_set_curve(keygen, "secp256k1"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add ECDH subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdh"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "NIST P-256"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add ECDH x25519 subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "ecdh"));
assert_rnp_success(rnp_op_generate_set_curve(keygen, "Curve25519"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(subkey));
/* Add SM2 subkey */
if (!sm2_enabled()) {
keygen = NULL;
assert_rnp_failure(rnp_op_generate_subkey_create(&keygen, ffi, key, "sm2"));
} else {
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "sm2"));
assert_rnp_success(rnp_op_generate_set_protection_cipher(keygen, "aes128"));
assert_rnp_success(rnp_op_generate_set_protection_hash(keygen, "sha1"));
assert_rnp_success(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_key_handle_destroy(subkey));
}
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_key_generate_protection)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "123"));
/* Generate key and subkey without protection */
rnp_op_generate_t keygen = NULL;
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* check whether key is encrypted */
bool flag = true;
assert_rnp_success(rnp_key_is_protected(key, &flag));
assert_false(flag);
/* generate subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_execute(keygen));
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_is_protected(subkey, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
/* Generate RSA key with password */
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_set_protection_password(keygen, "password"));
/* Line below should not change password from 'password' to '123' */
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
assert_rnp_success(rnp_op_generate_execute(keygen));
key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* check whether key is encrypted */
assert_rnp_success(rnp_key_is_protected(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(key, "password"));
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_lock(key));
/* generate subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_set_protection_password(keygen, "password"));
/* this should fail since primary key is locked */
assert_rnp_failure(rnp_op_generate_execute(keygen));
assert_rnp_success(rnp_key_unlock(key, "password"));
/* now it should work */
assert_rnp_success(rnp_op_generate_execute(keygen));
subkey = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_is_protected(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(subkey, "password"));
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
/* Generate RSA key via password request */
assert_rnp_success(rnp_op_generate_create(&keygen, ffi, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
assert_rnp_success(rnp_op_generate_execute(keygen));
key = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &key));
assert_non_null(key);
assert_rnp_success(rnp_op_generate_destroy(keygen));
/* check whether key is encrypted */
assert_rnp_success(rnp_key_is_protected(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(key, "123"));
assert_rnp_success(rnp_key_is_locked(key, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_lock(key));
/* generate subkey */
assert_rnp_success(rnp_op_generate_subkey_create(&keygen, ffi, key, "RSA"));
assert_rnp_success(rnp_op_generate_set_bits(keygen, 1024));
assert_rnp_success(rnp_op_generate_set_request_password(keygen, true));
/* this should succeed since password for primary key is returned via provider */
assert_rnp_success(rnp_op_generate_execute(keygen));
subkey = NULL;
assert_rnp_success(rnp_op_generate_get_key(keygen, &subkey));
assert_non_null(subkey);
assert_rnp_success(rnp_op_generate_destroy(keygen));
assert_rnp_success(rnp_key_is_protected(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_true(flag);
assert_rnp_success(rnp_key_unlock(subkey, "123"));
assert_rnp_success(rnp_key_is_locked(subkey, &flag));
assert_false(flag);
assert_rnp_success(rnp_key_handle_destroy(subkey));
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_keygen_json_sub_pass_required)
{
char * results = NULL;
size_t count = 0;
rnp_ffi_t ffi = NULL;
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(rnp_ffi_set_pass_provider(ffi, unused_getpasscb, NULL));
// generate our primary key
auto json = file_to_str("data/test_ffi_json/generate-primary.json");
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// check key counts
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(1, count);
assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
assert_int_equal(1, count);
// parse the results JSON
json_object *parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle+grip for the primary
rnp_key_handle_t primary = NULL;
char * primary_grip = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "primary", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
primary_grip = strdup(json_object_get_string(jsogrip));
assert_non_null(primary_grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", primary_grip, &primary));
assert_non_null(primary);
}
// cleanup
json_object_put(parsed_results);
parsed_results = NULL;
// protect+lock the primary key
assert_rnp_success(rnp_key_protect(primary, "pass123", NULL, NULL, NULL, 0));
assert_rnp_success(rnp_key_lock(primary));
rnp_key_handle_destroy(primary);
primary = NULL;
// load our JSON template
json = file_to_str("data/test_ffi_json/generate-sub.json");
// modify our JSON
{
// parse
json_object *jso = json_tokener_parse(json.c_str());
assert_non_null(jso);
// find the relevant fields
json_object *jsosub = NULL;
json_object *jsoprimary = NULL;
assert_true(json_object_object_get_ex(jso, "sub", &jsosub));
assert_non_null(jsosub);
assert_true(json_object_object_get_ex(jsosub, "primary", &jsoprimary));
assert_non_null(jsoprimary);
// replace the placeholder grip with the correct one
json_object_object_del(jsoprimary, "grip");
json_object_object_add(jsoprimary, "grip", json_object_new_string(primary_grip));
assert_int_equal(1, json_object_object_length(jsoprimary));
json = json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY);
assert_false(json.empty());
json_object_put(jso);
}
// cleanup
rnp_buffer_destroy(primary_grip);
primary_grip = NULL;
// generate the subkey (no ffi_string_password_provider, should fail)
assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL));
assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
assert_rnp_failure(rnp_generate_key_json(ffi, json.c_str(), &results));
// generate the subkey (wrong pass, should fail)
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "wrong"));
assert_rnp_failure(rnp_generate_key_json(ffi, json.c_str(), &results));
// generate the subkey
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass123"));
assert_rnp_success(rnp_generate_key_json(ffi, json.c_str(), &results));
assert_non_null(results);
// parse the results JSON
parsed_results = json_tokener_parse(results);
assert_non_null(parsed_results);
rnp_buffer_destroy(results);
results = NULL;
// get a handle for the sub
rnp_key_handle_t sub = NULL;
{
json_object *jsokey = NULL;
assert_int_equal(true, json_object_object_get_ex(parsed_results, "sub", &jsokey));
assert_non_null(jsokey);
json_object *jsogrip = NULL;
assert_int_equal(true, json_object_object_get_ex(jsokey, "grip", &jsogrip));
assert_non_null(jsogrip);
const char *grip = json_object_get_string(jsogrip);
assert_non_null(grip);
assert_rnp_success(rnp_locate_key(ffi, "grip", grip, &sub));
assert_non_null(sub);
}
// cleanup
json_object_put(parsed_results);
parsed_results = NULL;
// check the key counts
assert_int_equal(RNP_SUCCESS, rnp_get_public_key_count(ffi, &count));
assert_int_equal(2, count);
assert_int_equal(RNP_SUCCESS, rnp_get_secret_key_count(ffi, &count));
assert_int_equal(2, count);
// check some key properties
check_key_properties(sub, false, true, true);
// cleanup
rnp_key_handle_destroy(primary);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
}
/** get the value of a (potentially nested) field in a json object
*
* Note that this does not support JSON arrays, only objects.
*
* @param jso the json object to search within. This should be an object, not a string,
* array, etc.
* @param field the field to retrieve. The format is "first.second.third".
* @return a pointer to the located json object, or NULL
**/
static json_object *
get_json_obj(json_object *jso, const char *field)
{
const char *start = field;
const char *end;
char buf[32];
do {
end = strchr(start, '.');
size_t len = end ? (end - start) : strlen(start);
if (len >= sizeof(buf)) {
return NULL;
}
memcpy(buf, start, len);
buf[len] = '\0';
if (!json_object_object_get_ex(jso, buf, &jso)) {
return NULL;
}
start = end + 1;
} while (end);
return jso;
}
/* This test loads a keyring and converts the keys to JSON,
* then validates some properties.
*
* We could just do a simple strcmp, but that would depend
* on json-c sorting the keys consistently, across versions,
* etc.
*/
TEST_F(rnp_tests, test_ffi_key_to_json)
{
rnp_ffi_t ffi = NULL;
char * pub_format = NULL;
char * pub_path = NULL;
char * sec_format = NULL;
char * sec_path = NULL;
rnp_key_handle_t key = NULL;
char * json = NULL;
json_object * jso = NULL;
// detect the formats+paths
assert_rnp_success(rnp_detect_homedir_info(
"data/keyrings/5", &pub_format, &pub_path, &sec_format, &sec_path));
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, pub_format, sec_format));
// load our keyrings
assert_true(load_keys_gpg(ffi, pub_path, sec_path));
// free formats+paths
rnp_buffer_destroy(pub_format);
pub_format = NULL;
rnp_buffer_destroy(pub_path);
pub_path = NULL;
rnp_buffer_destroy(sec_format);
sec_format = NULL;
rnp_buffer_destroy(sec_path);
sec_path = NULL;
// locate key (primary)
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0E33FD46FF10F19C", &key));
assert_non_null(key);
// convert to JSON
json = NULL;
assert_rnp_success(rnp_key_to_json(key, 0xff, &json));
assert_non_null(json);
// parse it back in
jso = json_tokener_parse(json);
assert_non_null(jso);
// validate some properties
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "type")), "ECDSA"));
assert_int_equal(json_object_get_int(get_json_obj(jso, "length")), 256);
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "curve")), "NIST P-256"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "keyid")),
"0E33FD46FF10F19C"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "fingerprint")),
"B6B5E497A177551ECB8862200E33FD46FF10F19C"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "grip")),
"20A48B3C61525DCDF8B3B9D82C6BBCF4D8BFB5E5"));
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "revoked")), false);
assert_int_equal(json_object_get_int64(get_json_obj(jso, "creation time")), 1511313500);
assert_int_equal(json_object_get_int64(get_json_obj(jso, "expiration")), 0);
// usage
assert_int_equal(json_object_array_length(get_json_obj(jso, "usage")), 2);
assert_true(rnp::str_case_eq(
json_object_get_string(json_object_array_get_idx(get_json_obj(jso, "usage"), 0)),
"sign"));
assert_true(rnp::str_case_eq(
json_object_get_string(json_object_array_get_idx(get_json_obj(jso, "usage"), 1)),
"certify"));
// primary key grip
assert_null(get_json_obj(jso, "primary key grip"));
// subkey grips
assert_int_equal(json_object_array_length(get_json_obj(jso, "subkey grips")), 1);
assert_true(rnp::str_case_eq(
json_object_get_string(json_object_array_get_idx(get_json_obj(jso, "subkey grips"), 0)),
"FFFA72FC225214DC712D0127172EE13E88AF93B4"));
// public key
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "public key.present")), true);
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "public key.mpis.point")),
"04B0C6F2F585C1EEDF805C4492CB683839D5EAE6246420780F063D558"
"A33F607876BE6F818A665722F8204653CC4DCFAD4F4765521AC8A6E9F"
"793CEBAE8600BEEF"));
// secret key
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.present")), true);
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "secret key.mpis.x")),
"46DE93CA439735F36B9CF228F10D8586DA824D88BBF4E24566D5312D061802C8"));
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.locked")), false);
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.protected")),
false);
// userids
assert_int_equal(json_object_array_length(get_json_obj(jso, "userids")), 1);
assert_true(rnp::str_case_eq(
json_object_get_string(json_object_array_get_idx(get_json_obj(jso, "userids"), 0)),
"test0"));
// signatures
assert_int_equal(json_object_array_length(get_json_obj(jso, "signatures")), 1);
json_object *jsosig = json_object_array_get_idx(get_json_obj(jso, "signatures"), 0);
assert_int_equal(json_object_get_int(get_json_obj(jsosig, "userid")), 0);
// TODO: other properties of signature
// cleanup
json_object_put(jso);
rnp_key_handle_destroy(key);
key = NULL;
rnp_buffer_destroy(json);
json = NULL;
// locate key (sub)
assert_rnp_success(rnp_locate_key(ffi, "keyid", "074131BC8D16C5C9", &key));
assert_non_null(key);
// convert to JSON
assert_rnp_success(rnp_key_to_json(key, 0xff, &json));
assert_non_null(json);
// parse it back in
jso = json_tokener_parse(json);
assert_non_null(jso);
// validate some properties
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "type")), "ECDH"));
assert_int_equal(json_object_get_int(get_json_obj(jso, "length")), 256);
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "curve")), "NIST P-256"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "keyid")),
"074131BC8D16C5C9"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "fingerprint")),
"481E6A41B10ECD71A477DB02074131BC8D16C5C9"));
// ECDH-specific
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "kdf hash")), "SHA256"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "key wrap cipher")),
"AES128"));
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "grip")),
"FFFA72FC225214DC712D0127172EE13E88AF93B4"));
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "revoked")), false);
assert_int_equal(json_object_get_int64(get_json_obj(jso, "creation time")), 1511313500);
assert_int_equal(json_object_get_int64(get_json_obj(jso, "expiration")), 0);
// usage
assert_int_equal(json_object_array_length(get_json_obj(jso, "usage")), 1);
assert_true(rnp::str_case_eq(
json_object_get_string(json_object_array_get_idx(get_json_obj(jso, "usage"), 0)),
"encrypt"));
// primary key grip
assert_true(rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "primary key grip")),
"20A48B3C61525DCDF8B3B9D82C6BBCF4D8BFB5E5"));
// subkey grips
assert_null(get_json_obj(jso, "subkey grips"));
// public key
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "public key.present")), true);
assert_true(rnp::str_case_eq(
json_object_get_string(get_json_obj(jso, "public key.mpis.point")),
"04E2746BA4D180011B17A6909EABDBF2F3733674FBE00B20A3B857C2597233651544150B"
"896BCE7DCDF47C49FC1E12D5AD86384D26336A48A18845940A3F65F502"));
// secret key
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.present")), true);
assert_true(
rnp::str_case_eq(json_object_get_string(get_json_obj(jso, "secret key.mpis.x")),
"DF8BEB7272117AD7AFE2B7E882453113059787FBC785C82F78624EE7EF2117FB"));
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.locked")), false);
assert_int_equal(json_object_get_boolean(get_json_obj(jso, "secret key.protected")),
false);
// userids
assert_null(get_json_obj(jso, "userids"));
// signatures
assert_int_equal(json_object_array_length(get_json_obj(jso, "signatures")), 1);
jsosig = json_object_array_get_idx(get_json_obj(jso, "signatures"), 0);
assert_null(get_json_obj(jsosig, "userid"));
// TODO: other properties of signature
// cleanup
json_object_put(jso);
rnp_key_handle_destroy(key);
rnp_buffer_destroy(json);
// cleanup
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_iter)
{
rnp_ffi_t ffi = NULL;
char * pub_format = NULL;
char * pub_path = NULL;
char * sec_format = NULL;
char * sec_path = NULL;
// detect the formats+paths
assert_rnp_success(rnp_detect_homedir_info(
"data/keyrings/1", &pub_format, &pub_path, &sec_format, &sec_path));
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, pub_format, sec_format));
// test invalid identifier type
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_failure(rnp_identifier_iterator_create(ffi, &it, "keyidz"));
assert_null(it);
}
// test empty rings
// keyid
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "keyid"));
assert_non_null(it);
const char *ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
assert_null(ident);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// grip
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "grip"));
assert_non_null(it);
const char *ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
assert_null(ident);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// userid
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "userid"));
assert_non_null(it);
const char *ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
assert_null(ident);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// fingerprint
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
assert_non_null(it);
const char *ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
assert_null(ident);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// load our keyrings
assert_true(load_keys_gpg(ffi, pub_path, sec_path));
// free formats+paths
rnp_buffer_destroy(pub_format);
pub_format = NULL;
rnp_buffer_destroy(pub_path);
pub_path = NULL;
rnp_buffer_destroy(sec_format);
sec_format = NULL;
rnp_buffer_destroy(sec_path);
sec_path = NULL;
// keyid
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "keyid"));
assert_non_null(it);
{
static const char *expected[] = {"7BC6709B15C23A4A",
"1ED63EE56FADC34D",
"1D7E8A5393C997A8",
"8A05B89FAD5ADED1",
"2FCADF05FFA501BB",
"54505A936A4A970E",
"326EF111425D14A5"};
size_t i = 0;
const char * ident = NULL;
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (ident) {
assert_true(rnp::str_case_eq(expected[i], ident));
i++;
}
} while (ident);
assert_int_equal(i, ARRAY_SIZE(expected));
}
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// grip
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "grip"));
assert_non_null(it);
{
static const char *expected[] = {"66D6A0800A3FACDE0C0EB60B16B3669ED380FDFA",
"D9839D61EDAF0B3974E0A4A341D6E95F3479B9B7",
"B1CC352FEF9A6BD4E885B5351840EF9306D635F0",
"E7C8860B70DC727BED6DB64C633683B41221BB40",
"B2A7F6C34AA2C15484783E9380671869A977A187",
"43C01D6D96BE98C3C87FE0F175870ED92DE7BE45",
"8082FE753013923972632550838A5F13D81F43B9"};
size_t i = 0;
const char * ident = NULL;
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (ident) {
assert_true(rnp::str_case_eq(expected[i], ident));
i++;
}
} while (ident);
assert_int_equal(i, ARRAY_SIZE(expected));
}
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// userid
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "userid"));
assert_non_null(it);
{
static const char *expected[] = {
"key0-uid0", "key0-uid1", "key0-uid2", "key1-uid0", "key1-uid2", "key1-uid1"};
size_t i = 0;
const char *ident = NULL;
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (ident) {
assert_true(rnp::str_case_eq(expected[i], ident));
i++;
}
} while (ident);
assert_int_equal(i, ARRAY_SIZE(expected));
}
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// fingerprint
{
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
assert_non_null(it);
{
static const char *expected[] = {"E95A3CBF583AA80A2CCC53AA7BC6709B15C23A4A",
"E332B27CAF4742A11BAA677F1ED63EE56FADC34D",
"C5B15209940A7816A7AF3FB51D7E8A5393C997A8",
"5CD46D2A0BD0B8CFE0B130AE8A05B89FAD5ADED1",
"BE1C4AB951F4C2F6B604C7F82FCADF05FFA501BB",
"A3E94DE61A8CB229413D348E54505A936A4A970E",
"57F8ED6E5C197DB63C60FFAF326EF111425D14A5"};
size_t i = 0;
const char * ident = NULL;
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (ident) {
assert_true(rnp::str_case_eq(expected[i], ident));
i++;
}
} while (ident);
assert_int_equal(i, ARRAY_SIZE(expected));
}
assert_rnp_success(rnp_identifier_iterator_destroy(it));
}
// cleanup
rnp_ffi_destroy(ffi);
}
void
check_loaded_keys(const char * format,
bool armored,
uint8_t * buf,
size_t buf_len,
const char * id_type,
const std::vector<std::string> &expected_ids,
bool secret)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
rnp_identifier_iterator_t it = NULL;
const char * identifier = NULL;
if (armored) {
assert_memory_equal("-----", buf, 5);
} else {
assert_memory_not_equal("-----", buf, 5);
}
// setup FFI
assert_rnp_success(rnp_ffi_create(&ffi, format, format));
// load our keyrings
assert_rnp_success(rnp_input_from_memory(&input, buf, buf_len, true));
assert_rnp_success(rnp_load_keys(
ffi, format, input, secret ? RNP_LOAD_SAVE_SECRET_KEYS : RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
input = NULL;
std::vector<std::string> ids;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, id_type));
do {
identifier = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &identifier));
if (identifier) {
rnp_key_handle_t key = NULL;
bool expected_secret = secret;
bool expected_public = !secret;
bool result;
assert_rnp_success(rnp_locate_key(ffi, id_type, identifier, &key));
assert_non_null(key);
assert_rnp_success(rnp_key_have_secret(key, &result));
assert_int_equal(result, expected_secret);
assert_rnp_success(rnp_key_have_public(key, &result));
assert_int_equal(result, expected_public);
assert_rnp_success(rnp_key_handle_destroy(key));
ids.push_back(identifier);
}
} while (identifier);
assert_true(ids == expected_ids);
rnp_identifier_iterator_destroy(it);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_export)
{
rnp_ffi_t ffi = NULL;
rnp_output_t output = NULL;
rnp_key_handle_t key = NULL;
uint8_t * buf = NULL;
size_t buf_len = 0;
// setup FFI
test_ffi_init(&ffi);
// primary pub only
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(rnp_key_export(key, output, RNP_KEY_EXPORT_PUBLIC));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys("GPG", false, buf, buf_len, "keyid", {"2FCADF05FFA501BB"}, false);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// primary sec only (armored)
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(
rnp_key_export(key, output, RNP_KEY_EXPORT_SECRET | RNP_KEY_EXPORT_ARMORED));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys("GPG", true, buf, buf_len, "keyid", {"2FCADF05FFA501BB"}, true);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// primary pub and subs
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(
rnp_key_export(key, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_SUBKEYS));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys("GPG",
false,
buf,
buf_len,
"keyid",
{"2FCADF05FFA501BB", "54505A936A4A970E", "326EF111425D14A5"},
false);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// primary sec and subs (armored)
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(rnp_key_export(key,
output,
RNP_KEY_EXPORT_SECRET | RNP_KEY_EXPORT_SUBKEYS |
RNP_KEY_EXPORT_ARMORED));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys("GPG",
true,
buf,
buf_len,
"keyid",
{"2FCADF05FFA501BB", "54505A936A4A970E", "326EF111425D14A5"},
true);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// sub pub
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "54505A936A4A970E", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(
rnp_key_export(key, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_ARMORED));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys(
"GPG", true, buf, buf_len, "keyid", {"2FCADF05FFA501BB", "54505A936A4A970E"}, false);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// sub sec
{
// locate key
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "54505A936A4A970E", &key));
assert_non_null(key);
// create output
output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_non_null(output);
// export
assert_rnp_success(
rnp_key_export(key, output, RNP_KEY_EXPORT_SECRET | RNP_KEY_EXPORT_ARMORED));
// get output
buf = NULL;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
assert_non_null(buf);
// check results
check_loaded_keys(
"GPG", true, buf, buf_len, "keyid", {"2FCADF05FFA501BB", "54505A936A4A970E"}, true);
// cleanup
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
}
// cleanup
rnp_ffi_destroy(ffi);
}
static bool
check_import_keys_ex(rnp_ffi_t ffi,
json_object **jso,
uint32_t flags,
rnp_input_t input,
size_t rescount,
size_t pubcount,
size_t seccount)
{
bool res = false;
char * keys = NULL;
size_t keycount = 0;
json_object *keyarr = NULL;
*jso = NULL;
if (rnp_import_keys(ffi, input, flags, &keys)) {
goto done;
}
if (rnp_get_public_key_count(ffi, &keycount) || (keycount != pubcount)) {
goto done;
}
if (rnp_get_secret_key_count(ffi, &keycount) || (keycount != seccount)) {
goto done;
}
if (!keys) {
goto done;
}
*jso = json_tokener_parse(keys);
if (!jso) {
goto done;
}
if (!json_object_is_type(*jso, json_type_object)) {
goto done;
}
if (!json_object_object_get_ex(*jso, "keys", &keyarr)) {
goto done;
}
if (!json_object_is_type(keyarr, json_type_array)) {
goto done;
}
if ((size_t) json_object_array_length(keyarr) != rescount) {
goto done;
}
res = true;
done:
if (!res) {
json_object_put(*jso);
*jso = NULL;
}
rnp_buffer_destroy(keys);
return res;
}
static bool
check_import_keys(rnp_ffi_t ffi,
json_object **jso,
const char * keypath,
size_t rescount,
size_t pubcount,
size_t seccount)
{
rnp_input_t input = NULL;
if (rnp_input_from_path(&input, keypath)) {
return false;
}
bool res = check_import_keys_ex(ffi,
jso,
RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS,
input,
rescount,
pubcount,
seccount);
rnp_input_destroy(input);
return res;
}
static bool
check_key_status(
json_object *jso, size_t idx, const char *pub, const char *sec, const char *fp)
{
if (!jso) {
return false;
}
if (!json_object_is_type(jso, json_type_object)) {
return false;
}
json_object *keys = NULL;
if (!json_object_object_get_ex(jso, "keys", &keys)) {
return false;
}
if (!json_object_is_type(keys, json_type_array)) {
return false;
}
json_object *key = json_object_array_get_idx(keys, idx);
if (!json_object_is_type(key, json_type_object)) {
return false;
}
json_object *fld = NULL;
if (!json_object_object_get_ex(key, "public", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), pub) != 0) {
return false;
}
if (!json_object_object_get_ex(key, "secret", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), sec) != 0) {
return false;
}
if (!json_object_object_get_ex(key, "fingerprint", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), fp) != 0) {
return false;
}
return true;
}
TEST_F(rnp_tests, test_ffi_keys_import)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
// some edge cases
assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-both.asc"));
assert_rnp_failure(rnp_import_keys(NULL, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_failure(rnp_import_keys(ffi, NULL, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_failure(rnp_import_keys(ffi, input, 0, NULL));
assert_rnp_failure(rnp_import_keys(ffi, input, 0x31, NULL));
// load just public keys
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
size_t keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 3);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
// load just secret keys from pubkey file
assert_true(import_sec_keys(ffi, "data/test_stream_key_merge/key-pub.asc"));
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
// load both public and secret keys by specifying just secret (it will create pub part)
assert_true(import_sec_keys(ffi, "data/test_stream_key_merge/key-sec.asc"));
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 3);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 3);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
// import just a public key without subkeys
json_object *jso = NULL;
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-pub-just-key.pgp", 1, 1, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "090bd712a1166be572252c3c9747d2a6b3a63124"));
json_object_put(jso);
// import just subkey 1
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-pub-just-subkey-1.pgp", 1, 2, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
json_object_put(jso);
// import just subkey 2 without sigs
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-pub-just-subkey-2-no-sigs.pgp", 1, 3, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
// import subkey 2 with sigs
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-pub-just-subkey-2.pgp", 1, 3, 0));
assert_true(
check_key_status(jso, 0, "updated", "none", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
// import first uid
assert_true(
check_import_keys(ffi, &jso, "data/test_stream_key_merge/key-pub-uid-1.pgp", 1, 3, 0));
assert_true(
check_key_status(jso, 0, "updated", "none", "090bd712a1166be572252c3c9747d2a6b3a63124"));
json_object_put(jso);
// import the whole key
assert_true(
check_import_keys(ffi, &jso, "data/test_stream_key_merge/key-pub.pgp", 3, 3, 0));
assert_true(
check_key_status(jso, 0, "updated", "none", "090bd712a1166be572252c3c9747d2a6b3a63124"));
assert_true(check_key_status(
jso, 1, "unchanged", "none", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
assert_true(check_key_status(
jso, 2, "unchanged", "none", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
// import the first secret subkey
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-sec-just-subkey-1.pgp", 1, 3, 1));
assert_true(check_key_status(
jso, 0, "unchanged", "new", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
json_object_put(jso);
// import the second secret subkey
assert_true(check_import_keys(
ffi, &jso, "data/test_stream_key_merge/key-sec-just-subkey-2-no-sigs.pgp", 1, 3, 2));
assert_true(check_key_status(
jso, 0, "unchanged", "new", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
// import the whole secret key
assert_true(
check_import_keys(ffi, &jso, "data/test_stream_key_merge/key-sec.pgp", 3, 3, 3));
assert_true(check_key_status(
jso, 0, "unchanged", "new", "090bd712a1166be572252c3c9747d2a6b3a63124"));
assert_true(check_key_status(
jso, 1, "unchanged", "unchanged", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
assert_true(check_key_status(
jso, 2, "unchanged", "unchanged", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
// cleanup
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_elgamal4096)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* load public key */
json_object *jso = NULL;
assert_true(
check_import_keys(ffi, &jso, "data/test_key_edge_cases/key-eg-4096-pub.pgp", 2, 2, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "6541db10cdfcdba89db2dffea8f0408eb3369d8e"));
assert_true(
check_key_status(jso, 1, "new", "none", "c402a09b74acd0c11efc0527a3d630b457a0b15b"));
json_object_put(jso);
/* load secret key */
assert_true(
check_import_keys(ffi, &jso, "data/test_key_edge_cases/key-eg-4096-sec.pgp", 2, 2, 2));
assert_true(check_key_status(
jso, 0, "unchanged", "new", "6541db10cdfcdba89db2dffea8f0408eb3369d8e"));
assert_true(check_key_status(
jso, 1, "unchanged", "new", "c402a09b74acd0c11efc0527a3d630b457a0b15b"));
json_object_put(jso);
// cleanup
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_malformed_keys_import)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* import keys with bad key0-uid0 certification, first without flag */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/pubring-malf-cert.pgp"));
assert_rnp_failure(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
size_t keycount = 255;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
/* now try with RNP_LOAD_SAVE_PERMISSIVE */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/pubring-malf-cert.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 7);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_non_null(key);
size_t uidcount = 255;
assert_rnp_success(rnp_key_get_uid_count(key, &uidcount));
assert_int_equal(uidcount, 3);
size_t subcount = 255;
assert_rnp_success(rnp_key_get_subkey_count(key, &subcount));
assert_int_equal(subcount, 3);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fcadf05ffa501bb", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import keys with bad key0-sub0 binding */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/pubring-malf-key0-sub0-bind.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 7);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_non_null(key);
uidcount = 255;
assert_rnp_success(rnp_key_get_uid_count(key, &uidcount));
assert_int_equal(uidcount, 3);
subcount = 255;
assert_rnp_success(rnp_key_get_subkey_count(key, &subcount));
assert_int_equal(subcount, 3);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fcadf05ffa501bb", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import keys with bad key0-sub0 packet */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/pubring-malf-key0-sub0.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 6);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_non_null(key);
uidcount = 255;
assert_rnp_success(rnp_key_get_uid_count(key, &uidcount));
assert_int_equal(uidcount, 3);
subcount = 255;
assert_rnp_success(rnp_key_get_subkey_count(key, &subcount));
assert_int_equal(subcount, 2);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fcadf05ffa501bb", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import keys with bad key0 packet */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/pubring-malf-key0.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 3);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_null(key);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fcadf05ffa501bb", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import secret keys with bad key1 packet - public should be added as well */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/secring-malf-key1.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 7);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 4);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_non_null(key);
bool secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "326ef111425d14a5", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_false(secret);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import secret keys with bad key0 packet */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/secring-malf-key0.pgp"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PERMISSIVE, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 7);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 7);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid2", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "326ef111425d14a5", &key));
assert_non_null(key);
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
assert_rnp_success(rnp_key_handle_destroy(key));
/* import unprotected secret key with wrong crc */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_false(
import_sec_keys(ffi, "data/test_key_edge_cases/key-25519-tweaked-wrong-crc.asc"));
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
/* cleanup */
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_iterated_key_import)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
uint32_t flags =
RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_SINGLE;
/* two primary keys with attached subkeys in binary keyring */
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
json_object *jso = NULL;
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 4, 4, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "e95a3cbf583aa80a2ccc53aa7bc6709b15c23a4a"));
assert_true(
check_key_status(jso, 1, "new", "none", "e332b27caf4742a11baa677f1ed63ee56fadc34d"));
assert_true(
check_key_status(jso, 2, "new", "none", "c5b15209940a7816a7af3fb51d7e8a5393c997a8"));
assert_true(
check_key_status(jso, 3, "new", "none", "5cd46d2a0bd0b8cfe0b130ae8a05b89fad5aded1"));
json_object_put(jso);
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 3, 7, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "be1c4ab951f4c2f6b604c7f82fcadf05ffa501bb"));
assert_true(
check_key_status(jso, 1, "new", "none", "a3e94de61a8cb229413d348e54505a936a4a970e"));
assert_true(
check_key_status(jso, 2, "new", "none", "57f8ed6e5c197db63c60ffaf326ef111425d14a5"));
json_object_put(jso);
char *results = NULL;
assert_int_equal(RNP_ERROR_EOF, rnp_import_keys(ffi, input, flags, &results));
assert_null(results);
rnp_input_destroy(input);
/* public + secret key, armored separately */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-both.asc"));
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 3, 3, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "090bd712a1166be572252c3c9747d2a6b3a63124"));
assert_true(
check_key_status(jso, 1, "new", "none", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
assert_true(
check_key_status(jso, 2, "new", "none", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 3, 3, 3));
assert_true(check_key_status(
jso, 0, "unchanged", "new", "090bd712a1166be572252c3c9747d2a6b3a63124"));
assert_true(check_key_status(
jso, 1, "unchanged", "new", "51b45a4c74917272e4e34180af1114a47f5f5b28"));
assert_true(check_key_status(
jso, 2, "unchanged", "new", "5fe514a54816e1b331686c2c16cd16f267ccdd4f"));
json_object_put(jso);
assert_int_equal(RNP_ERROR_EOF, rnp_import_keys(ffi, input, flags, &results));
assert_null(results);
rnp_input_destroy(input);
/* public keyring, enarmored */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg.asc"));
flags |= RNP_LOAD_SAVE_PERMISSIVE;
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 4, 4, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "e95a3cbf583aa80a2ccc53aa7bc6709b15c23a4a"));
assert_true(
check_key_status(jso, 1, "new", "none", "e332b27caf4742a11baa677f1ed63ee56fadc34d"));
assert_true(
check_key_status(jso, 2, "new", "none", "c5b15209940a7816a7af3fb51d7e8a5393c997a8"));
assert_true(
check_key_status(jso, 3, "new", "none", "5cd46d2a0bd0b8cfe0b130ae8a05b89fad5aded1"));
json_object_put(jso);
assert_true(check_import_keys_ex(ffi, &jso, flags, input, 3, 7, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "be1c4ab951f4c2f6b604c7f82fcadf05ffa501bb"));
assert_true(
check_key_status(jso, 1, "new", "none", "a3e94de61a8cb229413d348e54505a936a4a970e"));
assert_true(
check_key_status(jso, 2, "new", "none", "57f8ed6e5c197db63c60ffaf326ef111425d14a5"));
json_object_put(jso);
results = NULL;
assert_int_equal(RNP_ERROR_EOF, rnp_import_keys(ffi, input, flags, &results));
assert_null(results);
rnp_input_destroy(input);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_stripped_keys_import)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* load stripped key as keyring */
assert_true(load_keys_gpg(ffi, "data/test_key_validity/case8/pubring.gpg"));
/* validate signatures - must succeed */
rnp_op_verify_t verify = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/case8/message.txt.asc"));
rnp_output_t output = NULL;
assert_rnp_success(rnp_output_to_null(&output));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
assert_rnp_success(rnp_op_verify_execute(verify));
rnp_input_destroy(input);
rnp_output_destroy(output);
rnp_op_verify_signature_t sig;
/* signature 1 - by primary key */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
/* signature 2 - by subkey */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 1, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
rnp_op_verify_destroy(verify);
/* load stripped key by parts via import */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/primary.pgp"));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/subkey.pgp"));
/* validate signatures - must be valid */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/case8/message.txt.asc"));
assert_rnp_success(rnp_output_to_null(&output));
assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
assert_rnp_success(rnp_op_verify_execute(verify));
rnp_input_destroy(input);
rnp_output_destroy(output);
/* signature 1 - by primary key */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
/* signature 2 - by subkey */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 1, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
rnp_op_verify_destroy(verify);
/* load stripped key with subkey first */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/subkey.pgp"));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/primary.pgp"));
/* validate signatures - must be valid */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/case8/message.txt.asc"));
assert_rnp_success(rnp_output_to_null(&output));
assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
assert_rnp_success(rnp_op_verify_execute(verify));
rnp_input_destroy(input);
rnp_output_destroy(output);
/* signature 1 - by primary key */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
/* signature 2 - by subkey */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 1, &sig));
assert_rnp_success(rnp_op_verify_signature_get_status(sig));
rnp_op_verify_destroy(verify);
/* load stripped key without subkey binding */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/primary.pgp"));
assert_true(import_pub_keys(ffi, "data/test_key_validity/case8/subkey-no-sig.pgp"));
/* validate signatures - must be invalid */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/case8/message.txt.asc"));
assert_rnp_success(rnp_output_to_null(&output));
assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
assert_int_equal(rnp_op_verify_execute(verify), RNP_ERROR_SIGNATURE_INVALID);
rnp_input_destroy(input);
rnp_output_destroy(output);
/* signature 1 - by primary key */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
assert_int_equal(rnp_op_verify_signature_get_status(sig), RNP_ERROR_SIGNATURE_INVALID);
/* signature 2 - by subkey */
assert_rnp_success(rnp_op_verify_get_signature_at(verify, 1, &sig));
assert_int_equal(rnp_op_verify_signature_get_status(sig), RNP_ERROR_SIGNATURE_INVALID);
rnp_op_verify_destroy(verify);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_import_edge_cases)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* key with empty packets - must fail with bad format */
rnp_input_t input = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/key-empty-packets.pgp"));
char *results = NULL;
assert_int_equal(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results),
RNP_ERROR_BAD_FORMAT);
assert_null(results);
rnp_input_destroy(input);
/* key with empty uid - must succeed */
json_object *jso = NULL;
assert_true(
check_import_keys(ffi, &jso, "data/test_key_edge_cases/key-empty-uid.pgp", 1, 1, 0));
assert_true(
check_key_status(jso, 0, "new", "none", "753d5b947e9a2b2e01147c1fc972affd358bf887"));
json_object_put(jso);
/* key with experimental signature subpackets - must succeed and append uid and signature
*/
assert_true(check_import_keys(
ffi, &jso, "data/test_key_edge_cases/key-subpacket-101-110.pgp", 1, 1, 0));
assert_true(
check_key_status(jso, 0, "updated", "none", "753d5b947e9a2b2e01147c1fc972affd358bf887"));
json_object_put(jso);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "C972AFFD358BF887", &key));
size_t count = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &count));
assert_int_equal(count, 2);
char *uid = NULL;
assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
assert_string_equal(uid, "");
rnp_buffer_destroy(uid);
assert_rnp_success(rnp_key_get_uid_at(key, 1, &uid));
assert_string_equal(uid, "NoUID");
rnp_buffer_destroy(uid);
rnp_key_handle_destroy(key);
/* key with malformed signature - must fail */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/key-malf-sig.pgp"));
assert_int_equal(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results),
RNP_ERROR_BAD_FORMAT);
assert_null(results);
rnp_input_destroy(input);
/* revoked key without revocation reason signature subpacket */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-rev-no-reason.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results));
rnp_input_destroy(input);
assert_non_null(results);
rnp_buffer_destroy(results);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
assert_rnp_success(rnp_key_get_revocation_reason(key, &results));
assert_string_equal(results, "No reason specified");
rnp_buffer_destroy(results);
bool revoked = false;
assert_rnp_success(rnp_key_is_revoked(key, &revoked));
assert_true(revoked);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
/* revoked subkey without revocation reason signature subpacket */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-sub-rev-no-reason.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results));
rnp_input_destroy(input);
assert_non_null(results);
rnp_buffer_destroy(results);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
assert_int_equal(rnp_key_get_revocation_reason(key, &results), RNP_ERROR_BAD_PARAMETERS);
revoked = true;
assert_rnp_success(rnp_key_is_revoked(key, &revoked));
assert_false(revoked);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD23CEB7FEBEFF17", &key));
assert_rnp_success(rnp_key_get_revocation_reason(key, &results));
assert_string_equal(results, "No reason specified");
rnp_buffer_destroy(results);
revoked = false;
assert_rnp_success(rnp_key_is_revoked(key, &revoked));
assert_true(revoked);
rnp_key_handle_destroy(key);
/* key with two subkeys with same material but different creation time */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-2-subs-same-grip.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results));
rnp_input_destroy(input);
assert_non_null(results);
rnp_buffer_destroy(results);
count = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(count, 3);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_t sub = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
char *keyid = NULL;
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "DD23CEB7FEBEFF17");
rnp_buffer_destroy(keyid);
char *fp = NULL;
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_key_get_subkey_at(key, 1, &sub));
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "C2E7FDCC9CD59FB5");
rnp_buffer_destroy(keyid);
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD23CEB7FEBEFF17", &sub));
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "C2E7FDCC9CD59FB5", &sub));
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* two keys with subkeys with same material but different creation time */
assert_true(import_pub_keys(ffi, "data/test_key_edge_cases/alice-2-keys-same-grip.pgp"));
assert_rnp_success(rnp_get_public_key_count(ffi, &count));
assert_int_equal(count, 4);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "DD23CEB7FEBEFF17");
rnp_buffer_destroy(keyid);
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_key_get_subkey_at(key, 1, &sub));
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "C2E7FDCC9CD59FB5");
rnp_buffer_destroy(keyid);
assert_rnp_success(rnp_key_get_primary_fprint(sub, &fp));
assert_string_equal(fp, "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C");
rnp_buffer_destroy(fp);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* subkey should belong to original key */
assert_rnp_success(rnp_locate_key(ffi, "keyid", "467A2DE826ABA0DB", &key));
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 0);
rnp_key_handle_destroy(key);
/* key with signing subkey, where primary binding has different from subkey binding hash
* algorithm */
assert_true(import_pub_keys(ffi, "data/test_key_edge_cases/key-binding-hash-alg.asc"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "F81A30AA5DCBD01E", &key));
bool valid = false;
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_true(valid);
assert_true(key->pub->valid());
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD716516A7249711", &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_true(valid);
assert_true(sub->pub->valid());
rnp_key_handle_destroy(sub);
/* key and subkey both has 0 key expiration with corresponding subpacket */
assert_true(import_pub_keys(ffi, "data/test_key_edge_cases/key-sub-0-expiry.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "6EFF45F2201AC5F8", &key));
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_true(valid);
assert_true(key->pub->valid());
uint32_t expiry = 0;
assert_rnp_success(rnp_key_valid_till(key, &expiry));
assert_int_equal(expiry, 0xffffffff);
uint64_t expiry64 = 0;
assert_rnp_success(rnp_key_valid_till64(key, &expiry64));
assert_int_equal(expiry64, UINT64_MAX);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "74F971795A5DDBC9", &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_true(valid);
assert_true(sub->pub->valid());
assert_rnp_success(rnp_key_valid_till(sub, &expiry));
assert_int_equal(expiry, 0xffffffff);
assert_rnp_success(rnp_key_valid_till64(sub, &expiry64));
assert_int_equal(expiry64, UINT64_MAX);
rnp_key_handle_destroy(sub);
/* key/subkey with expiration times in unhashed subpackets */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, "data/test_key_edge_cases/key-unhashed-subpkts.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7BC6709B15C23A4A", &key));
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_true(valid);
assert_true(key->pub->valid());
assert_rnp_success(rnp_key_get_expiration(key, &expiry));
assert_int_equal(expiry, 0);
assert_rnp_success(rnp_key_valid_till(key, &expiry));
assert_int_equal(expiry, 0xffffffff);
assert_rnp_success(rnp_key_valid_till64(key, &expiry64));
assert_int_equal(expiry64, UINT64_MAX);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "1ED63EE56FADC34D", &sub));
assert_true(sub->pub->valid());
expiry = 100;
assert_rnp_success(rnp_key_get_expiration(sub, &expiry));
assert_int_equal(expiry, 0);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_key_import_gpg_s2k)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* secret subkeys, exported via gpg --export-secret-subkeys (no primary secret key data) */
rnp_input_t input = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-1-subs.pgp"));
assert_rnp_success(rnp_import_keys(
ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL));
rnp_input_destroy(input);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
bool secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
bool locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
char *type = NULL;
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "GPG-None");
rnp_buffer_destroy(type);
assert_rnp_failure(rnp_key_unlock(key, "password"));
size_t count = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
/* signing secret subkey */
rnp_key_handle_t sub = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
char *keyid = NULL;
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "22F3A217C0E439CB");
rnp_buffer_destroy(keyid);
secret = false;
assert_rnp_success(rnp_key_have_secret(sub, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_key_unlock(sub, "password"));
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_false(locked);
rnp_key_handle_destroy(sub);
/* encrypting secret subkey */
assert_rnp_success(rnp_key_get_subkey_at(key, 1, &sub));
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "DD23CEB7FEBEFF17");
rnp_buffer_destroy(keyid);
secret = false;
assert_rnp_success(rnp_key_have_secret(sub, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_key_unlock(sub, "password"));
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_false(locked);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* save keyrings and reload */
reload_keyrings(&ffi);
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "GPG-None");
rnp_buffer_destroy(type);
count = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
/* signing secret subkey */
sub = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
keyid = NULL;
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "22F3A217C0E439CB");
rnp_buffer_destroy(keyid);
secret = false;
assert_rnp_success(rnp_key_have_secret(sub, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
rnp_key_handle_destroy(sub);
/* encrypting secret subkey */
assert_rnp_success(rnp_key_get_subkey_at(key, 1, &sub));
assert_rnp_success(rnp_key_get_keyid(sub, &keyid));
assert_string_equal(keyid, "DD23CEB7FEBEFF17");
rnp_buffer_destroy(keyid);
secret = false;
assert_rnp_success(rnp_key_have_secret(sub, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* secret subkeys, and primary key stored on the smartcard by gpg */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-2-card.pgp"));
assert_rnp_success(rnp_import_keys(
ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "GPG-Smartcard");
rnp_buffer_destroy(type);
assert_rnp_failure(rnp_key_unlock(key, "password"));
count = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
/* signing secret subkey */
assert_rnp_success(rnp_locate_key(ffi, "keyid", "22F3A217C0E439CB", &sub));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
rnp_key_handle_destroy(sub);
/* encrypting secret subkey */
assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD23CEB7FEBEFF17", &sub));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(sub, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(sub, &type));
assert_string_equal(type, "Encrypted-Hashed");
rnp_buffer_destroy(type);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* save keyrings and reload */
reload_keyrings(&ffi);
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
count = 0;
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "GPG-Smartcard");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_destroy(key);
/* load key with too large gpg_serial_len */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-2-card-len.pgp"));
assert_rnp_success(rnp_import_keys(
ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "GPG-Smartcard");
rnp_buffer_destroy(type);
assert_rnp_failure(rnp_key_unlock(key, "password"));
rnp_key_handle_destroy(key);
/* secret subkeys, and primary key stored with unknown gpg s2k */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-3.pgp"));
assert_rnp_success(rnp_import_keys(
ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "Unknown");
rnp_buffer_destroy(type);
assert_rnp_failure(rnp_key_unlock(key, "password"));
count = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_destroy(key);
/* save keyrings and reload */
reload_keyrings(&ffi);
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
count = 0;
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "Unknown");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_destroy(key);
/* secret subkeys, and primary key stored with unknown s2k */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-unknown.pgp"));
assert_rnp_success(rnp_import_keys(
ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
locked = false;
assert_rnp_success(rnp_key_is_locked(key, &locked));
assert_true(locked);
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "Unknown");
rnp_buffer_destroy(type);
assert_rnp_failure(rnp_key_unlock(key, "password"));
count = 0;
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_destroy(key);
/* save keyrings and reload */
reload_keyrings(&ffi);
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669FFDE3C", &key));
secret = false;
assert_rnp_success(rnp_key_have_secret(key, &secret));
assert_true(secret);
count = 0;
assert_rnp_success(rnp_key_get_protection_type(key, &type));
assert_string_equal(type, "Unknown");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 2);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}
static bool
check_key_autocrypt(rnp_output_t memout,
const std::string &keyid,
const std::string &subid,
const std::string &uid,
bool base64 = false)
{
rnp_ffi_t ffi = NULL;
rnp_ffi_create(&ffi, "GPG", "GPG");
uint8_t *buf = NULL;
size_t len = 0;
if (rnp_output_memory_get_buf(memout, &buf, &len, false) || !buf || !len) {
return false;
}
if (!import_all_keys(ffi, buf, len, base64 ? RNP_LOAD_SAVE_BASE64 : 0)) {
return false;
}
size_t count = 0;
rnp_get_public_key_count(ffi, &count);
if (count != 2) {
return false;
}
rnp_get_secret_key_count(ffi, &count);
if (count != 0) {
return false;
}
rnp_key_handle_t key = NULL;
if (rnp_locate_key(ffi, "keyid", keyid.c_str(), &key) || !key) {
return false;
}
rnp_key_handle_t sub = NULL;
if (rnp_locate_key(ffi, "keyid", subid.c_str(), &sub) || !sub) {
return false;
}
if (!key->pub->valid() || !sub->pub->valid()) {
return false;
}
if ((key->pub->sig_count() != 1) || (sub->pub->sig_count() != 1)) {
return false;
}
if (!key->pub->can_sign() || !sub->pub->can_encrypt()) {
return false;
}
if ((key->pub->uid_count() != 1) || (key->pub->get_uid(0).str != uid)) {
return false;
}
rnp_key_handle_destroy(key);
rnp_key_handle_destroy(sub);
rnp_ffi_destroy(ffi);
return true;
}
TEST_F(rnp_tests, test_ffi_key_export_autocrypt)
{
rnp_ffi_t ffi = NULL;
test_ffi_init(&ffi);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
rnp_key_handle_t sub = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "8a05b89fad5aded1", &sub));
/* edge cases */
assert_rnp_failure(rnp_key_export_autocrypt(key, NULL, NULL, NULL, 0));
rnp_output_t output = NULL;
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, sub, NULL, output, 17));
assert_rnp_failure(rnp_key_export_autocrypt(NULL, sub, "key0-uid0", output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, sub, NULL, output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, key, NULL, output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, key, "key0-uid0", output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(sub, sub, "key0-uid0", output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(sub, key, "key0-uid0", output, 0));
assert_int_equal(output->dst.writeb, 0);
/* export key + uid1 + sub2 */
assert_rnp_success(rnp_key_export_autocrypt(key, sub, "key0-uid1", output, 0));
assert_true(
check_key_autocrypt(output, "7bc6709b15c23a4a", "8a05b89fad5aded1", "key0-uid1"));
rnp_output_destroy(output);
/* export key + uid0 + sub1 (fail) */
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "1d7e8a5393c997a8", &sub));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, sub, "key0-uid0", output, 0));
assert_int_equal(output->dst.writeb, 0);
rnp_key_handle_destroy(sub);
/* export key without specifying subkey */
assert_rnp_success(rnp_key_export_autocrypt(key, NULL, "key0-uid2", output, 0));
assert_true(
check_key_autocrypt(output, "7bc6709b15c23a4a", "8a05b89fad5aded1", "key0-uid2"));
rnp_output_destroy(output);
/* export base64-encoded key */
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(
rnp_key_export_autocrypt(key, NULL, "key0-uid2", output, RNP_KEY_EXPORT_BASE64));
/* Make sure it is base64-encoded */
const std::string reg = "^[A-Za-z0-9\\+\\/]+={0,2}$";
uint8_t * buf = NULL;
size_t len = 0;
assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
std::string val((char *) buf, (char *) buf + len);
#ifndef RNP_USE_STD_REGEX
static regex_t r;
regmatch_t matches[1];
assert_int_equal(regcomp(&r, reg.c_str(), REG_EXTENDED), 0);
assert_int_equal(regexec(&r, val.c_str(), 1, matches, 0), 0);
#else
static std::regex re(reg, std::regex_constants::extended | std::regex_constants::icase);
std::smatch result;
assert_true(std::regex_search(val, result, re));
#endif
/* Fails to load without base64 flag */
assert_false(import_all_keys(ffi, buf, len));
/* Now should succeed */
assert_true(
check_key_autocrypt(output, "7bc6709b15c23a4a", "8a05b89fad5aded1", "key0-uid2", true));
rnp_output_destroy(output);
/* remove first subkey and export again */
assert_rnp_success(rnp_locate_key(ffi, "keyid", "1ed63ee56fadc34d", &sub));
assert_rnp_success(rnp_key_remove(sub, RNP_KEY_REMOVE_PUBLIC));
rnp_key_handle_destroy(sub);
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(rnp_key_export_autocrypt(key, NULL, "key0-uid0", output, 0));
assert_true(
check_key_autocrypt(output, "7bc6709b15c23a4a", "8a05b89fad5aded1", "key0-uid0"));
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
/* primary key with encrypting capability, make sure subkey is exported */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, "data/test_key_validity/encrypting-primary.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "92091b7b76c50017", &key));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(rnp_key_export_autocrypt(
key, NULL, "encrypting primary <encrypting_primary@rnp>", output, 0));
assert_true(check_key_autocrypt(output,
"92091b7b76c50017",
"c2e243e872c1fe50",
"encrypting primary <encrypting_primary@rnp>"));
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
/* export key with single uid and subkey */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, "data/test_key_validity/alice-sub-pub.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(rnp_key_export_autocrypt(key, NULL, NULL, output, 0));
assert_true(check_key_autocrypt(
output, "0451409669ffde3c", "dd23ceb7febeff17", "Alice <alice@rnp>"));
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
/* export key with sign-only subkey: fail */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, "data/test_key_validity/alice-sign-sub-pub.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "22f3a217c0e439cb", &sub));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, sub, NULL, output, 0));
assert_int_equal(output->dst.writeb, 0);
assert_rnp_failure(rnp_key_export_autocrypt(key, NULL, NULL, output, 0));
assert_int_equal(output->dst.writeb, 0);
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
rnp_key_handle_destroy(sub);
/* export key without subkey: fail */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_pub_keys(ffi, "data/test_key_validity/alice-pub.asc"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_failure(rnp_key_export_autocrypt(key, NULL, NULL, output, 0));
assert_int_equal(output->dst.writeb, 0);
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
/* export secret key: make sure public is exported */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(import_all_keys(ffi, "data/test_key_validity/alice-sub-sec.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(rnp_key_export_autocrypt(key, NULL, NULL, output, 0));
assert_true(check_key_autocrypt(
output, "0451409669ffde3c", "dd23ceb7febeff17", "Alice <alice@rnp>"));
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
/* make sure that only self-certification is exported */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
/* load key alice with 2 self-sigs, one of those is expired */
assert_true(import_pub_keys(ffi, "data/test_key_validity/case9/pubring.gpg"));
/* add one corrupted alice's signature and one valid from Basil */
assert_true(import_pub_keys(ffi, "data/test_key_validity/case2/pubring.gpg"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
assert_int_equal(key->pub->sig_count(), 4);
assert_rnp_success(rnp_output_to_memory(&output, 0));
assert_rnp_success(rnp_key_export_autocrypt(key, NULL, NULL, output, 0));
assert_true(check_key_autocrypt(
output, "0451409669ffde3c", "dd23ceb7febeff17", "Alice <alice@rnp>"));
rnp_output_destroy(output);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_keys_import_autocrypt)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
rnp_input_t input = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-25519-pub.b64"));
/* no base64 flag */
assert_rnp_failure(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
/* enable base64 flag */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-25519-pub.b64"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
size_t keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 1);
/* load other files, with different base64 formatting */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-25519-pub-2.b64"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 1);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-25519-pub-3.b64"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 1);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-25519-pub-4.b64"));
assert_rnp_failure(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 0);
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-p256k1-pub.b64"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 2);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-p256k1-pub-2.b64"));
assert_rnp_success(
rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_BASE64, NULL));
rnp_input_destroy(input);
keycount = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keycount));
assert_int_equal(keycount, 2);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_keys_load_armored_spaces)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
const char *key = R"key(
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEXLO69BYJKwYBBAHaRw8BAQdAWsoBwHOLMrbp7ykSSCD7FYG7tMYT74aLn5wh
Q63nmJC0BmVjZHNhMIiQBBMWCAA4FiEEMuxFQcPhApFLtGbaEJXD7W1DwDsFAlyz
uvQCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQEJXD7W1DwDs/cwD+PQt4
GnDUFFW2omo7XJh6AUUC4eUnKQoMWoD3iwYetCwA/1leV7sUdsvs5wvkp+LJVDTW
dbpkwTCmBVbAmazgea0B
=omFJ
-----END PGP PUBLIC KEY BLOCK-----
)key";
rnp_input_t input = NULL;
assert_rnp_success(rnp_input_from_memory(&input, (uint8_t *) key, strlen(key), false));
assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
size_t keys = 0;
assert_rnp_success(rnp_get_public_key_count(ffi, &keys));
assert_int_equal(keys, 1);
rnp_ffi_destroy(ffi);
}
/* Functions below are used to demonstrate how to check whether key has weak MD5/SHA1
* signatures, and may be reused later in FFI code */
static bool
is_self_signature(const char *keyid, rnp_signature_handle_t sig)
{
char *signer = NULL;
rnp_signature_get_keyid(sig, &signer);
if (!signer) {
return false;
}
bool result = !strcmp(keyid, signer);
rnp_buffer_destroy(signer);
return result;
}
static bool
is_weak_signature(rnp_ffi_t ffi, rnp_signature_handle_t sig)
{
char * hash = NULL;
uint32_t creation = 0;
rnp_signature_get_hash_alg(sig, &hash);
rnp_signature_get_creation(sig, &creation);
/* This approach would be more general, however hardcoding MD5/SHA1 may be used as well */
uint32_t flags = RNP_SECURITY_VERIFY_KEY;
uint32_t level = 0;
rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, hash, creation, &flags, NULL, &level);
bool res = level < RNP_SECURITY_DEFAULT;
if (res) {
printf(
"Detected weak signature with %s hash, created at %zu\n", hash, (size_t) creation);
}
rnp_buffer_destroy(hash);
return res;
}
static const std::string
get_uid_str(rnp_uid_handle_t uid)
{
uint32_t type = 0;
rnp_uid_get_type(uid, &type);
switch (type) {
case RNP_USER_ID: {
void * data = NULL;
size_t len = 0;
rnp_uid_get_data(uid, &data, &len);
std::string res((const char *) data, (const char *) data + len);
rnp_buffer_destroy(data);
return res;
}
case RNP_USER_ATTR:
return "photo";
default:
return "Unknown";
}
}
static size_t
key_weak_self_signatures_count(rnp_ffi_t ffi, rnp_key_handle_t key)
{
char *keyid = NULL;
rnp_key_get_keyid(key, &keyid);
bool valid = false;
rnp_key_is_valid(key, &valid);
printf(
"Key %s is %s, checking for the weak signatures.\n", keyid, valid ? "valid" : "invalid");
/* Check direct-key signatures */
size_t res = 0;
size_t count = 0;
rnp_key_get_signature_count(key, &count);
for (size_t i = 0; i < count; i++) {
rnp_signature_handle_t sig = NULL;
rnp_key_get_signature_at(key, i, &sig);
if (is_self_signature(keyid, sig) && is_weak_signature(ffi, sig)) {
printf("Key %s has weak direct-key signature at index %zu.\n", keyid, i);
res++;
}
rnp_signature_handle_destroy(sig);
}
/* Check certifications */
size_t uidcount = 0;
rnp_key_get_uid_count(key, &uidcount);
for (size_t i = 0; i < uidcount; i++) {
rnp_uid_handle_t uid = NULL;
rnp_key_get_uid_handle_at(key, i, &uid);
count = 0;
rnp_uid_get_signature_count(uid, &count);
for (size_t j = 0; j < count; j++) {
rnp_signature_handle_t sig = NULL;
rnp_uid_get_signature_at(uid, j, &sig);
if (is_self_signature(keyid, sig) && is_weak_signature(ffi, sig)) {
auto uidstr = get_uid_str(uid);
printf("Uid %s of the key %s has weak self-certification at index %zu.\n",
uidstr.c_str(),
keyid,
j);
res++;
}
rnp_signature_handle_destroy(sig);
}
rnp_uid_handle_destroy(uid);
}
/* Check subkeys */
size_t subcount = 0;
rnp_key_get_subkey_count(key, &subcount);
for (size_t i = 0; i < subcount; i++) {
rnp_key_handle_t subkey = NULL;
rnp_key_get_subkey_at(key, i, &subkey);
count = 0;
rnp_key_get_signature_count(subkey, &count);
for (size_t j = 0; j < count; j++) {
rnp_signature_handle_t sig = NULL;
rnp_key_get_signature_at(subkey, j, &sig);
if (is_self_signature(keyid, sig) && is_weak_signature(ffi, sig)) {
char *subid = NULL;
rnp_key_get_keyid(subkey, &subid);
printf("Subkey %s of the key %s has weak binding signature at index %zu.\n",
subid,
keyid,
j);
res++;
rnp_buffer_destroy(subid);
}
rnp_signature_handle_destroy(sig);
}
rnp_key_handle_destroy(subkey);
}
rnp_buffer_destroy(keyid);
return res;
}
TEST_F(rnp_tests, test_ffi_sha1_self_signatures)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* This key has SHA1 self signature, made before the cut-off date */
assert_true(import_pub_keys(ffi, "data/test_stream_key_load/rsa-rsa-pub.asc"));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fb9179118898e8b", &key));
/* Check key validity */
bool valid = false;
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_true(valid);
size_t count = 0;
/* Check uid validity */
assert_rnp_success(rnp_key_get_uid_count(key, &count));
assert_int_equal(count, 1);
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* Check subkey validity */
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 1);
rnp_key_handle_t sub = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_true(valid);
/* Check weak signature count */
assert_int_equal(key_weak_self_signatures_count(ffi, key), 0);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
/* Check the key which has SHA1 self signature, made after the cut-off date */
assert_rnp_success(rnp_set_timestamp(ffi, SHA1_KEY_FROM + 10));
assert_true(import_pub_keys(ffi, "data/test_forged_keys/eddsa-2024-pub.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "980e3741f632212c", &key));
/* Check key validity */
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_false(valid);
/* Check uid validity */
assert_rnp_success(rnp_key_get_uid_count(key, &count));
assert_int_equal(count, 1);
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
rnp_uid_handle_destroy(uid);
/* Check subkey validity */
assert_rnp_success(rnp_key_get_subkey_count(key, &count));
assert_int_equal(count, 1);
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_false(valid);
/* Check weak signature count */
assert_int_equal(key_weak_self_signatures_count(ffi, key), 2);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
/* Now allow the SHA1 hash */
assert_rnp_success(rnp_add_security_rule(ffi,
RNP_FEATURE_HASH_ALG,
"SHA1",
RNP_SECURITY_OVERRIDE,
SHA1_KEY_FROM + 1,
RNP_SECURITY_DEFAULT));
assert_true(import_pub_keys(ffi, "data/test_forged_keys/eddsa-2024-pub.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "980e3741f632212c", &key));
/* Check key validity */
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_true(valid);
/* Check uid validity */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* Check subkey validity */
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_true(valid);
/* Check weak signature count */
assert_int_equal(key_weak_self_signatures_count(ffi, key), 0);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* Check the key which has MD5 self signature, made after the cut-off date */
assert_true(import_pub_keys(ffi, "data/test_forged_keys/eddsa-2012-md5-pub.pgp"));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "8801eafbd906bd21", &key));
/* Check key validity */
assert_rnp_success(rnp_key_is_valid(key, &valid));
assert_false(valid);
/* Check uid validity */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
rnp_uid_handle_destroy(uid);
/* Check subkey validity */
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &sub));
assert_rnp_success(rnp_key_is_valid(sub, &valid));
assert_false(valid);
/* Check weak signature count */
assert_int_equal(key_weak_self_signatures_count(ffi, key), 2);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_reprotect_keys)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* Cast5-encrypted keys */
assert_true(
load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg", "data/keyrings/1/secring-cast5.gpg"));
rnp_identifier_iterator_t it = NULL;
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
assert_non_null(it);
const char *ident = NULL;
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (!ident) {
break;
}
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "fingerprint", ident, &key));
if (cast5_enabled()) {
assert_rnp_success(rnp_key_unprotect(key, "password"));
assert_rnp_success(rnp_key_protect(key, "password", "AES256", NULL, NULL, 65536));
} else {
assert_rnp_failure(rnp_key_unprotect(key, "password"));
}
rnp_key_handle_destroy(key);
} while (1);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
/* AES-encrypted keys */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
assert_true(
load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg", "data/keyrings/1/secring.gpg"));
assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
assert_non_null(it);
do {
ident = NULL;
assert_rnp_success(rnp_identifier_iterator_next(it, &ident));
if (!ident) {
break;
}
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "fingerprint", ident, &key));
assert_rnp_success(rnp_key_unprotect(key, "password"));
if (cast5_enabled()) {
assert_rnp_success(rnp_key_protect(key, "password", "CAST5", NULL, NULL, 65536));
} else {
assert_rnp_success(rnp_key_protect(key, "password", "AES128", NULL, NULL, 65536));
}
rnp_key_handle_destroy(key);
} while (1);
assert_rnp_success(rnp_identifier_iterator_destroy(it));
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_armored_keys_extra_line)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* Key with extra line after the checksum */
assert_true(
import_pub_keys(ffi, "data/test_stream_key_load/ecc-25519-pub-extra-line.asc"));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "cc786278981b0728", &key));
assert_true(check_key_valid(key, true));
assert_true(check_uid_valid(key, 0, true));
rnp_key_handle_destroy(key);
/* Key with extra lines with spaces after the checksum */
assert_true(
import_pub_keys(ffi, "data/test_stream_key_load/ecc-25519-pub-extra-line-2.asc"));
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "cc786278981b0728", &key));
assert_true(check_key_valid(key, true));
assert_true(check_uid_valid(key, 0, true));
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}