summaryrefslogtreecommitdiffstats
path: root/src/tests/ffi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/ffi.cpp')
-rw-r--r--src/tests/ffi.cpp6025
1 files changed, 6025 insertions, 0 deletions
diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp
new file mode 100644
index 0000000..1e75871
--- /dev/null
+++ b/src/tests/ffi.cpp
@@ -0,0 +1,6025 @@
+/*
+ * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fstream>
+#include <vector>
+#include <string>
+#include <set>
+#include <utility>
+
+#include <rnp/rnp.h>
+#include "rnp_tests.h"
+#include "support.h"
+#include "librepgp/stream-common.h"
+#include "librepgp/stream-packet.h"
+#include "librepgp/stream-sig.h"
+#include <json.h>
+#include "file-utils.h"
+#include "str-utils.h"
+#include <librepgp/stream-ctx.h>
+#include "pgp-key.h"
+#include "ffi-priv-types.h"
+
+TEST_F(rnp_tests, test_ffi_homedir)
+{
+ rnp_ffi_t ffi = NULL;
+ char * pub_format = NULL;
+ char * pub_path = NULL;
+ char * sec_format = NULL;
+ char * sec_path = NULL;
+
+ // get the default homedir (not a very thorough test)
+ {
+ assert_rnp_failure(rnp_get_default_homedir(NULL));
+ char *homedir = NULL;
+ assert_rnp_success(rnp_get_default_homedir(&homedir));
+ assert_non_null(homedir);
+ rnp_buffer_destroy(homedir);
+ }
+
+ // check NULL params
+ assert_rnp_failure(
+ rnp_detect_homedir_info(NULL, &pub_format, &pub_path, &sec_format, &sec_path));
+ assert_rnp_failure(
+ rnp_detect_homedir_info("data/keyrings/1", NULL, &pub_path, &sec_format, &sec_path));
+ assert_rnp_failure(
+ rnp_detect_homedir_info("data/keyrings/1", &pub_format, NULL, &sec_format, &sec_path));
+ assert_rnp_failure(
+ rnp_detect_homedir_info("data/keyrings/1", &pub_format, &pub_path, NULL, &sec_path));
+ assert_rnp_failure(
+ rnp_detect_homedir_info("data/keyrings/1", &pub_format, &pub_path, &sec_format, NULL));
+ // detect the formats+paths
+ assert_rnp_success(rnp_detect_homedir_info(
+ "data/keyrings/1", &pub_format, &pub_path, &sec_format, &sec_path));
+ // check formats
+ assert_string_equal(pub_format, "GPG");
+ assert_string_equal(sec_format, "GPG");
+ // check paths
+ assert_string_equal(pub_path, "data/keyrings/1/pubring.gpg");
+ assert_string_equal(sec_path, "data/keyrings/1/secring.gpg");
+ rnp_buffer_destroy(pub_format);
+ rnp_buffer_destroy(pub_path);
+ rnp_buffer_destroy(sec_format);
+ rnp_buffer_destroy(sec_path);
+// detect windows-style slashes
+#ifdef _WIN32
+ assert_rnp_success(rnp_detect_homedir_info(
+ "data\\keyrings\\1", &pub_format, &pub_path, &sec_format, &sec_path));
+ // check formats
+ assert_string_equal(pub_format, "GPG");
+ assert_string_equal(sec_format, "GPG");
+ // check paths
+ assert_string_equal(pub_path, "data\\keyrings\\1\\pubring.gpg");
+ assert_string_equal(sec_path, "data\\keyrings\\1\\secring.gpg");
+ rnp_buffer_destroy(pub_format);
+ rnp_buffer_destroy(pub_path);
+ rnp_buffer_destroy(sec_format);
+ rnp_buffer_destroy(sec_path);
+#endif
+ // detect with the trailing slash
+ assert_rnp_success(rnp_detect_homedir_info(
+ "data/keyrings/1/", &pub_format, &pub_path, &sec_format, &sec_path));
+ // check formats
+ assert_string_equal(pub_format, "GPG");
+ assert_string_equal(sec_format, "GPG");
+ // check paths
+ assert_string_equal(pub_path, "data/keyrings/1/pubring.gpg");
+ assert_string_equal(sec_path, "data/keyrings/1/secring.gpg");
+ // setup FFI with wrong parameters
+ assert_rnp_failure(rnp_ffi_create(NULL, "GPG", "GPG"));
+ assert_rnp_failure(rnp_ffi_create(&ffi, "GPG", NULL));
+ assert_rnp_failure(rnp_ffi_create(&ffi, NULL, "GPG"));
+ assert_rnp_failure(rnp_ffi_create(&ffi, "ZZG", "GPG"));
+ assert_rnp_failure(rnp_ffi_create(&ffi, "GPG", "ZZG"));
+ // 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;
+ // check key counts
+ size_t count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ // detect the formats+paths
+ assert_rnp_success(rnp_detect_homedir_info(
+ "data/keyrings/3", &pub_format, &pub_path, &sec_format, &sec_path));
+ // check formats
+ assert_string_equal(pub_format, "KBX");
+ assert_string_equal(sec_format, "G10");
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, pub_format, sec_format));
+ // load our keyrings
+ assert_true(load_keys_kbx_g10(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;
+ // check 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 grip (1)
+ rnp_key_handle_t key = NULL;
+ assert_int_equal(
+ RNP_SUCCESS,
+ rnp_locate_key(ffi, "grip", "63E59092E4B1AE9F8E675B2F98AA2B8BD9F4EA59", &key));
+ assert_non_null(key);
+ char *grip = NULL;
+ assert_rnp_success(rnp_key_get_grip(key, &grip));
+ assert_non_null(grip);
+ assert_string_equal(grip, "63E59092E4B1AE9F8E675B2F98AA2B8BD9F4EA59");
+ rnp_buffer_destroy(grip);
+ grip = NULL;
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // check grip (2)
+ assert_int_equal(
+ RNP_SUCCESS,
+ rnp_locate_key(ffi, "grip", "7EAB41A2F46257C36F2892696F5A2F0432499AD3", &key));
+ assert_non_null(key);
+ grip = NULL;
+ assert_rnp_success(rnp_key_get_grip(key, &grip));
+ assert_non_null(grip);
+ assert_string_equal(grip, "7EAB41A2F46257C36F2892696F5A2F0432499AD3");
+ rnp_buffer_destroy(grip);
+ grip = NULL;
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_detect_key_format)
+{
+ char *format = NULL;
+
+ // Wrong parameters
+ auto data = file_to_vec("data/keyrings/1/pubring.gpg");
+ assert_rnp_failure(rnp_detect_key_format(NULL, data.size(), &format));
+ assert_rnp_failure(rnp_detect_key_format(data.data(), 0, &format));
+ assert_rnp_failure(rnp_detect_key_format(data.data(), data.size(), NULL));
+ free(format);
+
+ // GPG
+ format = NULL;
+ data = file_to_vec("data/keyrings/1/pubring.gpg");
+ assert_rnp_success(rnp_detect_key_format(data.data(), data.size(), &format));
+ assert_string_equal(format, "GPG");
+ free(format);
+ format = NULL;
+
+ // GPG
+ data = file_to_vec("data/keyrings/1/secring.gpg");
+ assert_rnp_success(rnp_detect_key_format(data.data(), data.size(), &format));
+ assert_string_equal(format, "GPG");
+ free(format);
+ format = NULL;
+
+ // GPG (armored)
+ data = file_to_vec("data/keyrings/4/rsav3-p.asc");
+ assert_rnp_success(rnp_detect_key_format(data.data(), data.size(), &format));
+ assert_string_equal(format, "GPG");
+ free(format);
+ format = NULL;
+
+ // KBX
+ data = file_to_vec("data/keyrings/3/pubring.kbx");
+ assert_rnp_success(rnp_detect_key_format(data.data(), data.size(), &format));
+ assert_string_equal(format, "KBX");
+ free(format);
+ format = NULL;
+
+ // G10
+ data = file_to_vec(
+ "data/keyrings/3/private-keys-v1.d/63E59092E4B1AE9F8E675B2F98AA2B8BD9F4EA59.key");
+ assert_rnp_success(rnp_detect_key_format(data.data(), data.size(), &format));
+ assert_string_equal(format, "G10");
+ free(format);
+ format = NULL;
+
+ // invalid
+ assert_rnp_success(rnp_detect_key_format((uint8_t *) "ABC", 3, &format));
+ assert_null(format);
+}
+
+TEST_F(rnp_tests, test_ffi_load_keys)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ size_t count;
+
+ /* load public keys from pubring */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load pubring
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg"));
+ // again
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg"));
+ // check counts
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(0, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ /* load public keys from secring */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/secring.gpg"));
+ // check counts
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(0, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ /* load secret keys from secring */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load secring
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/secring.gpg"));
+ // again
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/secring.gpg"));
+ // check counts
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(0, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ /* load secret keys from pubring */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load pubring
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/pubring.gpg"));
+ // check counts
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(0, count);
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(0, count);
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ /* concatenate the pubring and secrings into a single buffer */
+ auto pub_buf = file_to_vec("data/keyrings/1/pubring.gpg");
+ auto sec_buf = file_to_vec("data/keyrings/1/secring.gpg");
+ auto buf = pub_buf;
+ buf.reserve(buf.size() + sec_buf.size());
+ buf.insert(buf.end(), sec_buf.begin(), sec_buf.end());
+
+ /* load secret keys from pubring */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load
+ assert_rnp_success(rnp_input_from_memory(&input, buf.data(), buf.size(), true));
+ assert_non_null(input);
+ // try wrong parameters
+ assert_rnp_failure(rnp_load_keys(NULL, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_failure(rnp_load_keys(ffi, NULL, input, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_failure(rnp_load_keys(ffi, "GPG", NULL, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_failure(rnp_load_keys(ffi, "WRONG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_failure(rnp_load_keys(ffi, "WRONG", input, 0));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ // again
+ assert_rnp_success(rnp_input_from_memory(&input, buf.data(), buf.size(), true));
+ assert_non_null(input);
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ // check counts
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+}
+
+TEST_F(rnp_tests, test_ffi_clear_keys)
+{
+ rnp_ffi_t ffi = NULL;
+ size_t pub_count;
+ size_t sec_count;
+
+ // setup FFI
+ test_ffi_init(&ffi);
+ // check counts
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(7, pub_count);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(7, sec_count);
+ // clear public keys
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(pub_count, 0);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(sec_count, 7);
+ // clear secret keys
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(pub_count, 0);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(sec_count, 0);
+ // load public and clear secret keys
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(pub_count, 7);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(sec_count, 0);
+ // load secret keys and clear all
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(7, pub_count);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(7, sec_count);
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &pub_count));
+ assert_int_equal(pub_count, 0);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &sec_count));
+ assert_int_equal(sec_count, 0);
+ // attempt to clear NULL ffi
+ assert_rnp_failure(rnp_unload_keys(NULL, RNP_KEY_UNLOAD_SECRET));
+ // attempt to pass wrong flags
+ assert_rnp_failure(rnp_unload_keys(ffi, 255));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+}
+
+TEST_F(rnp_tests, test_ffi_save_keys)
+{
+ rnp_ffi_t ffi = NULL;
+ // setup FFI
+ test_ffi_init(&ffi);
+ char *temp_dir = make_temp_dir();
+ // save pubring
+ auto pub_path = rnp::path::append(temp_dir, "pubring.gpg");
+ assert_false(rnp::path::exists(pub_path));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_path(&output, pub_path.c_str()));
+ assert_rnp_failure(rnp_save_keys(NULL, "GPG", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_failure(rnp_save_keys(ffi, NULL, output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_failure(rnp_save_keys(ffi, "GPG", NULL, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_failure(rnp_save_keys(ffi, "WRONG", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_failure(rnp_save_keys(ffi, "GPG", output, 0));
+ assert_rnp_success(rnp_save_keys(ffi, "GPG", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(pub_path));
+ // save secring
+ auto sec_path = rnp::path::append(temp_dir, "secring.gpg");
+ assert_false(rnp::path::exists(sec_path));
+ assert_rnp_success(rnp_output_to_path(&output, sec_path.c_str()));
+ assert_rnp_success(rnp_save_keys(ffi, "GPG", output, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(sec_path));
+ // save pubring && secring
+ auto both_path = rnp::path::append(temp_dir, "bothring.gpg");
+ assert_false(rnp::path::exists(both_path));
+ assert_rnp_success(rnp_output_to_path(&output, both_path.c_str()));
+ assert_int_equal(
+ RNP_SUCCESS,
+ rnp_save_keys(
+ ffi, "GPG", output, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(both_path));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+ // start over (read from the saved locations)
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load pubring & secring
+ assert_true(load_keys_gpg(ffi, pub_path, sec_path));
+ // check the counts
+ size_t count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+ // load both keyrings from the single file
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load pubring
+ rnp_input_t input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, both_path.c_str()));
+ assert_non_null(input);
+ assert_int_equal(
+ RNP_SUCCESS,
+ rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ // check the counts. We should get both secret and public keys, since public keys are
+ // extracted from the secret ones.
+ count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "KBX", "G10"));
+ // load pubring & secring
+ assert_true(load_keys_kbx_g10(
+ ffi, "data/keyrings/3/pubring.kbx", "data/keyrings/3/private-keys-v1.d"));
+ // save pubring
+ pub_path = rnp::path::append(temp_dir, "pubring.kbx");
+ assert_rnp_success(rnp_output_to_path(&output, pub_path.c_str()));
+ assert_rnp_success(rnp_save_keys(ffi, "KBX", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(pub_path));
+ // save secring to file - will fail for G10
+ sec_path = rnp::path::append(temp_dir, "secring.file");
+ assert_rnp_success(rnp_output_to_path(&output, sec_path.c_str()));
+ assert_rnp_failure(rnp_save_keys(ffi, "G10", output, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ // save secring
+ sec_path = rnp::path::append(temp_dir, "private-keys-v1.d");
+ assert_false(rnp::path::exists(sec_path, true));
+ assert_int_equal(0, RNP_MKDIR(sec_path.c_str(), S_IRWXU));
+ assert_rnp_success(rnp_output_to_path(&output, sec_path.c_str()));
+ assert_rnp_success(rnp_save_keys(ffi, "G10", output, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(sec_path, true));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+ // start over (read from the saved locations)
+ assert_rnp_success(rnp_ffi_create(&ffi, "KBX", "G10"));
+ // load pubring & secring
+ assert_true(load_keys_kbx_g10(ffi, pub_path, sec_path));
+ // check the counts
+ count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(2, count);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(2, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+
+ // final cleanup
+ clean_temp_dir(temp_dir);
+ free(temp_dir);
+}
+
+TEST_F(rnp_tests, test_ffi_load_save_keys_to_utf8_path)
+{
+ const char kbx_pubring_utf8_filename[] = "pubring_\xC2\xA2.kbx";
+ const char g10_secring_utf8_dirname[] = "private-keys-\xC2\xA2.d";
+ const char utf8_filename[] = "bothring_\xC2\xA2.gpg";
+
+ // setup FFI
+ rnp_ffi_t ffi = NULL;
+ test_ffi_init(&ffi);
+ auto temp_dir = make_temp_dir();
+ // save pubring && secring
+ auto both_path = rnp::path::append(temp_dir, utf8_filename);
+ assert_false(rnp::path::exists(both_path));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_path(&output, both_path.c_str()));
+ assert_rnp_success(rnp_save_keys(
+ ffi, "GPG", output, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(both_path));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+ // start over (read from the saved locations)
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load both keyrings from the single file
+ rnp_input_t input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, both_path.c_str()));
+ assert_non_null(input);
+ assert_rnp_success(
+ rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ // check the counts. We should get both secret and public keys, since public keys are
+ // extracted from the secret ones.
+ size_t count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(7, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "KBX", "G10"));
+ // load pubring
+ assert_true(load_keys_kbx_g10(
+ ffi, "data/keyrings/3/pubring.kbx", "data/keyrings/3/private-keys-v1.d"));
+ // save pubring
+ auto pub_path = rnp::path::append(temp_dir, kbx_pubring_utf8_filename);
+ assert_rnp_success(rnp_output_to_path(&output, pub_path.c_str()));
+ assert_rnp_success(rnp_save_keys(ffi, "KBX", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(pub_path));
+ // save secring
+ auto sec_path = rnp::path::append(temp_dir, g10_secring_utf8_dirname);
+ assert_false(rnp::path::exists(sec_path, true));
+ assert_int_equal(0, RNP_MKDIR(sec_path.c_str(), S_IRWXU));
+ assert_rnp_success(rnp_output_to_path(&output, sec_path.c_str()));
+ assert_rnp_success(rnp_save_keys(ffi, "G10", output, RNP_LOAD_SAVE_SECRET_KEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_true(rnp::path::exists(sec_path, true));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+ ffi = NULL;
+ // start over (read from the saved locations)
+ assert_rnp_success(rnp_ffi_create(&ffi, "KBX", "G10"));
+ // load pubring & secring
+ assert_true(load_keys_kbx_g10(ffi, pub_path, sec_path));
+ // check the counts
+ count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(2, count);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(2, count);
+ // cleanup
+ rnp_ffi_destroy(ffi);
+
+ // final cleanup
+ clean_temp_dir(temp_dir);
+ free(temp_dir);
+}
+
+static size_t
+get_longest_line_length(const std::string &str, const std::set<std::string> lines_to_skip)
+{
+ // eol could be \n or \r\n
+ size_t index = 0;
+ size_t max_len = 0;
+ for (;;) {
+ auto new_index = str.find('\n', index);
+ if (new_index == std::string::npos) {
+ break;
+ }
+ size_t line_length = new_index - index;
+ if (str[new_index - 1] == '\r') {
+ line_length--;
+ }
+ if (line_length > max_len &&
+ lines_to_skip.find(str.substr(index, line_length)) == lines_to_skip.end()) {
+ max_len = line_length;
+ }
+ index = new_index + 1;
+ }
+ return max_len;
+}
+
+TEST_F(rnp_tests, test_ffi_add_userid)
+{
+ rnp_ffi_t ffi = NULL;
+ char * results = NULL;
+ size_t count = 0;
+ rnp_uid_handle_t uid;
+ rnp_signature_handle_t sig;
+ char * hash_alg_name = NULL;
+
+ const char *new_userid = "my new userid <user@example.com>";
+ const char *default_hash_userid = "default hash <user@example.com";
+ const char *ripemd_hash_userid = "ripemd160 <user@example.com";
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, 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);
+ rnp_buffer_destroy(results);
+ 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);
+
+ rnp_key_handle_t key_handle = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "test0", &key_handle));
+ assert_non_null(key_handle);
+
+ assert_rnp_success(rnp_key_get_uid_count(key_handle, &count));
+ assert_int_equal(1, count);
+
+ // protect+lock the key
+ if (!sm2_enabled()) {
+ assert_rnp_failure(rnp_key_protect(key_handle, "pass", "SM4", "CFB", "SM3", 999999));
+ assert_rnp_success(
+ rnp_key_protect(key_handle, "pass", "AES128", "CFB", "SHA256", 999999));
+ } else {
+ assert_rnp_success(rnp_key_protect(key_handle, "pass", "SM4", "CFB", "SM3", 999999));
+ }
+ assert_rnp_success(rnp_key_lock(key_handle));
+
+ // add with NULL parameters
+ assert_rnp_failure(rnp_key_add_uid(NULL, new_userid, NULL, 2147317200, 0x00, false));
+ assert_rnp_failure(rnp_key_add_uid(key_handle, NULL, NULL, 2147317200, 0x00, false));
+
+ // add the userid (no pass provider, should fail)
+ assert_int_equal(
+ RNP_ERROR_BAD_PASSWORD,
+ rnp_key_add_uid(key_handle, new_userid, "SHA256", 2147317200, 0x00, false));
+
+ // actually add the userid
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass"));
+ // attempt to add empty uid
+ assert_rnp_failure(rnp_key_add_uid(key_handle, "", NULL, 2147317200, 0, false));
+ // add with default hash algorithm
+ assert_rnp_success(
+ rnp_key_add_uid(key_handle, default_hash_userid, NULL, 2147317200, 0, false));
+ // check whether key was locked back
+ bool locked = false;
+ assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
+ assert_true(locked);
+ // check if default hash was used
+ assert_rnp_success(rnp_key_get_uid_handle_at(key_handle, 1, &uid));
+ assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
+ assert_rnp_success(rnp_signature_get_hash_alg(sig, &hash_alg_name));
+ assert_int_equal(strcasecmp(hash_alg_name, DEFAULT_HASH_ALG), 0);
+ rnp_buffer_destroy(hash_alg_name);
+ hash_alg_name = NULL;
+ assert_rnp_success(rnp_signature_handle_destroy(sig));
+ assert_rnp_success(rnp_uid_handle_destroy(uid));
+
+ assert_int_equal(
+ RNP_SUCCESS, rnp_key_add_uid(key_handle, new_userid, "SHA256", 2147317200, 0x00, false));
+
+ int uid_count_expected = 3;
+ int res =
+ rnp_key_add_uid(key_handle, ripemd_hash_userid, "RIPEMD160", 2147317200, 0, false);
+ if (ripemd160_enabled()) {
+ assert_rnp_success(res);
+ uid_count_expected++;
+ } else {
+ assert_rnp_failure(res);
+ }
+
+ assert_rnp_success(rnp_key_get_uid_count(key_handle, &count));
+ assert_int_equal(uid_count_expected, count);
+
+ rnp_key_handle_t key_handle2 = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", new_userid, &key_handle2));
+ assert_non_null(key_handle2);
+
+ rnp_key_handle_destroy(key_handle);
+ rnp_key_handle_destroy(key_handle2);
+ rnp_ffi_destroy(ffi);
+}
+
+static bool
+file_equals(const char *filename, const void *data, size_t len)
+{
+ pgp_source_t msrc = {};
+ bool res = false;
+
+ if (file_to_mem_src(&msrc, filename)) {
+ return false;
+ }
+
+ res = (msrc.size == len) && !memcmp(mem_src_get_memory(&msrc), data, len);
+ src_close(&msrc);
+ return res;
+}
+
+static void
+test_ffi_init_sign_file_input(rnp_input_t *input, rnp_output_t *output)
+{
+ const char *plaintext = "this is some data that will be signed";
+
+ // write out some data
+ str_to_file("plaintext", plaintext);
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(input, "plaintext"));
+ assert_non_null(*input);
+ assert_rnp_success(rnp_output_to_path(output, "signed"));
+ assert_non_null(*output);
+}
+
+static void
+test_ffi_init_sign_memory_input(rnp_input_t *input, rnp_output_t *output)
+{
+ const char *plaintext = "this is some data that will be signed";
+
+ assert_rnp_success(
+ rnp_input_from_memory(input, (uint8_t *) plaintext, strlen(plaintext), true));
+ assert_non_null(*input);
+ if (output) {
+ assert_rnp_success(rnp_output_to_memory(output, 0));
+ assert_non_null(*output);
+ }
+}
+
+static void
+test_ffi_init_verify_file_input(rnp_input_t *input, rnp_output_t *output)
+{
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(input, "signed"));
+ assert_non_null(*input);
+ assert_rnp_success(rnp_output_to_path(output, "recovered"));
+ assert_non_null(*output);
+}
+
+static void
+test_ffi_init_verify_detached_file_input(rnp_input_t *input, rnp_input_t *signature)
+{
+ assert_rnp_success(rnp_input_from_path(input, "plaintext"));
+ assert_non_null(*input);
+ assert_rnp_success(rnp_input_from_path(signature, "signed"));
+ assert_non_null(*signature);
+}
+
+static void
+test_ffi_init_verify_memory_input(rnp_input_t * input,
+ rnp_output_t *output,
+ uint8_t * signed_buf,
+ size_t signed_len)
+{
+ // create input+output
+ assert_rnp_success(rnp_input_from_memory(input, signed_buf, signed_len, false));
+ assert_non_null(*input);
+ assert_rnp_success(rnp_output_to_memory(output, 0));
+ assert_non_null(*output);
+}
+
+static void
+test_ffi_setup_signatures(rnp_ffi_t *ffi, rnp_op_sign_t *op)
+{
+ rnp_key_handle_t key = NULL;
+ rnp_op_sign_signature_t sig = NULL;
+ // set signature times
+ const uint32_t issued = 1516211899; // Unix epoch, nowish
+ const uint32_t expires = 1000000000; // expires later
+ const uint32_t issued2 = 1516211900; // Unix epoch, nowish
+ const uint32_t expires2 = 2000000000; // expires later
+
+ assert_rnp_success(rnp_op_sign_set_armor(*op, true));
+ assert_rnp_success(rnp_op_sign_set_hash(*op, "SHA256"));
+ assert_rnp_success(rnp_op_sign_set_creation_time(*op, issued));
+ assert_rnp_success(rnp_op_sign_set_expiration_time(*op, expires));
+
+ // set pass provider
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(*ffi, ffi_string_password_provider, (void *) "password"));
+
+ // set first signature key
+ assert_rnp_success(rnp_locate_key(*ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_sign_add_signature(*op, key, NULL));
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // set second signature key
+ assert_rnp_success(rnp_locate_key(*ffi, "userid", "key0-uid1", &key));
+ assert_rnp_success(rnp_op_sign_add_signature(*op, key, &sig));
+ assert_rnp_success(rnp_op_sign_signature_set_creation_time(sig, issued2));
+ assert_rnp_success(rnp_op_sign_signature_set_expiration_time(sig, expires2));
+ assert_rnp_success(rnp_op_sign_signature_set_hash(sig, "SHA512"));
+ assert_rnp_success(rnp_key_handle_destroy(key));
+}
+
+static void
+test_ffi_check_signatures(rnp_op_verify_t *verify)
+{
+ rnp_op_verify_signature_t sig;
+ size_t sig_count;
+ uint32_t sig_create;
+ uint32_t sig_expires;
+ char * hname = NULL;
+ const uint32_t issued = 1516211899; // Unix epoch, nowish
+ const uint32_t expires = 1000000000; // expires later
+ const uint32_t issued2 = 1516211900; // Unix epoch, nowish
+ const uint32_t expires2 = 2000000000; // expires later
+
+ assert_rnp_success(rnp_op_verify_get_signature_count(*verify, &sig_count));
+ assert_int_equal(sig_count, 2);
+ // first signature
+ assert_rnp_success(rnp_op_verify_get_signature_at(*verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ assert_rnp_success(rnp_op_verify_signature_get_times(sig, &sig_create, &sig_expires));
+ assert_int_equal(sig_create, issued);
+ assert_int_equal(sig_expires, expires);
+ assert_rnp_success(rnp_op_verify_signature_get_hash(sig, &hname));
+ assert_string_equal(hname, "SHA256");
+ rnp_buffer_destroy(hname);
+ // second signature
+ assert_rnp_success(rnp_op_verify_get_signature_at(*verify, 1, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ assert_rnp_success(rnp_op_verify_signature_get_times(sig, &sig_create, &sig_expires));
+ assert_int_equal(sig_create, issued2);
+ assert_int_equal(sig_expires, expires2);
+ assert_rnp_success(rnp_op_verify_signature_get_hash(sig, &hname));
+ assert_string_equal(hname, "SHA512");
+ rnp_buffer_destroy(hname);
+}
+
+static bool
+test_ffi_check_recovered()
+{
+ pgp_source_t msrc1 = {};
+ pgp_source_t msrc2 = {};
+ bool res = false;
+
+ if (file_to_mem_src(&msrc1, "recovered")) {
+ return false;
+ }
+
+ if (file_to_mem_src(&msrc2, "plaintext")) {
+ goto finish;
+ }
+
+ res = (msrc1.size == msrc2.size) &&
+ !memcmp(mem_src_get_memory(&msrc1), mem_src_get_memory(&msrc2), msrc1.size);
+finish:
+ src_close(&msrc1);
+ src_close(&msrc2);
+ return res;
+}
+
+TEST_F(rnp_tests, test_ffi_signatures_memory)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ rnp_op_verify_t verify;
+ uint8_t * signed_buf;
+ size_t signed_len;
+ uint8_t * verified_buf;
+ size_t verified_len;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init input
+ test_ffi_init_sign_memory_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_rnp_failure(rnp_output_memory_get_buf(NULL, &signed_buf, &signed_len, true));
+ assert_rnp_failure(rnp_output_memory_get_buf(output, NULL, &signed_len, true));
+ assert_rnp_failure(rnp_output_memory_get_buf(output, &signed_buf, NULL, true));
+ assert_rnp_success(rnp_output_memory_get_buf(output, &signed_buf, &signed_len, true));
+ assert_non_null(signed_buf);
+ assert_true(signed_len > 0);
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ op = NULL;
+
+ /* now verify */
+ // make sure it is correctly armored
+ assert_int_equal(memcmp(signed_buf, "-----BEGIN PGP MESSAGE-----", 27), 0);
+ // create input and output
+ test_ffi_init_verify_memory_input(&input, &output, signed_buf, signed_len);
+ // call verify
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ test_ffi_check_signatures(&verify);
+ // get output
+ assert_rnp_success(rnp_output_memory_get_buf(output, &verified_buf, &verified_len, true));
+ assert_non_null(verified_buf);
+ assert_true(verified_len > 0);
+ // cleanup
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+ rnp_buffer_destroy(signed_buf);
+ rnp_buffer_destroy(verified_buf);
+}
+
+TEST_F(rnp_tests, test_ffi_signatures)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ rnp_op_verify_t verify;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init file input
+ test_ffi_init_sign_file_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_true(rnp_file_exists("signed"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ op = NULL;
+
+ /* now verify */
+
+ // create input and output
+ test_ffi_init_verify_file_input(&input, &output);
+ // call verify
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ test_ffi_check_signatures(&verify);
+ // cleanup
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+ // check output
+ assert_true(test_ffi_check_recovered());
+}
+
+TEST_F(rnp_tests, test_ffi_signatures_detached_memory)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_input_t signature = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ rnp_op_verify_t verify;
+ uint8_t * signed_buf;
+ size_t signed_len;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init input
+ test_ffi_init_sign_memory_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_detached_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ assert_rnp_success(rnp_output_memory_get_buf(output, &signed_buf, &signed_len, true));
+ assert_non_null(signed_buf);
+ assert_true(signed_len > 0);
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ op = NULL;
+
+ /* now verify */
+ // make sure it is correctly armored
+ assert_int_equal(memcmp(signed_buf, "-----BEGIN PGP SIGNATURE-----", 29), 0);
+ // create input and output
+ test_ffi_init_sign_memory_input(&input, NULL);
+ assert_rnp_success(rnp_input_from_memory(&signature, signed_buf, signed_len, true));
+ assert_non_null(signature);
+ // call verify
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ test_ffi_check_signatures(&verify);
+ // cleanup
+ rnp_buffer_destroy(signed_buf);
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_input_destroy(signature));
+ signature = NULL;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+TEST_F(rnp_tests, test_ffi_signatures_detached)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_input_t signature = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ rnp_op_verify_t verify;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init file input
+ test_ffi_init_sign_file_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_detached_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_true(rnp_file_exists("signed"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ op = NULL;
+
+ /* now verify */
+
+ // create input and output
+ test_ffi_init_verify_detached_file_input(&input, &signature);
+ // call verify
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ test_ffi_check_signatures(&verify);
+ // cleanup
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_input_destroy(signature));
+ signature = NULL;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+TEST_F(rnp_tests, test_ffi_signatures_dump)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_input_t signature = NULL;
+ rnp_op_verify_t verify;
+
+ /* init ffi and inputs */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ load_keys_gpg(ffi, "data/test_stream_signatures/pub.asc");
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_signatures/source.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&signature, "data/test_stream_signatures/source.txt.sig"));
+ /* call verify detached to obtain signatures */
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* get signature and check it */
+ rnp_op_verify_signature_t sig;
+ size_t sig_count;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 1);
+ /* get signature handle */
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ rnp_signature_handle_t sighandle = NULL;
+ assert_rnp_success(rnp_op_verify_signature_get_handle(sig, &sighandle));
+ assert_non_null(sighandle);
+ /* check signature type */
+ char *sigtype = NULL;
+ assert_rnp_success(rnp_signature_get_type(sighandle, &sigtype));
+ assert_string_equal(sigtype, "binary");
+ rnp_buffer_destroy(sigtype);
+ /* attempt to validate it via wrong function */
+ assert_int_equal(rnp_signature_is_valid(sighandle, 0), RNP_ERROR_BAD_PARAMETERS);
+ /* cleanup, making sure that sighandle doesn't depend on verify */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_input_destroy(signature));
+ /* check whether getters work on sighandle: algorithm */
+ char *alg = NULL;
+ assert_rnp_success(rnp_signature_get_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ /* keyid */
+ char *keyid = NULL;
+ assert_rnp_success(rnp_signature_get_keyid(sighandle, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "5873BD738E575398");
+ rnp_buffer_destroy(keyid);
+ /* creation time */
+ uint32_t create = 0;
+ assert_rnp_success(rnp_signature_get_creation(sighandle, &create));
+ assert_int_equal(create, 1522241943);
+ /* hash algorithm */
+ assert_rnp_success(rnp_signature_get_hash_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "SHA256");
+ rnp_buffer_destroy(alg);
+ /* now dump signature packet to json */
+ char *json = NULL;
+ assert_rnp_success(rnp_signature_packet_to_json(sighandle, 0, &json));
+ json_object *jso = json_tokener_parse(json);
+ rnp_buffer_destroy(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ assert_int_equal(json_object_array_length(jso), 1);
+ /* check the signature packet dump */
+ json_object *pkt = json_object_array_get_idx(jso, 0);
+ /* check helper functions */
+ assert_false(check_json_field_int(pkt, "unknown", 4));
+ assert_false(check_json_field_int(pkt, "version", 5));
+ assert_true(check_json_field_int(pkt, "version", 4));
+ assert_true(check_json_field_int(pkt, "type", 0));
+ assert_true(check_json_field_str(pkt, "type.str", "Signature of a binary document"));
+ assert_true(check_json_field_int(pkt, "algorithm", 1));
+ assert_true(check_json_field_str(pkt, "algorithm.str", "RSA (Encrypt or Sign)"));
+ assert_true(check_json_field_int(pkt, "hash algorithm", 8));
+ assert_true(check_json_field_str(pkt, "hash algorithm.str", "SHA256"));
+ assert_true(check_json_field_str(pkt, "lbits", "816e"));
+ json_object *subpkts = NULL;
+ assert_true(json_object_object_get_ex(pkt, "subpackets", &subpkts));
+ assert_non_null(subpkts);
+ assert_true(json_object_is_type(subpkts, json_type_array));
+ assert_int_equal(json_object_array_length(subpkts), 3);
+ /* subpacket 0 */
+ json_object *subpkt = json_object_array_get_idx(subpkts, 0);
+ assert_true(check_json_field_int(subpkt, "type", 33));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer fingerprint"));
+ assert_true(check_json_field_int(subpkt, "length", 21));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(
+ check_json_field_str(subpkt, "fingerprint", "7a60e671179f9b920f6478a25873bd738e575398"));
+ /* subpacket 1 */
+ subpkt = json_object_array_get_idx(subpkts, 1);
+ assert_true(check_json_field_int(subpkt, "type", 2));
+ assert_true(check_json_field_str(subpkt, "type.str", "signature creation time"));
+ assert_true(check_json_field_int(subpkt, "length", 4));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(check_json_field_int(subpkt, "creation time", 1522241943));
+ /* subpacket 2 */
+ subpkt = json_object_array_get_idx(subpkts, 2);
+ assert_true(check_json_field_int(subpkt, "type", 16));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer key ID"));
+ assert_true(check_json_field_int(subpkt, "length", 8));
+ assert_true(check_json_field_bool(subpkt, "hashed", false));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(check_json_field_str(subpkt, "issuer keyid", "5873bd738e575398"));
+ json_object_put(jso);
+ rnp_signature_handle_destroy(sighandle);
+ /* check text-mode detached signature */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_signatures/source.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&signature, "data/test_stream_signatures/source.txt.text.sig"));
+ /* call verify detached to obtain signatures */
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* get signature and check it */
+ sig_count = 0;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 1);
+ /* get signature handle */
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ assert_rnp_success(rnp_op_verify_signature_get_handle(sig, &sighandle));
+ assert_non_null(sighandle);
+ /* check signature type */
+ assert_rnp_success(rnp_signature_get_type(sighandle, &sigtype));
+ assert_string_equal(sigtype, "text");
+ rnp_buffer_destroy(sigtype);
+ /* attempt to validate it via wrong function */
+ assert_int_equal(rnp_signature_is_valid(sighandle, 0), RNP_ERROR_BAD_PARAMETERS);
+ /* cleanup, making sure that sighandle doesn't depend on verify */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_input_destroy(signature));
+ /* check whether getters work on sighandle: algorithm */
+ assert_rnp_success(rnp_signature_get_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ /* keyid */
+ assert_rnp_success(rnp_signature_get_keyid(sighandle, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "5873BD738E575398");
+ rnp_buffer_destroy(keyid);
+ /* creation time */
+ assert_rnp_success(rnp_signature_get_creation(sighandle, &create));
+ assert_int_equal(create, 1608118321);
+ /* hash algorithm */
+ assert_rnp_success(rnp_signature_get_hash_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "SHA256");
+ rnp_buffer_destroy(alg);
+ /* now dump signature packet to json */
+ assert_rnp_success(rnp_signature_packet_to_json(sighandle, 0, &json));
+ jso = json_tokener_parse(json);
+ rnp_buffer_destroy(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ assert_int_equal(json_object_array_length(jso), 1);
+ /* check the signature packet dump */
+ pkt = json_object_array_get_idx(jso, 0);
+ /* check helper functions */
+ assert_false(check_json_field_int(pkt, "unknown", 4));
+ assert_false(check_json_field_int(pkt, "version", 5));
+ assert_true(check_json_field_int(pkt, "version", 4));
+ assert_true(check_json_field_int(pkt, "type", 1));
+ assert_true(
+ check_json_field_str(pkt, "type.str", "Signature of a canonical text document"));
+ assert_true(check_json_field_int(pkt, "algorithm", 1));
+ assert_true(check_json_field_str(pkt, "algorithm.str", "RSA (Encrypt or Sign)"));
+ assert_true(check_json_field_int(pkt, "hash algorithm", 8));
+ assert_true(check_json_field_str(pkt, "hash algorithm.str", "SHA256"));
+ assert_true(check_json_field_str(pkt, "lbits", "1037"));
+ subpkts = NULL;
+ assert_true(json_object_object_get_ex(pkt, "subpackets", &subpkts));
+ assert_non_null(subpkts);
+ assert_true(json_object_is_type(subpkts, json_type_array));
+ assert_int_equal(json_object_array_length(subpkts), 3);
+ /* subpacket 0 */
+ subpkt = json_object_array_get_idx(subpkts, 0);
+ assert_true(check_json_field_int(subpkt, "type", 33));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer fingerprint"));
+ assert_true(check_json_field_int(subpkt, "length", 21));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(
+ check_json_field_str(subpkt, "fingerprint", "7a60e671179f9b920f6478a25873bd738e575398"));
+ /* subpacket 1 */
+ subpkt = json_object_array_get_idx(subpkts, 1);
+ assert_true(check_json_field_int(subpkt, "type", 2));
+ assert_true(check_json_field_str(subpkt, "type.str", "signature creation time"));
+ assert_true(check_json_field_int(subpkt, "length", 4));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(check_json_field_int(subpkt, "creation time", 1608118321));
+ /* subpacket 2 */
+ subpkt = json_object_array_get_idx(subpkts, 2);
+ assert_true(check_json_field_int(subpkt, "type", 16));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer key ID"));
+ assert_true(check_json_field_int(subpkt, "length", 8));
+ assert_true(check_json_field_bool(subpkt, "hashed", false));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(check_json_field_str(subpkt, "issuer keyid", "5873bd738e575398"));
+ json_object_put(jso);
+ rnp_signature_handle_destroy(sighandle);
+
+ /* attempt to validate a timestamp signature instead of detached */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_signatures/source.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&signature, "data/test_stream_signatures/signature-timestamp.asc"));
+ /* call verify detached to obtain signatures */
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
+ assert_int_equal(rnp_op_verify_execute(verify), RNP_ERROR_SIGNATURE_INVALID);
+ /* get signature and check it */
+ sig_count = 0;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 1);
+ /* get signature handle */
+ 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);
+ assert_rnp_success(rnp_op_verify_signature_get_handle(sig, &sighandle));
+ assert_non_null(sighandle);
+ /* check signature type */
+ assert_rnp_success(rnp_signature_get_type(sighandle, &sigtype));
+ assert_string_equal(sigtype, "timestamp");
+ rnp_buffer_destroy(sigtype);
+ /* attempt to validate it via wrong function */
+ assert_int_equal(rnp_signature_is_valid(sighandle, 0), RNP_ERROR_BAD_PARAMETERS);
+ /* cleanup, making sure that sighandle doesn't depend on verify */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_input_destroy(signature));
+ /* check whether getters work on sighandle: algorithm */
+ assert_rnp_success(rnp_signature_get_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "DSA");
+ rnp_buffer_destroy(alg);
+ /* keyid */
+ assert_rnp_success(rnp_signature_get_keyid(sighandle, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "2D727CC768697734");
+ rnp_buffer_destroy(keyid);
+ /* creation time */
+ assert_rnp_success(rnp_signature_get_creation(sighandle, &create));
+ assert_int_equal(create, 1535389094);
+ /* hash algorithm */
+ assert_rnp_success(rnp_signature_get_hash_alg(sighandle, &alg));
+ assert_non_null(alg);
+ assert_string_equal(alg, "SHA512");
+ rnp_buffer_destroy(alg);
+ /* now dump signature packet to json */
+ assert_rnp_success(rnp_signature_packet_to_json(sighandle, 0, &json));
+ jso = json_tokener_parse(json);
+ rnp_buffer_destroy(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ assert_int_equal(json_object_array_length(jso), 1);
+ /* check the signature packet dump */
+ pkt = json_object_array_get_idx(jso, 0);
+ /* check helper functions */
+ assert_false(check_json_field_int(pkt, "unknown", 4));
+ assert_false(check_json_field_int(pkt, "version", 5));
+ assert_true(check_json_field_int(pkt, "version", 4));
+ assert_true(check_json_field_int(pkt, "type", 0x40));
+ assert_true(check_json_field_str(pkt, "type.str", "Timestamp signature"));
+ assert_true(check_json_field_int(pkt, "algorithm", 17));
+ assert_true(check_json_field_str(pkt, "algorithm.str", "DSA"));
+ assert_true(check_json_field_int(pkt, "hash algorithm", 10));
+ assert_true(check_json_field_str(pkt, "hash algorithm.str", "SHA512"));
+ assert_true(check_json_field_str(pkt, "lbits", "2727"));
+ subpkts = NULL;
+ assert_true(json_object_object_get_ex(pkt, "subpackets", &subpkts));
+ assert_non_null(subpkts);
+ assert_true(json_object_is_type(subpkts, json_type_array));
+ assert_int_equal(json_object_array_length(subpkts), 7);
+ /* subpacket 0 */
+ subpkt = json_object_array_get_idx(subpkts, 0);
+ assert_true(check_json_field_int(subpkt, "type", 2));
+ assert_true(check_json_field_str(subpkt, "type.str", "signature creation time"));
+ assert_true(check_json_field_int(subpkt, "length", 4));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", true));
+ assert_true(check_json_field_int(subpkt, "creation time", 1535389094));
+ /* subpacket 1 */
+ subpkt = json_object_array_get_idx(subpkts, 1);
+ assert_true(check_json_field_int(subpkt, "type", 7));
+ assert_true(check_json_field_str(subpkt, "type.str", "revocable"));
+ assert_true(check_json_field_int(subpkt, "length", 1));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", true));
+ assert_true(check_json_field_bool(subpkt, "revocable", false));
+ /* subpacket 2 */
+ subpkt = json_object_array_get_idx(subpkts, 2);
+ assert_true(check_json_field_int(subpkt, "type", 16));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer key ID"));
+ assert_true(check_json_field_int(subpkt, "length", 8));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", true));
+ assert_true(check_json_field_str(subpkt, "issuer keyid", "2d727cc768697734"));
+ /* subpacket 3 */
+ subpkt = json_object_array_get_idx(subpkts, 3);
+ assert_true(check_json_field_int(subpkt, "type", 20));
+ assert_true(check_json_field_str(subpkt, "type.str", "notation data"));
+ assert_true(check_json_field_int(subpkt, "length", 51));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(check_json_field_bool(subpkt, "human", true));
+ assert_true(check_json_field_str(subpkt, "name", "serialnumber@dots.testdomain.test"));
+ assert_true(check_json_field_str(subpkt, "value", "TEST000001"));
+ /* subpacket 4 */
+ subpkt = json_object_array_get_idx(subpkts, 4);
+ assert_true(check_json_field_int(subpkt, "type", 26));
+ assert_true(check_json_field_str(subpkt, "type.str", "policy URI"));
+ assert_true(check_json_field_int(subpkt, "length", 44));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(
+ check_json_field_str(subpkt, "uri", "https://policy.testdomain.test/timestamping/"));
+ /* subpacket 5 */
+ subpkt = json_object_array_get_idx(subpkts, 5);
+ assert_true(check_json_field_int(subpkt, "type", 32));
+ assert_true(check_json_field_str(subpkt, "type.str", "embedded signature"));
+ assert_true(check_json_field_int(subpkt, "length", 105));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", true));
+ json_object *embsig = NULL;
+ assert_true(json_object_object_get_ex(subpkt, "signature", &embsig));
+ assert_true(check_json_field_int(embsig, "version", 4));
+ assert_true(check_json_field_int(embsig, "type", 0));
+ assert_true(check_json_field_str(embsig, "type.str", "Signature of a binary document"));
+ assert_true(check_json_field_int(embsig, "algorithm", 17));
+ assert_true(check_json_field_str(embsig, "algorithm.str", "DSA"));
+ assert_true(check_json_field_int(embsig, "hash algorithm", 10));
+ assert_true(check_json_field_str(embsig, "hash algorithm.str", "SHA512"));
+ assert_true(check_json_field_str(embsig, "lbits", "a386"));
+ /* subpacket 6 */
+ subpkt = json_object_array_get_idx(subpkts, 6);
+ assert_true(check_json_field_int(subpkt, "type", 33));
+ assert_true(check_json_field_str(subpkt, "type.str", "issuer fingerprint"));
+ assert_true(check_json_field_int(subpkt, "length", 21));
+ assert_true(check_json_field_bool(subpkt, "hashed", true));
+ assert_true(check_json_field_bool(subpkt, "critical", false));
+ assert_true(
+ check_json_field_str(subpkt, "fingerprint", "a0ff4590bb6122edef6e3c542d727cc768697734"));
+ json_object_put(jso);
+ rnp_signature_handle_destroy(sighandle);
+
+ /* cleanup ffi */
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+TEST_F(rnp_tests, test_ffi_locate_key)
+{
+ rnp_ffi_t ffi = NULL;
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load our keyrings
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg"));
+
+ // keyid
+ {
+ static const char *ids[] = {"7BC6709B15C23A4A",
+ "1ED63EE56FADC34D",
+ "1D7E8A5393C997A8",
+ "8A05B89FAD5ADED1",
+ "2FCADF05FFA501BB",
+ "54505A936A4A970E",
+ "326EF111425D14A5"};
+ for (size_t i = 0; i < ARRAY_SIZE(ids); i++) {
+ const char * id = ids[i];
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", id, &key));
+ assert_non_null(key);
+ rnp_key_handle_destroy(key);
+ }
+ // invalid - value did not change
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_failure(rnp_locate_key(ffi, "keyid", "invalid-keyid", &key));
+ assert_true(key == (rnp_key_handle_t) 0x111);
+ }
+ // valid but non-existent - null returned
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "AAAAAAAAAAAAAAAA", &key));
+ assert_null(key);
+ }
+ }
+
+ // userid
+ {
+ static const char *ids[] = {
+ "key0-uid0", "key0-uid1", "key0-uid2", "key1-uid0", "key1-uid2", "key1-uid1"};
+ for (size_t i = 0; i < ARRAY_SIZE(ids); i++) {
+ const char * id = ids[i];
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", id, &key));
+ assert_non_null(key);
+ rnp_key_handle_destroy(key);
+ }
+ // valid but non-existent
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "bad-userid", &key));
+ assert_null(key);
+ }
+ }
+
+ // fingerprint
+ {
+ static const char *ids[] = {"E95A3CBF583AA80A2CCC53AA7BC6709B15C23A4A",
+ "E332B27CAF4742A11BAA677F1ED63EE56FADC34D",
+ "C5B15209940A7816A7AF3FB51D7E8A5393C997A8",
+ "5CD46D2A0BD0B8CFE0B130AE8A05B89FAD5ADED1",
+ "BE1C4AB951F4C2F6B604C7F82FCADF05FFA501BB",
+ "A3E94DE61A8CB229413D348E54505A936A4A970E",
+ "57F8ED6E5C197DB63C60FFAF326EF111425D14A5"};
+ for (size_t i = 0; i < ARRAY_SIZE(ids); i++) {
+ const char * id = ids[i];
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "fingerprint", id, &key));
+ assert_non_null(key);
+ rnp_key_handle_destroy(key);
+ }
+ // invalid
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_failure(rnp_locate_key(ffi, "fingerprint", "invalid-fpr", &key));
+ assert_true(key == (rnp_key_handle_t) 0x111);
+ }
+ // valid but non-existent
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_success(rnp_locate_key(
+ ffi, "fingerprint", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", &key));
+ assert_null(key);
+ }
+ }
+
+ // grip
+ {
+ static const char *ids[] = {"66D6A0800A3FACDE0C0EB60B16B3669ED380FDFA",
+ "D9839D61EDAF0B3974E0A4A341D6E95F3479B9B7",
+ "B1CC352FEF9A6BD4E885B5351840EF9306D635F0",
+ "E7C8860B70DC727BED6DB64C633683B41221BB40",
+ "B2A7F6C34AA2C15484783E9380671869A977A187",
+ "43C01D6D96BE98C3C87FE0F175870ED92DE7BE45",
+ "8082FE753013923972632550838A5F13D81F43B9"};
+ for (size_t i = 0; i < ARRAY_SIZE(ids); i++) {
+ const char * id = ids[i];
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "grip", id, &key));
+ assert_non_null(key);
+ rnp_key_handle_destroy(key);
+ }
+ // invalid
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_failure(rnp_locate_key(ffi, "grip", "invalid-fpr", &key));
+ assert_true(key == (rnp_key_handle_t) 0x111);
+ }
+ // valid but non-existent
+ {
+ rnp_key_handle_t key = (rnp_key_handle_t) 0x111;
+ assert_rnp_success(
+ rnp_locate_key(ffi, "grip", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", &key));
+ assert_null(key);
+ }
+ }
+
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_signatures_detached_memory_g10)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_input_t input_sig = NULL;
+ rnp_output_t output = NULL;
+ rnp_key_handle_t key = NULL;
+ rnp_op_sign_t opsign = NULL;
+ rnp_op_verify_t opverify = NULL;
+ const char * data = "my data";
+ uint8_t * sig = NULL;
+ size_t sig_len = 0;
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "KBX", "G10"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ // load our keyrings
+ assert_true(load_keys_kbx_g10(
+ ffi, "data/keyrings/3/pubring.kbx", "data/keyrings/3/private-keys-v1.d"));
+
+ // find our signing key
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "4BE147BB22DF1E60", &key));
+ assert_non_null(key);
+
+ // create our input
+ assert_rnp_success(rnp_input_from_memory(&input, (uint8_t *) data, strlen(data), false));
+ assert_non_null(input);
+ // create our output
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_non_null(output);
+ // create the signing operation
+ assert_rnp_success(rnp_op_sign_detached_create(&opsign, ffi, input, output));
+ assert_non_null(opsign);
+
+ // add the signer
+ assert_rnp_success(rnp_op_sign_add_signature(opsign, key, NULL));
+ // execute the signing operation
+ assert_rnp_success(rnp_op_sign_execute(opsign));
+ // get the resulting signature
+ assert_rnp_success(rnp_output_memory_get_buf(output, &sig, &sig_len, true));
+ assert_non_null(sig);
+ assert_int_not_equal(0, sig_len);
+ // cleanup
+ rnp_op_sign_destroy(opsign);
+ opsign = NULL;
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // verify
+ // create our data input
+ assert_rnp_success(rnp_input_from_memory(&input, (uint8_t *) data, strlen(data), false));
+ assert_non_null(input);
+ // create our signature input
+ assert_rnp_success(rnp_input_from_memory(&input_sig, sig, sig_len, true));
+ assert_non_null(input_sig);
+ // create our operation
+ assert_rnp_success(rnp_op_verify_detached_create(&opverify, ffi, input, input_sig));
+ assert_non_null(opverify);
+ // execute the verification
+ assert_rnp_success(rnp_op_verify_execute(opverify));
+ // cleanup
+ rnp_op_verify_destroy(opverify);
+ opverify = NULL;
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_input_destroy(input_sig);
+ input_sig = NULL;
+
+ // verify (tamper with signature)
+ // create our data input
+ assert_rnp_success(rnp_input_from_memory(&input, (uint8_t *) data, strlen(data), false));
+ assert_non_null(input);
+ // create our signature input
+ sig[sig_len - 5] ^= 0xff;
+ assert_rnp_success(rnp_input_from_memory(&input_sig, sig, sig_len, true));
+ assert_non_null(input_sig);
+ // create our operation
+ assert_rnp_success(rnp_op_verify_detached_create(&opverify, ffi, input, input_sig));
+ assert_non_null(opverify);
+ // execute the verification
+ assert_rnp_failure(rnp_op_verify_execute(opverify));
+ // cleanup
+ rnp_op_verify_destroy(opverify);
+ opverify = NULL;
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_input_destroy(input_sig);
+ input_sig = NULL;
+
+ // cleanup
+ rnp_buffer_destroy(sig);
+ rnp_key_handle_destroy(key);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_enarmor_dearmor)
+{
+ std::string data;
+
+ // enarmor plain message
+ const std::string msg("this is a test");
+ data.clear();
+ {
+ uint8_t * buf = NULL;
+ size_t buf_size = 0;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) msg.data(), msg.size(), true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ assert_rnp_success(rnp_enarmor(input, output, "message"));
+
+ rnp_output_memory_get_buf(output, &buf, &buf_size, false);
+ data = std::string(buf, buf + buf_size);
+ assert_true(starts_with(data, "-----BEGIN PGP MESSAGE-----\r\n"));
+ assert_true(ends_with(data, "-----END PGP MESSAGE-----\r\n"));
+
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+ {
+ uint8_t * buf = NULL;
+ size_t buf_size = 0;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) data.data(), data.size(), true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ assert_rnp_success(rnp_dearmor(input, output));
+
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_size, false));
+ std::string dearmored(buf, buf + buf_size);
+ assert_true(msg == dearmored);
+
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+
+ // enarmor public key
+ data.clear();
+ {
+ uint8_t * buf = NULL;
+ size_t buf_size = 0;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // enarmor
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ assert_rnp_success(rnp_enarmor(input, output, NULL));
+
+ rnp_output_memory_get_buf(output, &buf, &buf_size, false);
+ data = std::string(buf, buf + buf_size);
+ assert_true(starts_with(data, "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n"));
+ assert_true(ends_with(data, "-----END PGP PUBLIC KEY BLOCK-----\r\n"));
+
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+ // dearmor public key
+ {
+ uint8_t * buf = NULL;
+ size_t buf_size = 0;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) data.data(), data.size(), true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ assert_rnp_success(rnp_dearmor(input, output));
+
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_size, false));
+ std::string dearmored(buf, buf + buf_size);
+ std::ifstream inf("data/keyrings/1/pubring.gpg", std::ios::binary | std::ios::ate);
+ std::string from_disk(inf.tellg(), ' ');
+ inf.seekg(0);
+ inf.read(&from_disk[0], from_disk.size());
+ inf.close();
+ assert_true(dearmored == from_disk);
+
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+ // test truncated armored data
+ {
+ std::ifstream keyf("data/test_stream_key_load/rsa-rsa-pub.asc",
+ std::ios::binary | std::ios::ate);
+ std::string keystr(keyf.tellg(), ' ');
+ keyf.seekg(0);
+ keyf.read(&keystr[0], keystr.size());
+ keyf.close();
+ for (size_t sz = keystr.size() - 2; sz > 0; sz--) {
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) keystr.data(), sz, true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_dearmor_edge_cases)
+{
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/long_header_line.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/empty_header_line.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(rnp_input_from_path(
+ &input, "data/test_stream_armor/64k_whitespace_before_armored_message.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* Armor header starts and fits in the first 1024 bytes of the input. Prepended by
+ * whitespaces. */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/1024_peek_buf.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/blank_line_with_whitespace.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/duplicate_header_line.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/long_header_line_1024.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/long_header_line_64k.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/long_header_nameline_64k.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* Armored message encoded in a single >64k text line */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/message_64k_oneline.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 68647);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_header_line.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* invalid, > 127 (negative char), preceding the armor header - just warning */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_header.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dearmor(input, output));
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 2226);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* invalid, > 127, base64 chars at positions 1..4 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_base64_1.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_base64_2.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_base64_3.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_base64_4.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* invalid, > 127 base64 char in the crc */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_chars_crc.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* too short armor header */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/too_short_header.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* wrong base64 padding */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_armor/wrong_b64_trailer.asc"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_failure(rnp_dearmor(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+}
+
+TEST_F(rnp_tests, test_ffi_customized_enarmor)
+{
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_output_t armor_layer = NULL;
+ const std::string msg("this is a test long enough to have more than 76 characters in "
+ "enarmored representation");
+ std::set<std::string> lines_to_skip{"-----BEGIN PGP MESSAGE-----",
+ "-----END PGP MESSAGE-----"};
+
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "message"));
+ // should fail when trying to set line length on non-armor output
+ assert_rnp_failure(rnp_output_armor_set_line_length(output, 64));
+ // should fail when trying to set zero line length
+ assert_rnp_failure(rnp_output_armor_set_line_length(armor_layer, 0));
+ // should fail when trying to set line length less than the minimum allowed 16
+ assert_rnp_failure(rnp_output_armor_set_line_length(armor_layer, 15));
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, 16));
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, 76));
+ // should fail when trying to set line length greater than the maximum allowed 76
+ assert_rnp_failure(rnp_output_armor_set_line_length(armor_layer, 77));
+ assert_rnp_success(rnp_output_destroy(armor_layer));
+ assert_rnp_success(rnp_output_destroy(output));
+
+ for (size_t llen = 16; llen <= 76; llen++) {
+ std::string data;
+ uint8_t * buf = NULL;
+ size_t buf_size = 0;
+
+ input = NULL;
+ output = NULL;
+ armor_layer = NULL;
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) msg.data(), msg.size(), true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "message"));
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, llen));
+ assert_rnp_success(rnp_output_pipe(input, armor_layer));
+ assert_rnp_success(rnp_output_finish(armor_layer));
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_size, false));
+ data = std::string(buf, buf + buf_size);
+ auto effective_llen = get_longest_line_length(data, lines_to_skip);
+ assert_int_equal(llen / 4, effective_llen / 4);
+ assert_true(llen >= effective_llen);
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(armor_layer));
+ assert_rnp_success(rnp_output_destroy(output));
+
+ // test that the dearmored message is correct
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) data.data(), data.size(), true));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ assert_rnp_success(rnp_dearmor(input, output));
+
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_size, false));
+ std::string dearmored(buf, buf + buf_size);
+ assert_true(msg == dearmored);
+
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_version)
+{
+ const uint32_t version = rnp_version();
+ const uint32_t major = rnp_version_major(version);
+ const uint32_t minor = rnp_version_minor(version);
+ const uint32_t patch = rnp_version_patch(version);
+
+ // reconstruct the version string
+ assert_string_equal(fmt("%d.%d.%d", major, minor, patch).c_str(), rnp_version_string());
+
+ // full version string should probably be at least as long as regular version string
+ assert_true(strlen(rnp_version_string_full()) >= strlen(rnp_version_string()));
+
+ // reconstruct the version value
+ assert_int_equal(version, rnp_version_for(major, minor, patch));
+
+ // check out-of-range handling
+ assert_int_equal(0, rnp_version_for(1024, 0, 0));
+ assert_int_equal(0, rnp_version_for(0, 1024, 0));
+ assert_int_equal(0, rnp_version_for(0, 0, 1024));
+
+ // check component extraction again
+ assert_int_equal(rnp_version_major(rnp_version_for(5, 4, 3)), 5);
+ assert_int_equal(rnp_version_minor(rnp_version_for(5, 4, 3)), 4);
+ assert_int_equal(rnp_version_patch(rnp_version_for(5, 4, 3)), 3);
+
+ // simple comparisons
+ assert_true(rnp_version_for(1, 0, 1) > rnp_version_for(1, 0, 0));
+ assert_true(rnp_version_for(1, 1, 0) > rnp_version_for(1, 0, 1023));
+ assert_true(rnp_version_for(2, 0, 0) > rnp_version_for(1, 1023, 1023));
+
+ // commit timestamp
+ const uint64_t timestamp = rnp_version_commit_timestamp();
+ assert_true(!timestamp || (timestamp >= 1639439116));
+}
+
+TEST_F(rnp_tests, test_ffi_backend_version)
+{
+ assert_non_null(rnp_backend_string());
+ assert_non_null(rnp_backend_version());
+
+ assert_true(strlen(rnp_backend_string()) > 0 && strlen(rnp_backend_string()) < 255);
+ assert_true(strlen(rnp_backend_version()) > 0 && strlen(rnp_backend_version()) < 255);
+}
+
+void check_loaded_keys(const char * format,
+ bool armored,
+ uint8_t * buf,
+ size_t buf_len,
+ const char * id_type,
+ const std::vector<std::string> &expected_ids,
+ bool secret);
+
+TEST_F(rnp_tests, test_ffi_key_export_customized_enarmor)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_output_t output = NULL;
+ rnp_output_t armor_layer = NULL;
+ rnp_key_handle_t key = NULL;
+ uint8_t * buf = NULL;
+ size_t buf_len = 0;
+ std::set<std::string> lines_to_skip{"-----BEGIN PGP PUBLIC KEY BLOCK-----",
+ "-----END PGP PUBLIC KEY BLOCK-----",
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----",
+ "-----END PGP PRIVATE KEY BLOCK-----"};
+ // setup FFI
+ test_ffi_init(&ffi);
+
+ for (size_t llen = 16; llen <= 76; llen++) {
+ // 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);
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "public key"));
+ assert_non_null(armor_layer);
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, llen));
+
+ // export
+ assert_rnp_success(rnp_key_export(key, armor_layer, RNP_KEY_EXPORT_PUBLIC));
+ assert_rnp_success(rnp_output_finish(armor_layer));
+ // get output
+ buf = NULL;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
+ assert_non_null(buf);
+ std::string data = std::string(buf, buf + buf_len);
+ auto effective_llen = get_longest_line_length(data, lines_to_skip);
+ assert_int_equal(llen / 4, effective_llen / 4);
+ assert_true(llen >= effective_llen);
+
+ // check results
+ check_loaded_keys("GPG", true, buf, buf_len, "keyid", {"2FCADF05FFA501BB"}, false);
+
+ // cleanup
+ rnp_output_destroy(armor_layer);
+ rnp_output_destroy(output);
+ rnp_key_handle_destroy(key);
+ }
+
+ // primary sec 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);
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "secret key"));
+ assert_non_null(armor_layer);
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, llen));
+
+ // export
+ assert_rnp_success(rnp_key_export(key, armor_layer, RNP_KEY_EXPORT_SECRET));
+ assert_rnp_success(rnp_output_finish(armor_layer));
+
+ // get output
+ buf = NULL;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
+ assert_non_null(buf);
+ std::string data = std::string(buf, buf + buf_len);
+ auto effective_llen = get_longest_line_length(data, lines_to_skip);
+ assert_int_equal(llen / 4, effective_llen / 4);
+ assert_true(llen >= effective_llen);
+
+ // check results
+ check_loaded_keys("GPG", true, buf, buf_len, "keyid", {"2FCADF05FFA501BB"}, true);
+
+ // cleanup
+ rnp_output_destroy(armor_layer);
+ 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);
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "public key"));
+ assert_non_null(armor_layer);
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, llen));
+
+ // export
+ assert_rnp_success(rnp_key_export(key, armor_layer, RNP_KEY_EXPORT_PUBLIC));
+ assert_rnp_success(rnp_output_finish(armor_layer));
+
+ // get output
+ buf = NULL;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
+ assert_non_null(buf);
+ std::string data = std::string(buf, buf + buf_len);
+ auto effective_llen = get_longest_line_length(data, lines_to_skip);
+ assert_int_equal(llen / 4, effective_llen / 4);
+ assert_true(llen >= effective_llen);
+
+ // check results
+ check_loaded_keys("GPG",
+ true,
+ buf,
+ buf_len,
+ "keyid",
+ {"2FCADF05FFA501BB", "54505A936A4A970E"},
+ false);
+
+ // cleanup
+ rnp_output_destroy(armor_layer);
+ 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);
+ assert_rnp_success(rnp_output_to_armor(output, &armor_layer, "secret key"));
+ assert_non_null(armor_layer);
+ assert_rnp_success(rnp_output_armor_set_line_length(armor_layer, llen));
+
+ // export
+ assert_rnp_success(rnp_key_export(key, armor_layer, RNP_KEY_EXPORT_SECRET));
+ assert_rnp_success(rnp_output_finish(armor_layer));
+
+ // get output
+ buf = NULL;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &buf_len, false));
+ assert_non_null(buf);
+ std::string data = std::string(buf, buf + buf_len);
+ auto effective_llen = get_longest_line_length(data, lines_to_skip);
+ assert_int_equal(llen / 4, effective_llen / 4);
+ assert_true(llen >= effective_llen);
+
+ // check results
+ check_loaded_keys("GPG",
+ true,
+ buf,
+ buf_len,
+ "keyid",
+ {"2FCADF05FFA501BB", "54505A936A4A970E"},
+ true);
+
+ // cleanup
+ rnp_output_destroy(armor_layer);
+ rnp_output_destroy(output);
+ rnp_key_handle_destroy(key);
+ }
+ }
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_key_dump)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_key_handle_t key = NULL;
+ char * json = NULL;
+ json_object * jso = NULL;
+
+ // setup FFI
+ test_ffi_init(&ffi);
+
+ // locate key
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
+ assert_non_null(key);
+
+ // dump public key and check results
+ assert_rnp_success(rnp_key_packets_to_json(
+ key, false, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ assert_non_null(json);
+ jso = json_tokener_parse(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ json_object_put(jso);
+ rnp_buffer_destroy(json);
+
+ // dump secret key and check results
+ assert_rnp_success(rnp_key_packets_to_json(
+ key, true, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ assert_non_null(json);
+ jso = json_tokener_parse(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ json_object_put(jso);
+ rnp_buffer_destroy(json);
+
+ // cleanup
+ rnp_key_handle_destroy(key);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_key_dump_edge_cases)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ /* secret key, stored on gpg card, with too large card serial len */
+ rnp_input_t input = NULL;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-2-card-len.pgp"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ std::string dstr(buf, buf + len);
+ assert_true(
+ dstr.find("card serial number: 0x000102030405060708090a0b0c0d0e0f (16 bytes)") !=
+ std::string::npos);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-2-card-len.pgp"));
+ char *json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ rnp_input_destroy(input);
+ dstr = json;
+ assert_true(dstr.find("\"card serial number\":\"000102030405060708090a0b0c0d0e0f\"") !=
+ std::string::npos);
+ rnp_buffer_destroy(json);
+
+ /* secret key, stored with unknown gpg s2k */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-3.pgp"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ dstr = std::string(buf, buf + len);
+ assert_true(dstr.find("Unknown experimental s2k: 0x474e5503 (4 bytes)") !=
+ std::string::npos);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-3.pgp"));
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ rnp_input_destroy(input);
+ dstr = json;
+ assert_true(dstr.find("\"unknown experimental\":\"474e5503\"") != std::string::npos);
+ rnp_buffer_destroy(json);
+
+ /* secret key, stored with unknown s2k */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-unknown.pgp"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ dstr = std::string(buf, buf + len);
+ assert_true(dstr.find("Unknown experimental s2k: 0x554e4b4e (4 bytes)") !=
+ std::string::npos);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/alice-s2k-101-unknown.pgp"));
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ rnp_input_destroy(input);
+ dstr = json;
+ assert_true(dstr.find("\"unknown experimental\":\"554e4b4e\"") != std::string::npos);
+ rnp_buffer_destroy(json);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_key_userid_dump_has_no_special_chars)
+{
+ rnp_ffi_t ffi = NULL;
+ char * json = NULL;
+ json_object *jso = NULL;
+ const char * trackers[] = {
+ "userid\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f@rnp",
+ "userid\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f@rnp"};
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ for (int i = 0; i < 2; i++) {
+ // generate RSA key
+ 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));
+ // user id
+ assert_rnp_success(rnp_op_generate_set_userid(keygen, trackers[0]));
+ // now execute keygen operation
+ 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));
+ keygen = NULL;
+
+ // dump public key and check results
+ assert_rnp_success(rnp_key_packets_to_json(
+ key, false, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ assert_non_null(json);
+ for (char c = 1; c < 0x20; c++) {
+ if (c != '\n') {
+ assert_null(strchr(json, c));
+ }
+ }
+ jso = json_tokener_parse(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ json_object_put(jso);
+ rnp_buffer_destroy(json);
+
+ // cleanup
+ rnp_key_handle_destroy(key);
+ }
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_pkt_dump)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ char * json = NULL;
+ json_object *jso = NULL;
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ // setup input
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+
+ // try with wrong parameters
+ assert_rnp_failure(rnp_dump_packets_to_json(input, 0, NULL));
+ assert_rnp_failure(rnp_dump_packets_to_json(NULL, 0, &json));
+ assert_rnp_failure(rnp_dump_packets_to_json(input, 117, &json));
+ // dump
+ assert_rnp_success(rnp_dump_packets_to_json(
+ input, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ rnp_input_destroy(input);
+ input = NULL;
+ assert_non_null(json);
+
+ // check results
+ jso = json_tokener_parse(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ /* make sure that correct number of packets dumped */
+ assert_int_equal(json_object_array_length(jso), 35);
+ json_object_put(jso);
+ rnp_buffer_destroy(json);
+
+ // setup input and output
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ // try with wrong parameters
+ assert_rnp_failure(rnp_dump_packets_to_output(input, NULL, 0));
+ assert_rnp_failure(rnp_dump_packets_to_output(NULL, output, 0));
+ assert_rnp_failure(rnp_dump_packets_to_output(input, output, 117));
+ // dump
+ assert_rnp_success(
+ rnp_dump_packets_to_output(input, output, RNP_DUMP_MPI | RNP_DUMP_RAW | RNP_DUMP_GRIP));
+
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ /* make sure output is not cut */
+ assert_true(len > 45000);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ // dump data with marker packet
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.marker"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(
+ rnp_dump_packets_to_output(input, output, RNP_DUMP_MPI | RNP_DUMP_RAW | RNP_DUMP_GRIP));
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ buf[len - 1] = '\0';
+ assert_non_null(strstr((char *) buf, "contents: PGP"));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ // dump data with marker packet to json
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.marker"));
+ assert_rnp_success(rnp_dump_packets_to_json(
+ input, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ assert_non_null(strstr(json, "\"contents\":\"PGP\""));
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ // dump data with malformed marker packet
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.marker.malf"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(
+ rnp_dump_packets_to_output(input, output, RNP_DUMP_MPI | RNP_DUMP_RAW | RNP_DUMP_GRIP));
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ buf[len - 1] = '\0';
+ assert_non_null(strstr((char *) buf, "contents: invalid"));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ // dump data with malformed marker packet to json
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.marker.malf"));
+ assert_rnp_success(rnp_dump_packets_to_json(
+ input, RNP_JSON_DUMP_MPI | RNP_JSON_DUMP_RAW | RNP_JSON_DUMP_GRIP, &json));
+ assert_non_null(strstr(json, "\"contents\":\"invalid\""));
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_rsa_v3_dump)
+{
+ rnp_input_t input = NULL;
+ char * json = NULL;
+
+ /* dump rsav3 key to json via FFI */
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/4/rsav3-p.asc"));
+ assert_rnp_success(rnp_dump_packets_to_json(input, RNP_JSON_DUMP_GRIP, &json));
+ rnp_input_destroy(input);
+ /* parse dump */
+ json_object *jso = json_tokener_parse(json);
+ rnp_buffer_destroy(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ json_object *rsapkt = json_object_array_get_idx(jso, 0);
+ assert_non_null(rsapkt);
+ assert_true(json_object_is_type(rsapkt, json_type_object));
+ /* check algorithm string */
+ json_object *fld = NULL;
+ assert_true(json_object_object_get_ex(rsapkt, "algorithm.str", &fld));
+ assert_non_null(fld);
+ const char *str = json_object_get_string(fld);
+ assert_non_null(str);
+ assert_string_equal(str, "RSA (Encrypt or Sign)");
+ /* check fingerprint */
+ fld = NULL;
+ assert_true(json_object_object_get_ex(rsapkt, "fingerprint", &fld));
+ assert_non_null(fld);
+ str = json_object_get_string(fld);
+ assert_non_null(str);
+ assert_string_equal(str, "06a044022bb5aa7991077466aeba2ce7");
+ json_object_put(jso);
+}
+
+TEST_F(rnp_tests, test_ffi_load_userattr)
+{
+ rnp_ffi_t ffi = NULL;
+
+ // init ffi and load key
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-25519-photo-pub.asc"));
+ // check userid 0 : ecc-25519
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "cc786278981b0728", &key));
+ assert_non_null(key);
+ size_t uid_count = 0;
+ assert_rnp_success(rnp_key_get_uid_count(key, &uid_count));
+ assert_int_equal(uid_count, 2);
+ char *uid = NULL;
+ assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
+ assert_string_equal(uid, "ecc-25519");
+ rnp_buffer_destroy(uid);
+ // check userattr 1, must be text instead of binary JPEG data
+ assert_rnp_success(rnp_key_get_uid_at(key, 1, &uid));
+ assert_string_equal(uid, "(photo)");
+ rnp_buffer_destroy(uid);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_revocations)
+{
+ rnp_ffi_t ffi = NULL;
+
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load key with revoked userid
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p256-revoked-uid.asc"));
+ // check userid 0 : ecc-p256
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &key));
+ assert_non_null(key);
+ size_t uid_count = 0;
+ assert_rnp_success(rnp_key_get_uid_count(key, &uid_count));
+ assert_int_equal(uid_count, 2);
+ char *uid = NULL;
+ assert_rnp_success(rnp_key_get_uid_at(key, 0, &uid));
+ assert_string_equal(uid, "ecc-p256");
+ rnp_buffer_destroy(uid);
+ rnp_uid_handle_t uid_handle = NULL;
+ assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid_handle));
+ assert_non_null(uid_handle);
+ bool revoked = true;
+ assert_rnp_failure(rnp_uid_is_revoked(NULL, &revoked));
+ assert_rnp_failure(rnp_uid_is_revoked(uid_handle, NULL));
+ assert_rnp_success(rnp_uid_is_revoked(uid_handle, &revoked));
+ assert_false(revoked);
+ rnp_signature_handle_t sig = (rnp_signature_handle_t) 0xdeadbeef;
+ assert_rnp_failure(rnp_uid_get_revocation_signature(NULL, &sig));
+ assert_rnp_failure(rnp_uid_get_revocation_signature(uid_handle, NULL));
+ assert_rnp_success(rnp_uid_get_revocation_signature(uid_handle, &sig));
+ assert_null(sig);
+ assert_rnp_success(rnp_uid_handle_destroy(uid_handle));
+ // check userid 1: ecc-p256-revoked
+ assert_rnp_success(rnp_key_get_uid_at(key, 1, &uid));
+ assert_string_equal(uid, "ecc-p256-revoked");
+ rnp_buffer_destroy(uid);
+ assert_rnp_success(rnp_key_get_uid_handle_at(key, 1, &uid_handle));
+ assert_non_null(uid_handle);
+ assert_rnp_success(rnp_uid_is_revoked(uid_handle, &revoked));
+ assert_true(revoked);
+ assert_rnp_success(rnp_uid_get_revocation_signature(uid_handle, &sig));
+ assert_non_null(sig);
+ uint32_t creation = 0;
+ assert_rnp_success(rnp_signature_get_creation(sig, &creation));
+ assert_int_equal(creation, 1556630215);
+ assert_rnp_success(rnp_signature_handle_destroy(sig));
+ assert_rnp_success(rnp_uid_handle_destroy(uid_handle));
+ assert_rnp_success(rnp_key_handle_destroy(key));
+
+ // load key with revoked subkey
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p256-revoked-sub.asc"));
+ // key is not revoked
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &key));
+ assert_rnp_success(rnp_key_is_revoked(key, &revoked));
+ assert_false(revoked);
+ assert_rnp_failure(rnp_key_get_revocation_signature(NULL, &sig));
+ assert_rnp_failure(rnp_key_get_revocation_signature(key, NULL));
+ assert_rnp_success(rnp_key_get_revocation_signature(key, &sig));
+ assert_null(sig);
+ bool valid = false;
+ assert_rnp_success(rnp_key_is_valid(key, &valid));
+ assert_true(valid);
+ uint32_t till = 0;
+ assert_rnp_success(rnp_key_valid_till(key, &till));
+ assert_int_equal(till, 0xFFFFFFFF);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ // subkey is revoked
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "37E285E9E9851491", &key));
+ assert_rnp_success(rnp_key_is_revoked(key, &revoked));
+ assert_true(revoked);
+ char *reason = NULL;
+ assert_rnp_success(rnp_key_get_revocation_reason(key, &reason));
+ assert_string_equal(reason, "Subkey revocation test.");
+ rnp_buffer_destroy(reason);
+ assert_rnp_success(rnp_key_is_superseded(key, &revoked));
+ assert_false(revoked);
+ assert_rnp_success(rnp_key_is_compromised(key, &revoked));
+ assert_true(revoked);
+ assert_rnp_success(rnp_key_is_retired(key, &revoked));
+ assert_false(revoked);
+ assert_rnp_success(rnp_key_get_revocation_signature(key, &sig));
+ assert_non_null(sig);
+ assert_rnp_success(rnp_signature_get_creation(sig, &creation));
+ assert_int_equal(creation, 1556630749);
+ assert_rnp_success(rnp_signature_handle_destroy(sig));
+ assert_rnp_success(rnp_key_is_valid(key, &valid));
+ assert_false(valid);
+ assert_rnp_success(rnp_key_valid_till(key, &till));
+ assert_int_equal(till, 0);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+
+ // load revoked key
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p256-revoked-key.asc"));
+ // key is revoked
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &key));
+ assert_rnp_success(rnp_key_is_revoked(key, &revoked));
+ assert_true(revoked);
+ reason = NULL;
+ assert_rnp_success(rnp_key_get_revocation_reason(key, &reason));
+ assert_string_equal(reason, "Superseded key test.");
+ rnp_buffer_destroy(reason);
+ assert_rnp_success(rnp_key_is_superseded(key, &revoked));
+ assert_true(revoked);
+ assert_rnp_success(rnp_key_is_compromised(key, &revoked));
+ assert_false(revoked);
+ assert_rnp_success(rnp_key_is_retired(key, &revoked));
+ assert_false(revoked);
+ assert_rnp_success(rnp_key_get_revocation_signature(key, &sig));
+ assert_non_null(sig);
+ assert_rnp_success(rnp_signature_get_creation(sig, &creation));
+ assert_int_equal(creation, 1556799806);
+ assert_rnp_success(rnp_signature_handle_destroy(sig));
+ assert_rnp_success(rnp_key_is_valid(key, &valid));
+ assert_false(valid);
+ assert_rnp_success(rnp_key_valid_till(key, &till));
+ assert_int_equal(till, 1556799806);
+ uint64_t till64 = 0;
+ assert_rnp_success(rnp_key_valid_till64(key, &till64));
+ assert_int_equal(till64, 1556799806);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+
+ // cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+#define KEY_OUT_PATH "exported-key.asc"
+
+TEST_F(rnp_tests, test_ffi_file_output)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load two keys
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p256-pub.asc"));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p521-pub.asc"));
+
+ rnp_key_handle_t k256 = NULL;
+ rnp_key_handle_t k521 = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &k256));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p521", &k521));
+
+ rnp_output_t output = NULL;
+ // test output to path - must overwrite if exists
+ assert_rnp_success(rnp_output_to_path(&output, KEY_OUT_PATH));
+ assert_rnp_success(rnp_key_export(
+ k256, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_true(rnp_file_exists(KEY_OUT_PATH));
+ off_t sz = file_size(KEY_OUT_PATH);
+ assert_rnp_success(rnp_output_to_path(&output, KEY_OUT_PATH));
+ assert_rnp_success(rnp_key_export(
+ k521, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_true(rnp_file_exists(KEY_OUT_PATH));
+ assert_true(sz != file_size(KEY_OUT_PATH));
+ sz = file_size(KEY_OUT_PATH);
+ // test output to file - will fail without overwrite
+ assert_rnp_failure(rnp_output_to_file(&output, KEY_OUT_PATH, 0));
+ // fail with wrong flags
+ assert_rnp_failure(rnp_output_to_file(&output, KEY_OUT_PATH, 0x100));
+ // test output to random file - will succeed on creation and export but fail on finish.
+ assert_rnp_success(rnp_output_to_file(&output, KEY_OUT_PATH, RNP_OUTPUT_FILE_RANDOM));
+ assert_true(file_size(KEY_OUT_PATH) == sz);
+ assert_rnp_success(
+ rnp_key_export(k256, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_failure(rnp_output_finish(output));
+ assert_rnp_success(rnp_output_destroy(output));
+ // test output with random + overwrite - will succeed
+ assert_rnp_success(rnp_output_to_file(
+ &output, KEY_OUT_PATH, RNP_OUTPUT_FILE_RANDOM | RNP_OUTPUT_FILE_OVERWRITE));
+ assert_true(file_size(KEY_OUT_PATH) == sz);
+ assert_rnp_success(
+ rnp_key_export(k256, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_success(rnp_output_finish(output));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_true(file_size(KEY_OUT_PATH) != sz);
+ sz = file_size(KEY_OUT_PATH);
+ // test output with just overwrite - will succeed
+ assert_rnp_success(rnp_output_to_file(&output, KEY_OUT_PATH, RNP_OUTPUT_FILE_OVERWRITE));
+ assert_true(file_size(KEY_OUT_PATH) == 0);
+ assert_rnp_success(
+ rnp_key_export(k521, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_success(rnp_output_finish(output));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_true(file_size(KEY_OUT_PATH) != sz);
+ assert_int_equal(rnp_unlink(KEY_OUT_PATH), 0);
+ // cleanup
+ assert_rnp_success(rnp_key_handle_destroy(k256));
+ assert_rnp_success(rnp_key_handle_destroy(k521));
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_stdout_output)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/ecc-p256-pub.asc"));
+
+ rnp_key_handle_t k256 = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &k256));
+
+ rnp_output_t output = NULL;
+ assert_rnp_failure(rnp_output_to_stdout(NULL));
+ assert_rnp_success(rnp_output_to_stdout(&output));
+ assert_rnp_success(rnp_key_export(
+ k256, output, RNP_KEY_EXPORT_PUBLIC | RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_SUBKEYS));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_key_handle_destroy(k256));
+ rnp_ffi_destroy(ffi);
+}
+
+/* shrink the length to 1 packet
+ * set packet length type as PGP_PTAG_OLD_LEN_1 and remove one octet from length header
+ */
+static std::vector<uint8_t>
+shrink_len_2_to_1(const std::vector<uint8_t> &src)
+{
+ std::vector<uint8_t> dst = std::vector<uint8_t>();
+ dst.reserve(src.size() - 1);
+ dst.insert(dst.end(),
+ PGP_PTAG_ALWAYS_SET | (PGP_PKT_PUBLIC_KEY << PGP_PTAG_OF_CONTENT_TAG_SHIFT) |
+ PGP_PTAG_OLD_LEN_1);
+ // make sure the most significant octet of 2-octet length is actually zero
+ if (src[1] != 0) {
+ throw std::invalid_argument("src");
+ }
+ dst.insert(dst.end(), src[2]);
+ dst.insert(dst.end(), src.begin() + 3, src.end());
+ return dst;
+}
+
+/*
+ * fake a packet with len = 0xEEEE
+ */
+static std::vector<uint8_t>
+fake_len_EEEE(const std::vector<uint8_t> &src)
+{
+ std::vector<uint8_t> dst = std::vector<uint8_t>(src);
+ dst[1] = 0xEE;
+ dst[2] = 0xEE;
+ return dst;
+}
+
+/*
+ * fake a packet with len = 0x00
+ */
+static std::vector<uint8_t>
+fake_len_0(const std::vector<uint8_t> &src)
+{
+ std::vector<uint8_t> dst = shrink_len_2_to_1(src);
+ // erase subsequent octets for the packet to correspond the length
+ uint8_t old_length = dst[1];
+ dst.erase(dst.begin() + 2, dst.begin() + 2 + old_length);
+ dst[1] = 0;
+ return dst;
+}
+
+/* extend the length to 4 octets (preserving the value)
+ * set packet length type as PGP_PTAG_OLD_LEN_4 and set 4 octet length instead of 2
+ */
+static std::vector<uint8_t>
+extend_len_2_to_4(const std::vector<uint8_t> &src)
+{
+ std::vector<uint8_t> dst = std::vector<uint8_t>();
+ dst.reserve(src.size() + 2);
+ dst.insert(dst.end(), src.begin(), src.begin() + 3);
+ dst[0] &= ~PGP_PTAG_OF_LENGTH_TYPE_MASK;
+ dst[0] |= PGP_PTAG_OLD_LEN_4;
+ dst.insert(dst.begin() + 1, 2, 0);
+ dst.insert(dst.end(), src.begin() + 3, src.end());
+ return dst;
+}
+
+static bool
+import_public_keys_from_vector(std::vector<uint8_t> keyring)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_ffi_create(&ffi, "GPG", "GPG");
+ bool res = import_pub_keys(ffi, &keyring[0], keyring.size());
+ rnp_ffi_destroy(ffi);
+ return res;
+}
+
+TEST_F(rnp_tests, test_ffi_import_keys_check_pktlen)
+{
+ std::vector<uint8_t> keyring = file_to_vec("data/keyrings/2/pubring.gpg");
+ // check tag
+ // we are assuming that original key uses old format and packet length type is
+ // PGP_PTAG_OLD_LEN_2
+ assert_true(keyring.size() >= 5);
+ uint8_t expected_tag = PGP_PTAG_ALWAYS_SET |
+ (PGP_PKT_PUBLIC_KEY << PGP_PTAG_OF_CONTENT_TAG_SHIFT) |
+ PGP_PTAG_OLD_LEN_2;
+ assert_int_equal(expected_tag, 0x99);
+ assert_int_equal(keyring[0], expected_tag);
+ // original file can be loaded correctly
+ assert_true(import_public_keys_from_vector(keyring));
+ {
+ // Shrink the packet length to 1 octet
+ std::vector<uint8_t> keyring_valid_1 = shrink_len_2_to_1(keyring);
+ assert_int_equal(keyring_valid_1.size(), keyring.size() - 1);
+ assert_true(import_public_keys_from_vector(keyring_valid_1));
+ }
+ {
+ // get invalid key with length 0
+ std::vector<uint8_t> keyring_invalid_0 = fake_len_0(keyring);
+ assert_false(import_public_keys_from_vector(keyring_invalid_0));
+ }
+ {
+ // get invalid key with length 0xEEEE
+ std::vector<uint8_t> keyring_invalid_EEEE = fake_len_EEEE(keyring);
+ assert_int_equal(keyring_invalid_EEEE.size(), keyring.size());
+ assert_false(import_public_keys_from_vector(keyring_invalid_EEEE));
+ }
+ {
+ std::vector<uint8_t> keyring_len_4 = extend_len_2_to_4(keyring);
+ assert_int_equal(keyring_len_4.size(), keyring.size() + 2);
+ assert_true(import_public_keys_from_vector(keyring_len_4));
+ // get invalid key with length 0xEEEEEEEE
+ keyring_len_4[1] = 0xEE;
+ keyring_len_4[2] = 0xEE;
+ keyring_len_4[3] = 0xEE;
+ keyring_len_4[4] = 0xEE;
+ assert_false(import_public_keys_from_vector(keyring_len_4));
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_calculate_iterations)
+{
+ size_t iterations = 0;
+ assert_rnp_failure(rnp_calculate_iterations(NULL, 500, &iterations));
+ assert_rnp_failure(rnp_calculate_iterations("SHA256", 500, NULL));
+ assert_rnp_failure(rnp_calculate_iterations("WRONG", 500, &iterations));
+ assert_rnp_success(rnp_calculate_iterations("SHA256", 500, &iterations));
+ assert_true(iterations > 65536);
+}
+
+static bool
+check_features(const char *type, const char *json, size_t count)
+{
+ size_t got_count = 0;
+
+ json_object *features = json_tokener_parse(json);
+ if (!features) {
+ return false;
+ }
+ bool res = false;
+ if (!json_object_is_type(features, json_type_array)) {
+ goto done;
+ }
+ got_count = json_object_array_length(features);
+ if (got_count != count) {
+ RNP_LOG("wrong feature count for %s: expected %zu, got %zu", type, count, got_count);
+ goto done;
+ }
+ for (size_t i = 0; i < count; i++) {
+ json_object *val = json_object_array_get_idx(features, i);
+ const char * str = json_object_get_string(val);
+ bool supported = false;
+ if (!str || rnp_supports_feature(type, str, &supported) || !supported) {
+ goto done;
+ }
+ }
+
+ res = true;
+done:
+ json_object_put(features);
+ return res;
+}
+
+TEST_F(rnp_tests, test_ffi_supported_features)
+{
+ char *features = NULL;
+ /* some edge cases */
+ assert_rnp_failure(rnp_supported_features(NULL, &features));
+ assert_rnp_failure(rnp_supported_features("something", NULL));
+ assert_rnp_failure(rnp_supported_features(RNP_FEATURE_SYMM_ALG, NULL));
+ assert_rnp_failure(rnp_supported_features("something", &features));
+ /* symmetric algorithms */
+ assert_rnp_success(rnp_supported_features("Symmetric Algorithm", &features));
+ assert_non_null(features);
+ bool has_sm2 = sm2_enabled();
+ bool has_tf = twofish_enabled();
+ bool has_brainpool = brainpool_enabled();
+ bool has_idea = idea_enabled();
+ assert_true(
+ check_features(RNP_FEATURE_SYMM_ALG,
+ features,
+ 7 + has_sm2 + has_tf + has_idea + blowfish_enabled() + cast5_enabled()));
+ rnp_buffer_destroy(features);
+ bool supported = false;
+ assert_rnp_failure(rnp_supports_feature(NULL, "IDEA", &supported));
+ assert_rnp_failure(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, NULL, &supported));
+ assert_rnp_failure(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "IDEA", NULL));
+ assert_rnp_failure(rnp_supports_feature("WRONG", "IDEA", &supported));
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "IDEA", &supported));
+ assert_true(supported == has_idea);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "TRIPLEDES", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "CAST5", &supported));
+ assert_int_equal(supported, cast5_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "BLOWFISH", &supported));
+ assert_int_equal(supported, blowfish_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "AES128", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "AES192", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "AES256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "TWOFISH", &supported));
+ assert_true(supported == has_tf);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "CAMELLIA128", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "CAMELLIA192", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "CAMELLIA256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "SM4", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "idea", &supported));
+ assert_true(supported == has_idea);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "tripledes", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "cast5", &supported));
+ assert_true(supported == cast5_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "blowfish", &supported));
+ assert_true(supported == blowfish_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "aes128", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "aes192", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "aes256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "twofish", &supported));
+ assert_true(supported == has_tf);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "camellia128", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "camellia192", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "camellia256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "sm4", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_SYMM_ALG, "wrong", &supported));
+ assert_false(supported);
+ /* aead algorithms */
+ bool has_eax = aead_eax_enabled();
+ bool has_ocb = aead_ocb_enabled();
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_AEAD_ALG, &features));
+ assert_non_null(features);
+ assert_true(check_features(RNP_FEATURE_AEAD_ALG, features, 1 + has_eax + has_ocb));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_AEAD_ALG, "eax", &supported));
+ assert_true(supported == has_eax);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_AEAD_ALG, "ocb", &supported));
+ assert_true(supported == has_ocb);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_AEAD_ALG, "none", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_AEAD_ALG, "wrong", &supported));
+ assert_false(supported);
+ /* protection mode */
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_PROT_MODE, &features));
+ assert_non_null(features);
+ assert_true(check_features(RNP_FEATURE_PROT_MODE, features, 1));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PROT_MODE, "cfb", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PROT_MODE, "wrong", &supported));
+ assert_false(supported);
+ /* public key algorithm */
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_PK_ALG, &features));
+ assert_non_null(features);
+ assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "RSA", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "DSA", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "ELGAMAL", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "ECDSA", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "ECDH", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "EDDSA", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "SM2", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "rsa", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "dsa", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "elgamal", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "ecdsa", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "ecdh", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "eddsa", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "sm2", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "wrong", &supported));
+ assert_false(supported);
+ /* hash algorithm */
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_HASH_ALG, &features));
+ assert_non_null(features);
+ assert_true(
+ check_features(RNP_FEATURE_HASH_ALG, features, 8 + has_sm2 + ripemd160_enabled()));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "MD5", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA1", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "RIPEMD160", &supported));
+ assert_true(supported == ripemd160_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA384", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA512", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA224", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA3-256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SHA3-512", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "SM3", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "md5", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha1", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "ripemd160", &supported));
+ assert_true(supported == ripemd160_enabled());
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha384", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha512", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha224", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha3-256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sha3-512", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "sm3", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "wrong", &supported));
+ assert_false(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_HASH_ALG, "CRC24", &supported));
+ assert_false(supported);
+ /* compression algorithm */
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_COMP_ALG, &features));
+ assert_non_null(features);
+ assert_true(check_features(RNP_FEATURE_COMP_ALG, features, 4));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_COMP_ALG, "Uncompressed", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_COMP_ALG, "Zlib", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_COMP_ALG, "ZIP", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_COMP_ALG, "BZIP2", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_COMP_ALG, "wrong", &supported));
+ assert_false(supported);
+ /* elliptic curve */
+ assert_rnp_success(rnp_supported_features(RNP_FEATURE_CURVE, &features));
+ assert_non_null(features);
+ assert_true(check_features(RNP_FEATURE_CURVE, features, 6 + has_sm2 + 3 * has_brainpool));
+ rnp_buffer_destroy(features);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "NIST P-256", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "NIST P-384", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "NIST P-521", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "ed25519", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "curve25519", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "brainpoolP256r1", &supported));
+ assert_true(supported == has_brainpool);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "brainpoolP384r1", &supported));
+ assert_true(supported == has_brainpool);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "brainpoolP512r1", &supported));
+ assert_true(supported == has_brainpool);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "secp256k1", &supported));
+ assert_true(supported);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "SM2 P-256", &supported));
+ assert_true(supported == has_sm2);
+ assert_rnp_success(rnp_supports_feature(RNP_FEATURE_CURVE, "wrong", &supported));
+ assert_false(supported);
+}
+
+TEST_F(rnp_tests, test_ffi_output_to_armor)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_output_t memory = NULL;
+ rnp_output_t armor = NULL;
+ rnp_input_t input = NULL;
+
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg"));
+
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "2FCADF05FFA501BB", &key));
+ assert_non_null(key);
+
+ assert_rnp_success(rnp_output_to_memory(&memory, 0));
+ /* some edge cases */
+ assert_rnp_failure(rnp_output_to_armor(NULL, &armor, "message"));
+ assert_null(armor);
+ assert_rnp_failure(rnp_output_to_armor(memory, NULL, "message"));
+ assert_null(armor);
+ assert_rnp_failure(rnp_output_to_armor(memory, &armor, "wrong"));
+ assert_null(armor);
+ /* export raw key to armored stream with 'message' header */
+ assert_rnp_success(rnp_output_to_armor(memory, &armor, "message"));
+ assert_rnp_success(rnp_key_export(key, armor, RNP_KEY_EXPORT_PUBLIC));
+ assert_rnp_success(rnp_output_destroy(armor));
+ uint8_t *buf = NULL;
+ size_t buf_len = 0;
+ /* check contents to make sure it is correct armored stream */
+ assert_rnp_success(rnp_output_memory_get_buf(memory, &buf, &buf_len, false));
+ assert_non_null(buf);
+ const char *hdr = "-----BEGIN PGP MESSAGE-----";
+ assert_true(buf_len > strlen(hdr));
+ assert_int_equal(strncmp((char *) buf, hdr, strlen(hdr)), 0);
+ assert_rnp_success(rnp_input_from_memory(&input, buf, buf_len, false));
+ rnp_output_t memory2 = NULL;
+ assert_rnp_success(rnp_output_to_memory(&memory2, 0));
+ assert_rnp_success(rnp_dearmor(input, memory2));
+ rnp_output_destroy(memory2);
+ rnp_input_destroy(input);
+
+ rnp_key_handle_destroy(key);
+ rnp_output_destroy(memory);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_rnp_guess_contents)
+{
+ char * msgt = NULL;
+ rnp_input_t input = NULL;
+ assert_rnp_failure(rnp_guess_contents(NULL, &msgt));
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/issue1188/armored_revocation_signature.pgp"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_int_equal(strcmp(msgt, "signature"), 0);
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-pub.pgp"));
+ assert_rnp_failure(rnp_guess_contents(input, NULL));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "public key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_key_merge/key-pub-just-subkey-1.pgp"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "public key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-pub.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "public key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-sec.pgp"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "secret key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_merge/key-sec.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "secret key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_key_merge/key-sec-just-subkey-1.pgp"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "secret key");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_z/128mb.zip"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "message");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_z/4gb.bzip2.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "message");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_signatures/source.txt.sig"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "signature");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_signatures/source.txt.sig.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "signature");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_signatures/source.txt.asc.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "cleartext");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_signatures/source.txt"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "unknown");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.marker"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "message");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.wrong-armor.asc"));
+ assert_rnp_success(rnp_guess_contents(input, &msgt));
+ assert_string_equal(msgt, "unknown");
+ rnp_buffer_destroy(msgt);
+ rnp_input_destroy(input);
+}
+
+TEST_F(rnp_tests, test_ffi_literal_filename)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ uint8_t * signed_buf;
+ size_t signed_len;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init input
+ test_ffi_init_sign_memory_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // setup filename and modification time
+ assert_rnp_success(rnp_op_sign_set_file_name(op, "checkleak.dat"));
+ assert_rnp_success(rnp_op_sign_set_file_name(op, NULL));
+ assert_rnp_success(rnp_op_sign_set_file_name(op, "testfile.dat"));
+ assert_rnp_success(rnp_op_sign_set_file_mtime(op, 12345678));
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_rnp_success(rnp_output_memory_get_buf(output, &signed_buf, &signed_len, true));
+ assert_non_null(signed_buf);
+ assert_true(signed_len > 0);
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ op = NULL;
+
+ // check the resulting stream for correct name/time
+ assert_rnp_success(rnp_input_from_memory(&input, signed_buf, signed_len, false));
+ char *json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_non_null(json);
+
+ std::string jstr = json;
+ assert_true(jstr.find("\"filename\":\"testfile.dat\"") != std::string::npos);
+ assert_true(jstr.find("\"timestamp\":12345678") != std::string::npos);
+
+ assert_rnp_success(rnp_input_destroy(input));
+ rnp_buffer_destroy(signed_buf);
+ rnp_buffer_destroy(json);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_op_set_hash)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ uint8_t * signed_buf;
+ size_t signed_len;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init input
+ test_ffi_init_sign_memory_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // make sure it doesn't fail on NULL hash value
+ assert_rnp_failure(rnp_op_sign_set_hash(op, NULL));
+ assert_rnp_failure(rnp_op_sign_set_hash(op, "Unknown"));
+ assert_rnp_success(rnp_op_sign_set_hash(op, "SHA256"));
+ // execute the operation with wrong password
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "wrong"));
+ assert_int_equal(rnp_op_sign_execute(op), RNP_ERROR_BAD_PASSWORD);
+ assert_rnp_success(rnp_op_sign_destroy(op));
+ // execute the operation with valid password
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_rnp_success(rnp_output_memory_get_buf(output, &signed_buf, &signed_len, true));
+ assert_non_null(signed_buf);
+ assert_true(signed_len > 0);
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_sign_destroy(op));
+
+ rnp_buffer_destroy(signed_buf);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_op_set_compression)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_sign_t op = NULL;
+ uint8_t * signed_buf;
+ size_t signed_len;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ // init input
+ test_ffi_init_sign_memory_input(&input, &output);
+ // create signature operation
+ assert_rnp_success(rnp_op_sign_create(&op, ffi, input, output));
+ // setup signature(s)
+ test_ffi_setup_signatures(&ffi, &op);
+ // make sure it doesn't fail on NULL compression algorithm value
+ assert_rnp_failure(rnp_op_sign_set_compression(op, NULL, 6));
+ assert_rnp_failure(rnp_op_sign_set_compression(op, "Unknown", 6));
+ assert_rnp_failure(rnp_op_sign_set_compression(NULL, "ZLib", 6));
+ assert_rnp_success(rnp_op_sign_set_compression(op, "ZLib", 6));
+ // execute the operation
+ assert_rnp_success(rnp_op_sign_execute(op));
+ // make sure the output file was created
+ assert_rnp_success(rnp_output_memory_get_buf(output, &signed_buf, &signed_len, true));
+ assert_non_null(signed_buf);
+ assert_true(signed_len > 0);
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_sign_destroy(op));
+
+ rnp_buffer_destroy(signed_buf);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_aead_params)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char *plaintext = "Some data to encrypt using the AEAD-EAX and AEAD-OCB encryption.";
+
+ // setup FFI
+ test_ffi_init(&ffi);
+
+ // write out some data
+ str_to_file("plaintext", plaintext);
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ assert_non_null(output);
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // setup AEAD params
+ assert_rnp_failure(rnp_op_encrypt_set_aead(NULL, "OCB"));
+ assert_rnp_failure(rnp_op_encrypt_set_aead(op, NULL));
+ assert_rnp_failure(rnp_op_encrypt_set_aead(op, "WRONG"));
+ if (!aead_ocb_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_set_aead(op, "OCB"));
+ } else {
+ assert_rnp_success(rnp_op_encrypt_set_aead(op, "OCB"));
+ }
+ assert_rnp_failure(rnp_op_encrypt_set_aead_bits(NULL, 10));
+ assert_rnp_failure(rnp_op_encrypt_set_aead_bits(op, -1));
+ assert_rnp_failure(rnp_op_encrypt_set_aead_bits(op, 60));
+ assert_rnp_failure(rnp_op_encrypt_set_aead_bits(op, 17));
+ assert_rnp_success(rnp_op_encrypt_set_aead_bits(op, 10));
+ // add password (using all defaults)
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass1", NULL, 0, NULL));
+ // setup compression
+ assert_rnp_failure(rnp_op_encrypt_set_compression(NULL, "ZLIB", 6));
+ assert_rnp_failure(rnp_op_encrypt_set_compression(op, NULL, 6));
+ assert_rnp_failure(rnp_op_encrypt_set_compression(op, "WRONG", 6));
+ assert_rnp_success(rnp_op_encrypt_set_compression(op, "ZLIB", 6));
+ // set filename and mtime
+ assert_rnp_failure(rnp_op_encrypt_set_file_name(NULL, "filename"));
+ assert_rnp_success(rnp_op_encrypt_set_file_name(op, NULL));
+ assert_rnp_success(rnp_op_encrypt_set_file_name(op, "filename"));
+ assert_rnp_failure(rnp_op_encrypt_set_file_mtime(NULL, 1000));
+ assert_rnp_success(rnp_op_encrypt_set_file_mtime(op, 1000));
+ // execute the operation
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+
+ // list packets
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ char *json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ json_object *jso = json_tokener_parse(json);
+ rnp_buffer_destroy(json);
+ assert_non_null(jso);
+ assert_true(json_object_is_type(jso, json_type_array));
+ /* check the symmetric-key encrypted session key packet */
+ json_object *pkt = json_object_array_get_idx(jso, 0);
+ assert_true(check_json_pkt_type(pkt, PGP_PKT_SK_SESSION_KEY));
+ if (!aead_ocb_enabled()) {
+ // if AEAD is not enabled then v4 encrypted packet will be created
+ assert_true(check_json_field_int(pkt, "version", 4));
+ assert_true(check_json_field_str(pkt, "algorithm.str", "AES-256"));
+ } else {
+ assert_true(check_json_field_int(pkt, "version", 5));
+ assert_true(check_json_field_str(pkt, "aead algorithm.str", "OCB"));
+ }
+ /* check the aead-encrypted packet */
+ pkt = json_object_array_get_idx(jso, 1);
+ if (!aead_ocb_enabled()) {
+ assert_true(check_json_pkt_type(pkt, PGP_PKT_SE_IP_DATA));
+ } else {
+ assert_true(check_json_pkt_type(pkt, PGP_PKT_AEAD_ENCRYPTED));
+ assert_true(check_json_field_int(pkt, "version", 1));
+ assert_true(check_json_field_str(pkt, "aead algorithm.str", "OCB"));
+ assert_true(check_json_field_int(pkt, "chunk size", 10));
+ }
+ json_object_put(jso);
+
+ /* decrypt */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass1"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_true(file_equals("decrypted", plaintext, strlen(plaintext)));
+ rnp_unlink("decrypted");
+
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_detached_verify_input)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ /* verify detached signature via rnp_op_verify_create - should not crash */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_signatures/source.txt.sig"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_detached_cleartext_signed_input)
+{
+ rnp_ffi_t ffi = NULL;
+ test_ffi_init(&ffi);
+ /* verify detached signature with cleartext input - must fail */
+ rnp_input_t inputmsg = NULL;
+ assert_rnp_success(rnp_input_from_path(&inputmsg, "data/test_messages/message.txt"));
+ rnp_input_t inputsig = NULL;
+ assert_rnp_success(
+ rnp_input_from_path(&inputsig, "data/test_messages/message.txt.cleartext-signed"));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, inputmsg, inputsig));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(inputmsg);
+ rnp_input_destroy(inputsig);
+ /* verify detached signature with signed/embedded input - must fail */
+ assert_rnp_success(rnp_input_from_path(&inputmsg, "data/test_messages/message.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&inputsig, "data/test_messages/message.txt.empty.sig"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, inputmsg, inputsig));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(inputmsg);
+ rnp_input_destroy(inputsig);
+ /* verify detached signature as a whole message - must fail */
+ assert_rnp_success(rnp_input_from_path(&inputmsg, "data/test_messages/message.txt.sig"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, inputmsg, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_output_destroy(output);
+ rnp_input_destroy(inputmsg);
+
+ rnp_ffi_destroy(ffi);
+}
+
+static bool
+check_signature(rnp_op_verify_t op, size_t idx, rnp_result_t status)
+{
+ rnp_op_verify_signature_t sig = NULL;
+ if (rnp_op_verify_get_signature_at(op, idx, &sig)) {
+ return false;
+ }
+ return rnp_op_verify_signature_get_status(sig) == status;
+}
+
+TEST_F(rnp_tests, test_ffi_op_verify_sig_count)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ test_ffi_init(&ffi);
+
+ /* signed message */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.signed"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_failure(rnp_op_verify_create(NULL, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_create(&verify, NULL, input, output));
+ assert_rnp_failure(rnp_op_verify_create(&verify, ffi, NULL, output));
+ assert_rnp_failure(rnp_op_verify_create(&verify, ffi, input, NULL));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(NULL));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ size_t sigcount = 0;
+ assert_rnp_failure(rnp_op_verify_get_signature_count(verify, NULL));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed with unknown key */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.unknown"));
+ 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);
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_KEY_NOT_FOUND));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed with malformed signature (bad version) */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.malfsig"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_UNKNOWN));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed with invalid signature (modified hash alg) */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.invsig"));
+ 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);
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed without the signature */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.nosig"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* detached signature */
+ rnp_input_t source = NULL;
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/message.txt"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.sig"));
+ assert_rnp_failure(rnp_op_verify_detached_create(NULL, ffi, source, input));
+ assert_rnp_failure(rnp_op_verify_detached_create(&verify, NULL, source, input));
+ assert_rnp_failure(rnp_op_verify_detached_create(&verify, ffi, NULL, input));
+ assert_rnp_failure(rnp_op_verify_detached_create(&verify, ffi, source, NULL));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* detached text-mode signature */
+ source = NULL;
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/message.txt"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.sig-text"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ source = NULL;
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/message.txt.crlf"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.sig-text"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* detached text-mode signature with trailing CR characters */
+ source = NULL;
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&source, "data/test_messages/message-trailing-cr.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message-trailing-cr.txt.sig-text"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* detached text-mode signature with CRLF on 32k boundary */
+ source = NULL;
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&source, "data/test_messages/message-32k-crlf.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message-32k-crlf.txt.sig"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* embedded text-mode signature with CRLF on 32k boundary */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message-32k-crlf.txt.gpg"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* malformed detached signature */
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/message.txt"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.sig.malf"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* malformed detached signature, wrong bitlen in MPI */
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/message.txt"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.sig.wrong-mpi-bitlen"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* encrypted message */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.encrypted"));
+ 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));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* encrypted and signed message */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-encrypted"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* cleartext signed message */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.cleartext-signed"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* cleartext signed message without newline */
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(
+ &input, "data/test_messages/message.txt.cleartext-signed-nonewline"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* cleartext signed with malformed signature (wrong mpi len) */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.cleartext-malf"));
+ 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);
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_UNKNOWN));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* cleartext signed without the signature */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.cleartext-nosig"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message without compression */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-no-z"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed and password-encrypted data with 0 compression algo */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-sym-none-z"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with one-pass with wrong version */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-no-z-malf"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* encrypted and signed message with marker packet */
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.marker"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* encrypted and signed message with marker packet, armored */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.marker.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));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* encrypted and signed message with malformed marker packet */
+ sigcount = 255;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.marker.malf"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* sha1 detached signature over the collision-suspicious data */
+ /* allow sha1 temporary */
+ rnp::SecurityRule allow_sha1(
+ rnp::FeatureType::Hash, PGP_HASH_SHA1, rnp::SecurityLevel::Default, 1547856001);
+ global_ctx.profile.add_rule(allow_sha1);
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/shattered-1.pdf"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/shattered-1.pdf.sig"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* sha1 detached signature over the document with collision*/
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&source, "data/test_messages/shattered-2.pdf"));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/shattered-1.pdf.sig"));
+ assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, source, input));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(source);
+ rnp_input_destroy(input);
+
+ /* sha1 attached signature over the collision-suspicious data */
+ sigcount = 255;
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/shattered-2.pdf.gpg"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* remove sha1 rule */
+ assert_true(global_ctx.profile.del_rule(allow_sha1));
+
+ /* signed message with key which is now expired */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ import_pub_keys(ffi, "data/test_messages/expired_signing_key-pub.asc");
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "30FC0D776915BA44", &key));
+ uint64_t till = 0;
+ assert_rnp_success(rnp_key_valid_till64(key, &till));
+ assert_int_equal(till, 1623424417);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-expired-key"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with subkey which is now expired */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ import_pub_keys(ffi, "data/test_messages/expired_signing_sub-pub.asc");
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "D93A47FD93191FD1", &key));
+ till = 0;
+ assert_rnp_success(rnp_key_valid_till64(key, &till));
+ assert_int_equal(till, 1623933507);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-expired-sub"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with md5 hash */
+ 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"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.md5"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with md5 hash before the cut-off date */
+ assert_true(import_all_keys(ffi, "data/test_key_edge_cases/key-rsa-2001-pub.asc"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-md5-before"));
+ 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));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with md5 hash right after the cut-off date */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-md5-after"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* signed message with sha1 hash */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed.sha1"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message signed with sha1 before the cut-off date */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-sha1-before"));
+ 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));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_SUCCESS));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message signed with sha1 right after the cut-off date */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.signed-sha1-after"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ sigcount = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
+ assert_int_equal(sigcount, 1);
+ assert_true(check_signature(verify, 0, RNP_ERROR_SIGNATURE_INVALID));
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_op_verify_get_protection_info)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ /* message just signed */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.signed"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ char *mode = NULL;
+ char *cipher = NULL;
+ bool valid = true;
+ assert_rnp_failure(rnp_op_verify_get_protection_info(NULL, &mode, &cipher, &valid));
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, NULL, NULL));
+ assert_string_equal(mode, "none");
+ rnp_buffer_destroy(mode);
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, NULL, &cipher, NULL));
+ assert_string_equal(cipher, "none");
+ rnp_buffer_destroy(cipher);
+ valid = true;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, NULL, NULL, &valid));
+ assert_false(valid);
+ assert_rnp_failure(rnp_op_verify_get_protection_info(verify, NULL, NULL, NULL));
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "none");
+ assert_string_equal(cipher, "none");
+ assert_false(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message without MDC */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-no-mdc"));
+ 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));
+ mode = NULL;
+ cipher = NULL;
+ valid = true;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "cfb");
+ assert_string_equal(cipher, "AES256");
+ assert_false(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with MDC */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.enc-mdc"));
+ 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));
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "cfb-mdc");
+ assert_string_equal(cipher, "AES256");
+ assert_true(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-OCB */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-ocb"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_ocb_enabled() || aead_ocb_aes_only()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-ocb");
+ assert_string_equal(cipher, "CAMELLIA192");
+ assert_true(valid == (aead_ocb_enabled() && !aead_ocb_aes_only()));
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-OCB AES-192 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-ocb-aes"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_ocb_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-ocb");
+ assert_string_equal(cipher, "AES192");
+ assert_true(valid == aead_ocb_enabled());
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* modified message with AEAD-OCB */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-ocb-malf"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-ocb");
+ assert_string_equal(cipher, "CAMELLIA192");
+ assert_false(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-EAX */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-eax"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-eax");
+ assert_string_equal(cipher, "AES256");
+ assert_true(valid == aead_eax_enabled());
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* modified message with AEAD-EAX */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-eax-malf"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ mode = NULL;
+ cipher = NULL;
+ valid = false;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-eax");
+ assert_string_equal(cipher, "AES256");
+ assert_false(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+static bool
+getpasscb_for_key(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ if (!key) {
+ return false;
+ }
+ char *keyid = NULL;
+ rnp_key_get_keyid(key, &keyid);
+ if (!keyid) {
+ return false;
+ }
+ const char *pass = "password";
+ if (strcmp(keyid, (const char *) app_ctx)) {
+ pass = "wrongpassword";
+ }
+ size_t pass_len = strlen(pass);
+ rnp_buffer_destroy(keyid);
+
+ if (pass_len >= buf_len) {
+ return false;
+ }
+ memcpy(buf, pass, pass_len + 1);
+ return true;
+}
+
+TEST_F(rnp_tests, test_ffi_op_verify_recipients_info)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ test_ffi_init(&ffi);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ /* message just signed */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.signed"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* check filename and mtime */
+ char * filename = NULL;
+ uint32_t mtime = 0;
+ assert_rnp_failure(rnp_op_verify_get_file_info(NULL, &filename, &mtime));
+ assert_rnp_success(rnp_op_verify_get_file_info(verify, &filename, &mtime));
+ assert_string_equal(filename, "message.txt");
+ assert_int_equal(mtime, 1571991574);
+ rnp_buffer_destroy(filename);
+ filename = NULL;
+ assert_rnp_success(rnp_op_verify_get_file_info(verify, &filename, NULL));
+ assert_string_equal(filename, "message.txt");
+ rnp_buffer_destroy(filename);
+ mtime = 0;
+ assert_rnp_success(rnp_op_verify_get_file_info(verify, NULL, &mtime));
+ assert_int_equal(mtime, 1571991574);
+ /* rnp_op_verify_get_recipient_count */
+ assert_rnp_failure(rnp_op_verify_get_recipient_count(verify, NULL));
+ size_t count = 255;
+ assert_rnp_failure(rnp_op_verify_get_recipient_count(NULL, &count));
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 0);
+ /* rnp_op_verify_get_recipient_at */
+ rnp_recipient_handle_t recipient = NULL;
+ assert_rnp_failure(rnp_op_verify_get_recipient_at(NULL, 0, &recipient));
+ assert_rnp_failure(rnp_op_verify_get_recipient_at(verify, 0, NULL));
+ assert_rnp_failure(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_rnp_failure(rnp_op_verify_get_recipient_at(verify, 10, &recipient));
+ /* rnp_op_verify_get_used_recipient */
+ assert_rnp_failure(rnp_op_verify_get_used_recipient(NULL, &recipient));
+ assert_rnp_failure(rnp_op_verify_get_used_recipient(verify, NULL));
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_null(recipient);
+ /* rnp_op_verify_get_symenc_count */
+ assert_rnp_failure(rnp_op_verify_get_symenc_count(verify, NULL));
+ count = 255;
+ assert_rnp_failure(rnp_op_verify_get_symenc_count(NULL, &count));
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 0);
+ /* rnp_op_verify_get_symenc_at */
+ rnp_symenc_handle_t symenc = NULL;
+ assert_rnp_failure(rnp_op_verify_get_symenc_at(NULL, 0, &symenc));
+ assert_rnp_failure(rnp_op_verify_get_symenc_at(verify, 0, NULL));
+ assert_rnp_failure(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_rnp_failure(rnp_op_verify_get_symenc_at(verify, 10, &symenc));
+ /* rnp_op_verify_get_used_symenc */
+ assert_rnp_failure(rnp_op_verify_get_used_symenc(NULL, &symenc));
+ assert_rnp_failure(rnp_op_verify_get_used_symenc(verify, NULL));
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ assert_null(symenc);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message without MDC: single recipient */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-no-mdc"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_failure(rnp_op_verify_get_recipient_at(verify, 1, &recipient));
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ char *alg = NULL;
+ assert_rnp_failure(rnp_recipient_get_alg(NULL, &alg));
+ assert_rnp_failure(rnp_recipient_get_alg(recipient, NULL));
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ char *keyid = NULL;
+ assert_rnp_failure(rnp_recipient_get_keyid(NULL, &keyid));
+ assert_rnp_failure(rnp_recipient_get_keyid(recipient, NULL));
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+ recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_non_null(recipient);
+ alg = NULL;
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-OCB: single password */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-ocb"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_ocb_enabled() || aead_ocb_aes_only()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 0);
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_failure(rnp_op_verify_get_symenc_at(verify, 1, &symenc));
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_non_null(symenc);
+ char *cipher = NULL;
+ assert_rnp_failure(rnp_symenc_get_cipher(symenc, NULL));
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "CAMELLIA192");
+ rnp_buffer_destroy(cipher);
+ char *aead = NULL;
+ assert_rnp_failure(rnp_symenc_get_aead_alg(symenc, NULL));
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "OCB");
+ rnp_buffer_destroy(aead);
+ char *hash = NULL;
+ assert_rnp_failure(rnp_symenc_get_hash_alg(symenc, NULL));
+ assert_rnp_success(rnp_symenc_get_hash_alg(symenc, &hash));
+ assert_string_equal(hash, "SHA1");
+ rnp_buffer_destroy(hash);
+ char *s2k = NULL;
+ assert_rnp_failure(rnp_symenc_get_s2k_type(symenc, NULL));
+ assert_rnp_success(rnp_symenc_get_s2k_type(symenc, &s2k));
+ assert_string_equal(s2k, "Iterated and salted");
+ rnp_buffer_destroy(s2k);
+ uint32_t iterations = 0;
+ assert_rnp_failure(rnp_symenc_get_s2k_iterations(symenc, NULL));
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 30408704);
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ if (!aead_ocb_enabled() || aead_ocb_aes_only()) {
+ assert_null(symenc);
+ } else {
+ assert_non_null(symenc);
+ cipher = NULL;
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "CAMELLIA192");
+ rnp_buffer_destroy(cipher);
+ aead = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "OCB");
+ rnp_buffer_destroy(aead);
+ hash = NULL;
+ assert_rnp_success(rnp_symenc_get_hash_alg(symenc, &hash));
+ assert_string_equal(hash, "SHA1");
+ rnp_buffer_destroy(hash);
+ s2k = NULL;
+ assert_rnp_success(rnp_symenc_get_s2k_type(symenc, &s2k));
+ assert_string_equal(s2k, "Iterated and salted");
+ rnp_buffer_destroy(s2k);
+ iterations = 0;
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 30408704);
+ }
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-OCB-AES: single password */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-ocb-aes"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_ocb_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 0);
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_non_null(symenc);
+ cipher = NULL;
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES192");
+ rnp_buffer_destroy(cipher);
+ aead = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "OCB");
+ rnp_buffer_destroy(aead);
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ if (!aead_ocb_enabled()) {
+ assert_null(symenc);
+ } else {
+ assert_non_null(symenc);
+ cipher = NULL;
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES192");
+ rnp_buffer_destroy(cipher);
+ aead = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "OCB");
+ rnp_buffer_destroy(aead);
+ }
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* modified message with AEAD-EAX: one recipient and one password, decrypt with recipient
+ */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-eax-malf"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ alg = NULL;
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+ recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ if (!aead_eax_enabled()) {
+ assert_null(recipient);
+ } else {
+ assert_non_null(recipient);
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_non_null(recipient);
+ alg = NULL;
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+ recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_non_null(recipient);
+ assert_rnp_success(rnp_recipient_get_alg(recipient, &alg));
+ assert_string_equal(alg, "RSA");
+ rnp_buffer_destroy(alg);
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+ }
+
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_non_null(symenc);
+ cipher = NULL;
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES256");
+ rnp_buffer_destroy(cipher);
+ aead = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "EAX");
+ rnp_buffer_destroy(aead);
+ hash = NULL;
+ assert_rnp_success(rnp_symenc_get_hash_alg(symenc, &hash));
+ assert_string_equal(hash, "SHA256");
+ rnp_buffer_destroy(hash);
+ s2k = NULL;
+ assert_rnp_success(rnp_symenc_get_s2k_type(symenc, &s2k));
+ assert_string_equal(s2k, "Iterated and salted");
+ rnp_buffer_destroy(s2k);
+ iterations = 0;
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 3932160);
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ assert_null(symenc);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message with AEAD-EAX: one recipient and one password, decrypt with password */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-aead-eax"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ }
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_null(recipient);
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_non_null(symenc);
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ if (!aead_eax_enabled()) {
+ assert_null(symenc);
+ } else {
+ assert_non_null(symenc);
+ cipher = NULL;
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES256");
+ rnp_buffer_destroy(cipher);
+ aead = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aead));
+ assert_string_equal(aead, "EAX");
+ rnp_buffer_destroy(aead);
+ hash = NULL;
+ assert_rnp_success(rnp_symenc_get_hash_alg(symenc, &hash));
+ assert_string_equal(hash, "SHA256");
+ rnp_buffer_destroy(hash);
+ s2k = NULL;
+ assert_rnp_success(rnp_symenc_get_s2k_type(symenc, &s2k));
+ assert_string_equal(s2k, "Iterated and salted");
+ rnp_buffer_destroy(s2k);
+ iterations = 0;
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 3932160);
+ }
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* message encrypted to 3 recipients and 2 passwords: password1, password2 */
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "wrongpassword"));
+ assert_true(import_sec_keys(ffi, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-3key-2p"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 3);
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 1, &recipient));
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 2, &recipient));
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "54505A936A4A970E");
+ rnp_buffer_destroy(keyid);
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_null(recipient);
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 2);
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 3932160);
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 1, &symenc));
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_int_equal(iterations, 3276800);
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ assert_null(symenc);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password2"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-3key-2p"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ assert_rnp_success(rnp_symenc_get_s2k_iterations(symenc, &iterations));
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_null(recipient);
+ assert_int_equal(iterations, 3276800);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, getpasscb_for_key, (void *) "8A05B89FAD5ADED1"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-3key-2p"));
+ 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));
+ assert_rnp_success(rnp_op_verify_get_used_symenc(verify, &symenc));
+ assert_null(symenc);
+ assert_rnp_success(rnp_op_verify_get_used_recipient(verify, &recipient));
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_secret_sig_import)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(import_sec_keys(ffi, "data/test_key_validity/alice-sec.asc"));
+ rnp_key_handle_t key_handle = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
+ bool locked = false;
+ /* unlock secret key */
+ assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
+ assert_true(locked);
+ assert_rnp_success(rnp_key_unlock(key_handle, "password"));
+ assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
+ assert_false(locked);
+ /* import revocation signature */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-rev.pgp"));
+ assert_rnp_success(rnp_import_signatures(ffi, input, 0, NULL));
+ assert_rnp_success(rnp_input_destroy(input));
+ /* make sure that key is still unlocked */
+ assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
+ assert_false(locked);
+ /* import subkey */
+ assert_true(import_sec_keys(ffi, "data/test_key_validity/alice-sub-sec.pgp"));
+ /* make sure that primary key is still unlocked */
+ assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
+ assert_false(locked);
+ /* unlock subkey and make sure it is unlocked after revocation */
+ rnp_key_handle_t sub_handle = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD23CEB7FEBEFF17", &sub_handle));
+ assert_rnp_success(rnp_key_unlock(sub_handle, "password"));
+ assert_rnp_success(rnp_key_is_locked(sub_handle, &locked));
+ assert_false(locked);
+ assert_rnp_success(rnp_key_revoke(sub_handle, 0, "SHA256", "retired", "Custom reason"));
+ assert_rnp_success(rnp_key_is_locked(sub_handle, &locked));
+ assert_false(locked);
+ assert_rnp_success(rnp_key_handle_destroy(sub_handle));
+ assert_rnp_success(rnp_key_handle_destroy(key_handle));
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+static bool
+getpasscb_fail(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ return false;
+}
+
+static bool
+getpasscb_context(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ strncpy(buf, pgp_context, buf_len - 1);
+ return true;
+}
+
+static bool
+getpasscb_keyid(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ if (!key) {
+ return false;
+ }
+ char *keyid = NULL;
+ if (rnp_key_get_keyid(key, &keyid)) {
+ return false;
+ }
+ strncpy(buf, keyid, buf_len - 1);
+ rnp_buffer_destroy(keyid);
+ return true;
+}
+
+TEST_F(rnp_tests, test_ffi_rnp_request_password)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ /* check wrong parameters cases */
+ char *password = NULL;
+ assert_rnp_failure(rnp_request_password(ffi, NULL, "sign", &password));
+ assert_null(password);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_failure(rnp_request_password(NULL, NULL, "sign", &password));
+ assert_rnp_failure(rnp_request_password(ffi, NULL, "sign", NULL));
+ /* now it should succeed */
+ assert_rnp_success(rnp_request_password(ffi, NULL, "sign", &password));
+ assert_string_equal(password, "password");
+ rnp_buffer_destroy(password);
+ /* let's try failing password provider */
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_fail, NULL));
+ assert_rnp_failure(rnp_request_password(ffi, NULL, "sign", &password));
+ /* let's try to return request context */
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_context, NULL));
+ assert_rnp_success(rnp_request_password(ffi, NULL, "custom context", &password));
+ assert_string_equal(password, "custom context");
+ rnp_buffer_destroy(password);
+ /* let's check whether key is correctly passed to handler */
+ assert_true(import_sec_keys(ffi, "data/test_key_validity/alice-sec.asc"));
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_keyid, NULL));
+ assert_rnp_success(rnp_request_password(ffi, key, NULL, &password));
+ assert_string_equal(password, "0451409669FFDE3C");
+ rnp_buffer_destroy(password);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+TEST_F(rnp_tests, test_ffi_mdc_8k_boundary)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+
+ test_ffi_init(&ffi);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ /* correctly process two messages */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message_mdc_8k_1.pgp"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_null(&output));
+ rnp_op_verify_t verify;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* check signature */
+ size_t sig_count = 0;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 1);
+ rnp_op_verify_signature_t sig = NULL;
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ /* cleanup */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message_mdc_8k_2.pgp"));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* check signature */
+ sig_count = 0;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 1);
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ /* cleanup */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+
+ /* let it gracefully fail on message 1 with the last byte cut */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message_mdc_8k_cut1.pgp"));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ /* cleanup */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+
+ /* let it gracefully fail on message 1 with the last 22 bytes (MDC size) cut */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message_mdc_8k_cut22.pgp"));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(verify));
+ /* cleanup */
+ assert_rnp_success(rnp_op_verify_destroy(verify));
+ assert_rnp_success(rnp_input_destroy(input));
+
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+}
+
+TEST_F(rnp_tests, test_ffi_decrypt_wrong_mpi_bits)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ test_ffi_init(&ffi);
+
+ /* 1024 bitcount instead of 1023 */
+ rnp_op_verify_t op = NULL;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-malf-1"));
+ 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(&op, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(op));
+ }
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* 1025 bitcount instead of 1023 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-malf-2"));
+ 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(&op, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(op));
+ }
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* 1031 bitcount instead of 1023 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-malf-3"));
+ 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(&op, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(op));
+ }
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* 1040 bitcount instead of 1023 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-malf-4"));
+ 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(&op, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(op));
+ }
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* 1017 bitcount instead of 1023 */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-malf-5"));
+ 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(&op, ffi, input, output));
+ if (!aead_eax_enabled()) {
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ } else {
+ assert_rnp_success(rnp_op_verify_execute(op));
+ }
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_decrypt_edge_cases)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ test_ffi_init(&ffi);
+
+ /* unknown algorithm in public-key encrypted session key */
+ rnp_op_verify_t op = NULL;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-wrong-alg"));
+ 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(&op, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* endless recursive compression packets, 'quine'.
+ * Generated using the code by Taylor R. Campbell */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.zlib-quine"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&op, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.zlib-quine"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.zlib-quine"));
+ char *json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_non_null(json);
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ /* 128 levels of compression - fail decryption*/
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr.128-rounds"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_op_verify_create(&op, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* but dumping will succeed */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr.128-rounds"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr.128-rounds"));
+ json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_non_null(json);
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ /* 32 levels of compression + encryption */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.32-rounds"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_success(rnp_op_verify_create(&op, ffi, input, output));
+ assert_rnp_failure(rnp_op_verify_execute(op));
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.32-rounds"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.32-rounds"));
+ json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_non_null(json);
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ /* 31 levels of compression + encryption */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.31-rounds"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_op_verify_create(&op, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(op));
+ rnp_op_verify_destroy(op);
+ rnp_input_destroy(input);
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 7);
+ assert_int_equal(memcmp(buf, "message", 7), 0);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.31-rounds"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_dump_packets_to_output(input, output, 0));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.compr-encr.31-rounds"));
+ json = NULL;
+ assert_rnp_success(rnp_dump_packets_to_json(input, 0, &json));
+ assert_non_null(json);
+ rnp_buffer_destroy(json);
+ rnp_input_destroy(input);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_key_remove)
+{
+ rnp_ffi_t ffi = NULL;
+ test_ffi_init(&ffi);
+
+ rnp_key_handle_t key0 = NULL;
+ rnp_key_handle_t key0_sub0 = NULL;
+ rnp_key_handle_t key0_sub1 = NULL;
+ rnp_key_handle_t key0_sub2 = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key0));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "1ed63ee56fadc34d", &key0_sub0));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "1d7e8a5393c997a8", &key0_sub1));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8a05b89fad5aded1", &key0_sub2));
+
+ /* edge cases */
+ assert_rnp_failure(rnp_key_remove(NULL, RNP_KEY_REMOVE_PUBLIC));
+ assert_rnp_failure(rnp_key_remove(key0, 0));
+ /* make sure we correctly remove public and secret keys */
+ bool pub = false;
+ assert_rnp_success(rnp_key_have_public(key0_sub2, &pub));
+ assert_true(pub);
+ bool sec = false;
+ assert_rnp_success(rnp_key_have_secret(key0_sub2, &sec));
+ assert_true(sec);
+ assert_rnp_success(rnp_key_remove(key0_sub2, RNP_KEY_REMOVE_PUBLIC));
+ pub = true;
+ assert_rnp_success(rnp_key_have_public(key0_sub2, &pub));
+ assert_false(pub);
+ sec = false;
+ assert_rnp_success(rnp_key_have_secret(key0_sub2, &sec));
+ assert_true(sec);
+ assert_rnp_failure(rnp_key_remove(key0_sub2, RNP_KEY_REMOVE_PUBLIC));
+ rnp_key_handle_destroy(key0_sub2);
+ /* locate it back */
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8a05b89fad5aded1", &key0_sub2));
+ assert_non_null(key0_sub2);
+ pub = true;
+ assert_rnp_success(rnp_key_have_public(key0_sub2, &pub));
+ assert_false(pub);
+ sec = false;
+ assert_rnp_success(rnp_key_have_secret(key0_sub2, &sec));
+ assert_true(sec);
+
+ pub = false;
+ assert_rnp_success(rnp_key_have_public(key0_sub0, &pub));
+ assert_true(pub);
+ sec = false;
+ assert_rnp_success(rnp_key_have_secret(key0_sub0, &sec));
+ assert_true(sec);
+ assert_rnp_success(rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_SECRET));
+ pub = false;
+ assert_rnp_success(rnp_key_have_public(key0_sub0, &pub));
+ assert_true(pub);
+ sec = true;
+ assert_rnp_success(rnp_key_have_secret(key0_sub0, &sec));
+ assert_false(sec);
+ assert_rnp_failure(rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_SECRET));
+ rnp_key_handle_destroy(key0_sub0);
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "1ed63ee56fadc34d", &key0_sub0));
+ assert_non_null(key0_sub0);
+
+ size_t count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+ count = 0;
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+
+ /* while there are 2 public and 1 secret subkey, this calculates only public */
+ assert_rnp_success(rnp_key_get_subkey_count(key0, &count));
+ assert_int_equal(count, 2);
+
+ assert_rnp_success(rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_PUBLIC));
+ assert_rnp_success(rnp_key_get_subkey_count(key0, &count));
+ assert_int_equal(count, 1);
+ count = 0;
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 5);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+
+ assert_rnp_success(rnp_key_remove(key0_sub2, RNP_KEY_REMOVE_SECRET));
+ assert_rnp_success(rnp_key_get_subkey_count(key0, &count));
+ assert_int_equal(count, 1);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 5);
+
+ assert_rnp_success(rnp_key_remove(key0, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 4);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 4);
+
+ rnp_key_handle_destroy(key0_sub1);
+ /* key0_sub1 should be left in keyring */
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "1d7e8a5393c997a8", &key0_sub1));
+ pub = false;
+ assert_rnp_success(rnp_key_have_public(key0_sub1, &pub));
+ assert_true(pub);
+ sec = false;
+ assert_rnp_success(rnp_key_have_secret(key0_sub1, &sec));
+ assert_true(sec);
+
+ rnp_key_handle_destroy(key0);
+ rnp_key_handle_destroy(key0_sub0);
+ rnp_key_handle_destroy(key0_sub1);
+ rnp_key_handle_destroy(key0_sub2);
+
+ /* let's import keys back */
+ assert_true(import_pub_keys(ffi, "data/keyrings/1/pubring.gpg"));
+ assert_true(import_sec_keys(ffi, "data/keyrings/1/secring.gpg"));
+
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 7);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 7);
+
+ /* now try to remove the whole key */
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key0));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "1ed63ee56fadc34d", &key0_sub0));
+
+ assert_rnp_failure(
+ rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_SECRET | RNP_KEY_REMOVE_SUBKEYS));
+ assert_rnp_success(rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_SECRET));
+ assert_rnp_success(rnp_key_remove(key0_sub0, RNP_KEY_REMOVE_PUBLIC));
+
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+
+ assert_rnp_success(rnp_key_remove(key0, RNP_KEY_REMOVE_SECRET | RNP_KEY_REMOVE_SUBKEYS));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 6);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 3);
+
+ assert_rnp_success(rnp_key_remove(key0, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SUBKEYS));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 3);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 3);
+
+ rnp_key_handle_destroy(key0);
+ rnp_key_handle_destroy(key0_sub0);
+
+ /* delete the second key all at once */
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "2fcadf05ffa501bb", &key0));
+ assert_rnp_success(rnp_key_remove(
+ key0, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET | RNP_KEY_REMOVE_SUBKEYS));
+ assert_rnp_success(rnp_get_public_key_count(ffi, &count));
+ assert_int_equal(count, 0);
+ assert_rnp_success(rnp_get_secret_key_count(ffi, &count));
+ assert_int_equal(count, 0);
+ rnp_key_handle_destroy(key0);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_literal_packet)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // init ffi
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ /* try rnp_decrypt() */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.literal"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ rnp_output_memory_get_buf(output, &buf, &len, false);
+ std::string out;
+ out.assign((char *) buf, len);
+ assert_true(out == file_to_str("data/test_messages/message.txt"));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* try rnp_op_verify() */
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.literal"));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ rnp_output_memory_get_buf(output, &buf, &len, false);
+ out.assign((char *) buf, len);
+ assert_true(out == file_to_str("data/test_messages/message.txt"));
+ char *mode = NULL;
+ char *cipher = NULL;
+ bool valid = true;
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "none");
+ assert_string_equal(cipher, "none");
+ assert_false(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ size_t count = 255;
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &count));
+ assert_int_equal(count, 0);
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 0);
+ count = 255;
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 0);
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+/* This test checks that any exceptions thrown by the internal library
+ * will not propagate beyond the FFI boundary.
+ * In this case we (ab)use a callback to mimic this scenario.
+ */
+TEST_F(rnp_tests, test_ffi_exception)
+{
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+
+ // bad_alloc -> RNP_ERROR_OUT_OF_MEMORY
+ {
+ auto reader = [](void *app_ctx, void *buf, size_t len, size_t *read) {
+ throw std::bad_alloc();
+ return true;
+ };
+ assert_rnp_success(rnp_input_from_callback(&input, reader, NULL, NULL));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_int_equal(RNP_ERROR_OUT_OF_MEMORY, rnp_output_pipe(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+
+ // runtime_error -> RNP_ERROR_GENERIC
+ {
+ auto reader = [](void *app_ctx, void *buf, size_t len, size_t *read) {
+ throw std::runtime_error("");
+ return true;
+ };
+ assert_rnp_success(rnp_input_from_callback(&input, reader, NULL, NULL));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_int_equal(RNP_ERROR_GENERIC, rnp_output_pipe(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+
+ // everything else -> RNP_ERROR_GENERIC
+ {
+ auto reader = [](void *app_ctx, void *buf, size_t len, size_t *read) {
+ throw 5;
+ return true;
+ };
+ assert_rnp_success(rnp_input_from_callback(&input, reader, NULL, NULL));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_int_equal(RNP_ERROR_GENERIC, rnp_output_pipe(input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_key_protection_change)
+{
+ 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));
+
+ assert_rnp_success(rnp_key_unprotect(key, "password"));
+ assert_rnp_success(rnp_key_unprotect(sub, "password"));
+
+ bool protect = true;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_false(protect);
+ protect = true;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_false(protect);
+
+ assert_rnp_success(rnp_key_protect(key, "password2", "Camellia128", NULL, "SHA1", 0));
+ assert_rnp_success(rnp_key_protect(sub, "password2", "Camellia256", NULL, "SHA512", 0));
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_true(protect);
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_true(protect);
+
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(sub);
+
+ reload_keyrings(&ffi);
+
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8a05b89fad5aded1", &sub));
+
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_true(protect);
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_true(protect);
+
+ char *cipher = NULL;
+ assert_rnp_success(rnp_key_get_protection_cipher(key, &cipher));
+ assert_string_equal(cipher, "CAMELLIA128");
+ rnp_buffer_destroy(cipher);
+ char *hash = NULL;
+ assert_rnp_success(rnp_key_get_protection_hash(key, &hash));
+ assert_string_equal(hash, "SHA1");
+ rnp_buffer_destroy(hash);
+ cipher = NULL;
+ assert_rnp_success(rnp_key_get_protection_cipher(sub, &cipher));
+ assert_string_equal(cipher, "CAMELLIA256");
+ rnp_buffer_destroy(cipher);
+ hash = NULL;
+ assert_rnp_success(rnp_key_get_protection_hash(sub, &hash));
+ assert_string_equal(hash, "SHA512");
+ rnp_buffer_destroy(hash);
+
+ assert_rnp_failure(rnp_key_unlock(key, "password"));
+ assert_rnp_failure(rnp_key_unlock(sub, "password"));
+
+ assert_rnp_success(rnp_key_unlock(key, "password2"));
+ assert_rnp_success(rnp_key_unlock(sub, "password2"));
+
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_true(protect);
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_true(protect);
+
+ assert_rnp_success(rnp_key_protect(key, "password3", "AES256", NULL, "SHA512", 10000000));
+ assert_rnp_success(rnp_key_protect(sub, "password3", "AES128", NULL, "SHA1", 10000000));
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_true(protect);
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_true(protect);
+
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(sub);
+
+ reload_keyrings(&ffi);
+
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8a05b89fad5aded1", &sub));
+
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(key, &protect));
+ assert_true(protect);
+ protect = false;
+ assert_rnp_success(rnp_key_is_protected(sub, &protect));
+ assert_true(protect);
+
+ cipher = NULL;
+ assert_rnp_success(rnp_key_get_protection_cipher(key, &cipher));
+ assert_string_equal(cipher, "AES256");
+ rnp_buffer_destroy(cipher);
+ hash = NULL;
+ assert_rnp_success(rnp_key_get_protection_hash(key, &hash));
+ assert_string_equal(hash, "SHA512");
+ rnp_buffer_destroy(hash);
+ size_t iterations = 0;
+ assert_rnp_success(rnp_key_get_protection_iterations(key, &iterations));
+ assert_true(iterations >= 10000000);
+ cipher = NULL;
+ assert_rnp_success(rnp_key_get_protection_cipher(sub, &cipher));
+ assert_string_equal(cipher, "AES128");
+ rnp_buffer_destroy(cipher);
+ hash = NULL;
+ assert_rnp_success(rnp_key_get_protection_hash(sub, &hash));
+ assert_string_equal(hash, "SHA1");
+ rnp_buffer_destroy(hash);
+ iterations = 0;
+ assert_rnp_success(rnp_key_get_protection_iterations(sub, &iterations));
+ assert_true(iterations >= 10000000);
+
+ assert_rnp_failure(rnp_key_unlock(key, "password"));
+ assert_rnp_failure(rnp_key_unlock(sub, "password"));
+
+ assert_rnp_success(rnp_key_unlock(key, "password3"));
+ assert_rnp_success(rnp_key_unlock(sub, "password3"));
+
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(sub);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_set_log_fd)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_rnp_failure(rnp_ffi_set_log_fd(NULL, 0));
+ assert_rnp_failure(rnp_ffi_set_log_fd(ffi, 100));
+ int file_fd = rnp_open("tests.txt", O_RDWR | O_CREAT | O_TRUNC, 0777);
+ assert_true(file_fd > 0);
+ assert_rnp_success(rnp_ffi_set_log_fd(ffi, file_fd));
+ rnp_input_t input = NULL;
+ const char *msg = "hello";
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) msg, strlen(msg), true));
+ char *saved_env = NULL;
+ if (getenv(RNP_LOG_CONSOLE)) {
+ saved_env = strdup(getenv(RNP_LOG_CONSOLE));
+ }
+ setenv(RNP_LOG_CONSOLE, "1", 1);
+ assert_rnp_failure(rnp_load_keys(ffi, "GPG", input, 119));
+ assert_rnp_success(rnp_input_destroy(input));
+ rnp_ffi_destroy(ffi);
+ if (saved_env) {
+ assert_int_equal(0, setenv(RNP_LOG_CONSOLE, saved_env, 1));
+ free(saved_env);
+ } else {
+ unsetenv(RNP_LOG_CONSOLE);
+ }
+#ifndef _WIN32
+ assert_int_equal(fcntl(file_fd, F_GETFD), -1);
+ assert_int_equal(errno, EBADF);
+#endif
+ char buffer[128] = {0};
+ file_fd = rnp_open("tests.txt", O_RDONLY, 0);
+ int64_t rres = read(file_fd, buffer, sizeof(buffer));
+ assert_true(rres > 0);
+ assert_non_null(strstr(buffer, "unexpected flags remaining: 0x"));
+ close(file_fd);
+}
+
+TEST_F(rnp_tests, test_ffi_security_profile)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_ffi_create(&ffi, "GPG", "GPG");
+ /* check predefined rules */
+ uint32_t flags = 0;
+ uint64_t from = 0;
+ uint32_t level = 0;
+ assert_rnp_failure(
+ rnp_get_security_rule(NULL, RNP_FEATURE_HASH_ALG, "SHA1", 0, &flags, &from, &level));
+ assert_rnp_failure(rnp_get_security_rule(ffi, NULL, "SHA1", 0, &flags, &from, &level));
+ assert_rnp_failure(
+ rnp_get_security_rule(ffi, RNP_FEATURE_SYMM_ALG, "AES256", 0, &flags, &from, &level));
+ assert_rnp_failure(
+ rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, "Unknown", 0, &flags, &from, &level));
+ assert_rnp_failure(
+ rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, "SHA1", 0, NULL, NULL, NULL));
+ /* default rule */
+ from = 256;
+ assert_rnp_success(
+ rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, "SHA256", 0, &flags, &from, &level));
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ assert_int_equal(from, 0);
+ /* MD5 */
+ from = 256;
+ assert_rnp_success(
+ rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, "MD5", 0, &flags, &from, &level));
+ assert_int_equal(from, 0);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, MD5_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", MD5_FROM - 1, &flags, &from, &level));
+ assert_int_equal(from, 0);
+ assert_int_equal(flags, 0);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ /* Override it */
+ assert_rnp_failure(rnp_add_security_rule(
+ NULL, RNP_FEATURE_HASH_ALG, "MD5", RNP_SECURITY_OVERRIDE, 0, RNP_SECURITY_DEFAULT));
+ assert_rnp_failure(rnp_add_security_rule(
+ ffi, RNP_FEATURE_SYMM_ALG, "MD5", RNP_SECURITY_OVERRIDE, 0, RNP_SECURITY_DEFAULT));
+ assert_rnp_failure(
+ rnp_add_security_rule(ffi, NULL, "MD5", RNP_SECURITY_OVERRIDE, 0, RNP_SECURITY_DEFAULT));
+ assert_rnp_failure(rnp_add_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, NULL, RNP_SECURITY_OVERRIDE, 0, RNP_SECURITY_DEFAULT));
+ assert_rnp_failure(rnp_add_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_OVERRIDE | 0x17,
+ 0,
+ RNP_SECURITY_DEFAULT));
+ assert_rnp_failure(
+ rnp_add_security_rule(ffi, RNP_FEATURE_HASH_ALG, "MD5", RNP_SECURITY_OVERRIDE, 0, 25));
+ assert_rnp_success(rnp_add_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ RNP_SECURITY_DEFAULT));
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, MD5_FROM - 1);
+ assert_int_equal(flags, RNP_SECURITY_OVERRIDE);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ /* Remove and check back */
+ size_t removed = 0;
+ assert_rnp_failure(rnp_remove_security_rule(NULL,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ &removed));
+ assert_rnp_failure(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_SYMM_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ &removed));
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "SHA256",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ &removed));
+ assert_int_equal(removed, 0);
+ removed = 1;
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_INSECURE,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ &removed));
+ assert_int_equal(removed, 0);
+ removed = 1;
+ assert_rnp_success(rnp_remove_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", RNP_SECURITY_DEFAULT, 0, MD5_FROM - 1, &removed));
+ assert_int_equal(removed, 0);
+ removed = 1;
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM,
+ &removed));
+ assert_int_equal(removed, 0);
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_OVERRIDE,
+ MD5_FROM - 1,
+ &removed));
+ assert_int_equal(removed, 1);
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, MD5_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_int_equal(flags, 0);
+ /* Add for data sigs only */
+ assert_rnp_success(rnp_add_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_VERIFY_DATA,
+ MD5_FROM + 1,
+ RNP_SECURITY_DEFAULT));
+ flags = RNP_SECURITY_VERIFY_DATA;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, MD5_FROM + 1);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_DATA);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ /* Add for key sigs only */
+ assert_rnp_success(rnp_add_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_VERIFY_KEY,
+ MD5_FROM + 2,
+ RNP_SECURITY_DEFAULT));
+ flags = RNP_SECURITY_VERIFY_KEY;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, MD5_FROM + 2);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_KEY);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ /* Remove added two rules */
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_VERIFY_DATA,
+ MD5_FROM + 1,
+ &removed));
+ assert_int_equal(removed, 1);
+ assert_rnp_success(rnp_remove_security_rule(ffi,
+ RNP_FEATURE_HASH_ALG,
+ "MD5",
+ RNP_SECURITY_DEFAULT,
+ RNP_SECURITY_VERIFY_KEY,
+ MD5_FROM + 2,
+ &removed));
+ assert_int_equal(removed, 1);
+ /* Remove all */
+ removed = 0;
+ assert_rnp_failure(rnp_remove_security_rule(ffi, NULL, NULL, 0, 0x17, 0, &removed));
+ assert_rnp_success(rnp_remove_security_rule(ffi, NULL, NULL, 0, 0, 0, &removed));
+ assert_int_equal(removed, 3);
+ rnp_ffi_destroy(ffi);
+ rnp_ffi_create(&ffi, "GPG", "GPG");
+ /* Remove all rules for hash */
+ assert_rnp_failure(
+ rnp_remove_security_rule(ffi, RNP_FEATURE_SYMM_ALG, NULL, 0, 0, 0, &removed));
+ removed = 0;
+ assert_rnp_success(
+ rnp_remove_security_rule(ffi, RNP_FEATURE_HASH_ALG, NULL, 0, 0, 0, &removed));
+ assert_int_equal(removed, 3);
+ rnp_ffi_destroy(ffi);
+ rnp_ffi_create(&ffi, "GPG", "GPG");
+ /* Remove all rules for specific hash */
+ assert_rnp_success(rnp_remove_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "MD5", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed));
+ assert_int_equal(removed, 1);
+ assert_rnp_success(rnp_remove_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed));
+ assert_int_equal(removed, 2);
+ rnp_ffi_destroy(ffi);
+ rnp_ffi_create(&ffi, "GPG", "GPG");
+ /* SHA1 - ancient times */
+ from = 256;
+ flags = 0;
+ assert_rnp_success(
+ rnp_get_security_rule(ffi, RNP_FEATURE_HASH_ALG, "SHA1", 0, &flags, &from, &level));
+ assert_int_equal(from, 0);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ assert_int_equal(flags, 0);
+ /* SHA1 - now, data verify disabled, key sig verify is enabled */
+ flags = 0;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, SHA1_DATA_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_DATA);
+ flags = 0;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", SHA1_DATA_FROM - 1, &flags, &from, &level));
+ assert_int_equal(from, 0);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ flags = RNP_SECURITY_VERIFY_DATA;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, SHA1_DATA_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_DATA);
+ flags = RNP_SECURITY_VERIFY_KEY;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", time(NULL), &flags, &from, &level));
+ assert_int_equal(from, 0);
+ assert_int_equal(level, RNP_SECURITY_DEFAULT);
+ assert_int_equal(flags, 0);
+ flags = RNP_SECURITY_VERIFY_KEY;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", SHA1_KEY_FROM + 5, &flags, &from, &level));
+ assert_int_equal(from, SHA1_KEY_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_KEY);
+ flags = 0;
+ assert_rnp_success(rnp_get_security_rule(
+ ffi, RNP_FEATURE_HASH_ALG, "SHA1", SHA1_KEY_FROM + 5, &flags, &from, &level));
+ assert_int_equal(from, SHA1_KEY_FROM);
+ assert_int_equal(level, RNP_SECURITY_INSECURE);
+ assert_int_equal(flags, RNP_SECURITY_VERIFY_KEY);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_result_to_string)
+{
+ const char * result_string = NULL;
+ rnp_result_t code;
+ std::set<std::string> stringset;
+
+ result_string = rnp_result_to_string(RNP_SUCCESS);
+ assert_string_equal(result_string, "Success");
+
+ /* Cover all defined error code ranges,
+ * check that each defined
+ * code has corresponding unique string */
+
+ std::vector<std::pair<rnp_result_t, rnp_result_t>> error_codes = {
+ {RNP_ERROR_GENERIC, RNP_ERROR_NULL_POINTER},
+ {RNP_ERROR_ACCESS, RNP_ERROR_WRITE},
+ {RNP_ERROR_BAD_STATE, RNP_ERROR_SIGNATURE_UNKNOWN},
+ {RNP_ERROR_NOT_ENOUGH_DATA, RNP_ERROR_EOF}};
+
+ for (auto &range : error_codes) {
+ for (code = range.first; code <= range.second; code++) {
+ result_string = rnp_result_to_string(code);
+
+ assert_int_not_equal(strcmp("Unsupported error code", result_string), 0);
+
+ auto search = stringset.find(result_string);
+
+ /* Make sure returned error string is not already returned for other codes */
+ assert_true(search == stringset.end());
+
+ stringset.insert(result_string);
+ }
+ }
+}