/* * 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 #include "rnp_tests.h" #include "support.h" #include #include "pgp-key.h" #include "ffi-priv-types.h" #include "str-utils.h" #ifndef RNP_USE_STD_REGEX #include #else #include #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 &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 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 ", output, 0)); assert_true(check_key_autocrypt(output, "92091b7b76c50017", "c2e243e872c1fe50", "encrypting primary ")); 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 ")); 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 ")); 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 ")); 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); }