summaryrefslogtreecommitdiffstats
path: root/src/tests/ffi-enc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/ffi-enc.cpp')
-rw-r--r--src/tests/ffi-enc.cpp1362
1 files changed, 1362 insertions, 0 deletions
diff --git a/src/tests/ffi-enc.cpp b/src/tests/ffi-enc.cpp
new file mode 100644
index 0000000..55b0d10
--- /dev/null
+++ b/src/tests/ffi-enc.cpp
@@ -0,0 +1,1362 @@
+/*
+ * Copyright (c) 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 <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 <vector>
+#include <string>
+#include "file-utils.h"
+#include <librepgp/stream-ctx.h>
+#include "pgp-key.h"
+#include "ffi-priv-types.h"
+
+static bool
+getpasscb_once(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ const char **pass = (const char **) app_ctx;
+ if (!*pass) {
+ return false;
+ }
+ size_t pass_len = strlen(*pass);
+ if (pass_len >= buf_len) {
+ return false;
+ }
+ memcpy(buf, *pass, pass_len);
+ *pass = NULL;
+ return true;
+}
+
+static bool
+getpasscb_inc(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ int * num = (int *) app_ctx;
+ std::string pass = "pass" + std::to_string(*num);
+ (*num)++;
+ strncpy(buf, pass.c_str(), buf_len - 1);
+ return true;
+}
+
+#define TBL_MAX_USERIDS 4
+typedef struct key_tbl_t {
+ const uint8_t *key_data;
+ size_t key_data_size;
+ bool secret;
+ const char * keyid;
+ const char * grip;
+ const char * userids[TBL_MAX_USERIDS + 1];
+} key_tbl_t;
+
+static void
+tbl_getkeycb(rnp_ffi_t ffi,
+ void * app_ctx,
+ const char *identifier_type,
+ const char *identifier,
+ bool secret)
+{
+ key_tbl_t *found = NULL;
+ for (key_tbl_t *tbl = (key_tbl_t *) app_ctx; tbl && tbl->key_data && !found; tbl++) {
+ if (tbl->secret != secret) {
+ continue;
+ }
+ if (!strcmp(identifier_type, "keyid") && !strcmp(identifier, tbl->keyid)) {
+ found = tbl;
+ break;
+ } else if (!strcmp(identifier_type, "grip") && !strcmp(identifier, tbl->grip)) {
+ found = tbl;
+ break;
+ } else if (!strcmp(identifier_type, "userid")) {
+ for (size_t i = 0; i < TBL_MAX_USERIDS; i++) {
+ if (!strcmp(identifier, tbl->userids[i])) {
+ found = tbl;
+ break;
+ }
+ }
+ }
+ }
+ if (found) {
+ char *format = NULL;
+ assert_rnp_success(
+ rnp_detect_key_format(found->key_data, found->key_data_size, &format));
+ assert_non_null(format);
+ uint32_t flags = secret ? RNP_LOAD_SAVE_SECRET_KEYS : RNP_LOAD_SAVE_PUBLIC_KEYS;
+ rnp_input_t input = NULL;
+ assert_rnp_success(
+ rnp_input_from_memory(&input, found->key_data, found->key_data_size, true));
+ assert_non_null(input);
+ assert_rnp_success(rnp_load_keys(ffi, format, input, flags));
+ free(format);
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pass)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ // 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", "data/keyrings/1/secring.gpg"));
+
+ // write out some data
+ str_to_file("plaintext", plaintext);
+ // create input+output w/ bad paths (should fail)
+ input = NULL;
+ assert_rnp_failure(rnp_input_from_path(&input, "noexist"));
+ assert_null(input);
+ assert_rnp_failure(rnp_output_to_path(&output, ""));
+ assert_null(output);
+
+ // 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_failure(rnp_op_encrypt_create(NULL, ffi, input, output));
+ assert_rnp_failure(rnp_op_encrypt_create(&op, NULL, input, output));
+ assert_rnp_failure(rnp_op_encrypt_create(&op, ffi, NULL, output));
+ assert_rnp_failure(rnp_op_encrypt_create(&op, ffi, input, NULL));
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add password (using all defaults)
+ assert_rnp_failure(rnp_op_encrypt_add_password(NULL, "pass1", NULL, 0, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "", NULL, 0, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "pass1", "WRONG", 0, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "pass1", NULL, 0, "WRONG"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass1", NULL, 0, NULL));
+ // add password
+ if (!sm2_enabled() && !twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "TWOFISH"));
+ assert_rnp_failure(
+ rnp_op_encrypt_add_password(op, "pass2", "SHA256", 12345, "TWOFISH"));
+ assert_rnp_success(
+ rnp_op_encrypt_add_password(op, "pass2", "SHA256", 12345, "BLOWFISH"));
+ } else if (!sm2_enabled() && twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "TWOFISH"));
+ assert_rnp_success(
+ rnp_op_encrypt_add_password(op, "pass2", "SHA256", 12345, "TWOFISH"));
+ } else if (sm2_enabled() && !twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "TWOFISH"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "BLOWFISH"));
+ } else {
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "TWOFISH"));
+ }
+ // set the data encryption cipher
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(NULL, "CAST5"));
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, NULL));
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "WRONG"));
+ if (cast5_enabled()) {
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ } else {
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES256"));
+ }
+ // 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;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ 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, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ 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);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (pass1)
+ 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_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ // decrypt (pass2)
+ 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 *) "pass2"));
+ 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_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pass_provider)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char *plaintext = "Data encrypted with password provided via password provider.";
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // write out some data
+ str_to_file("plaintext", plaintext);
+ // create input + output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add password with NULL password provider set - should fail
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, NULL, 0, NULL));
+ // add password with password provider set.
+ int pswdnum = 1;
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_inc, &pswdnum));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, NULL, 0, NULL));
+ // add another password with different encryption parameters
+ if (!sm2_enabled() && !twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, "TWOFISH"));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, "SHA256", 12345, "TWOFISH"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, NULL, 12345, NULL));
+ } else if (!sm2_enabled() && twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, "TWOFISH"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, "SHA256", 12345, "TWOFISH"));
+ } else if (sm2_enabled() && !twofish_enabled()) {
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, "TWOFISH"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, NULL));
+ } else {
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, "TWOFISH"));
+ }
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAMELLIA256"));
+ // 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;
+
+ /* decrypt with pass1 */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass1"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ /* decrypt with pass2 via provider */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ pswdnum = 2;
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_inc, &pswdnum));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_set_cipher)
+{
+ /* setup FFI */
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ /* create input + output */
+ rnp_input_t input = NULL;
+ const char *plaintext = "Data encrypted with password using different CEK/KEK.";
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) plaintext, strlen(plaintext), false));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ /* create encrypt operation */
+ rnp_op_encrypt_t op = NULL;
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ /* use different sym algos */
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "password1", NULL, 0, "AES192"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "password2", NULL, 0, "AES128"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES256"));
+ /* execute the operation */
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ assert_true(rnp_file_exists("encrypted"));
+ /* cleanup */
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ /* decrypt with password1 */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password1"));
+ rnp_op_verify_t verify;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ /* Check protection info */
+ char *mode = NULL;
+ char *cipher = NULL;
+ bool 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);
+ /* Check SESKs */
+ size_t count = 0;
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 2);
+ /* First SESK: AES192 */
+ rnp_symenc_handle_t symenc = NULL;
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ char *aalg = NULL;
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aalg));
+ assert_string_equal(aalg, "None");
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES192");
+ rnp_buffer_destroy(aalg);
+ rnp_buffer_destroy(cipher);
+ /* Second SESK: AES128 */
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 1, &symenc));
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aalg));
+ assert_string_equal(aalg, "None");
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES128");
+ rnp_buffer_destroy(aalg);
+ rnp_buffer_destroy(cipher);
+ unlink("decrypted");
+ unlink("encrypted");
+ rnp_op_verify_destroy(verify);
+
+ /* Now use AEAD */
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (const uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted-aead"));
+ /* create encrypt operation */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ /* use different sym algos */
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "password1", NULL, 0, "AES256"));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "password2", NULL, 0, "AES192"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES128"));
+ assert_rnp_success(rnp_op_encrypt_set_aead(op, "OCB"));
+ /* execute the operation */
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ assert_true(rnp_file_exists("encrypted-aead"));
+ /* cleanup */
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ /* decrypt with password2 */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted-aead"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password2"));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ /* Check protection info */
+ assert_rnp_success(rnp_op_verify_get_protection_info(verify, &mode, &cipher, &valid));
+ assert_string_equal(mode, "aead-ocb");
+ assert_string_equal(cipher, "AES128");
+ assert_true(valid);
+ rnp_buffer_destroy(mode);
+ rnp_buffer_destroy(cipher);
+ /* Check SESKs */
+ assert_rnp_success(rnp_op_verify_get_symenc_count(verify, &count));
+ assert_int_equal(count, 2);
+ /* First SESK: AES192 */
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 0, &symenc));
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aalg));
+ assert_string_equal(aalg, "OCB");
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES256");
+ rnp_buffer_destroy(aalg);
+ rnp_buffer_destroy(cipher);
+ /* Second SESK: AES128 */
+ assert_rnp_success(rnp_op_verify_get_symenc_at(verify, 1, &symenc));
+ assert_rnp_success(rnp_symenc_get_aead_alg(symenc, &aalg));
+ assert_string_equal(aalg, "OCB");
+ assert_rnp_success(rnp_symenc_get_cipher(symenc, &cipher));
+ assert_string_equal(cipher, "AES192");
+ rnp_buffer_destroy(aalg);
+ rnp_buffer_destroy(cipher);
+ unlink("decrypted");
+ unlink("encrypted-aead");
+ rnp_op_verify_destroy(verify);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ // 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", "data/keyrings/1/secring.gpg"));
+
+ // 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));
+ // add recipients
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_failure(rnp_op_encrypt_add_recipient(NULL, key));
+ assert_rnp_failure(rnp_op_encrypt_add_recipient(op, NULL));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set the data encryption cipher
+ if (cast5_enabled()) {
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ } else {
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES256"));
+ }
+ // 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;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ 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, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ 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);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // 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 *) "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // read in the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+bool
+first_key_password_provider(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ if (!key) {
+ throw std::invalid_argument("key");
+ }
+ char *keyid = NULL;
+ rnp_key_get_keyid(key, &keyid);
+ if (strcmp(keyid, "8A05B89FAD5ADED1")) {
+ throw std::invalid_argument("keyid");
+ }
+ rnp_buffer_destroy(keyid);
+ return false;
+}
+
+TEST_F(rnp_tests, test_ffi_decrypt_pk_unlocked)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ // 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", "data/keyrings/1/secring.gpg"));
+
+ // write out some data
+ str_to_file("plaintext", plaintext);
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add recipients
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ // 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));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+
+ /* decrypt (unlocked first key, no pass provider) */
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ rnp_key_handle_t defkey = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_key_get_default_key(key, "encrypt", 0, &defkey));
+ assert_non_null(defkey);
+ assert_rnp_success(rnp_key_unlock(defkey, "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_key_lock(defkey));
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(defkey);
+ // cleanup
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ assert_int_equal(unlink("decrypted"), 0);
+
+ /* decrypt (unlocked second key, no pass provider) */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_key_get_default_key(key, "encrypt", 0, &defkey));
+ assert_non_null(defkey);
+ assert_rnp_success(rnp_key_unlock(defkey, "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_key_lock(defkey));
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(defkey);
+ // cleanup
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ assert_int_equal(unlink("decrypted"), 0);
+
+ /* decrypt (unlocked first key, pass provider should not be called) */
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, ffi_asserting_password_provider, NULL));
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_key_get_default_key(key, "encrypt", 0, &defkey));
+ assert_non_null(defkey);
+ assert_rnp_success(rnp_key_unlock(defkey, "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_key_lock(defkey));
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(defkey);
+ // cleanup
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ assert_int_equal(unlink("decrypted"), 0);
+
+ /* decrypt (unlocked second key, pass provider should not be called) */
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, first_key_password_provider, NULL));
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_key_get_default_key(key, "encrypt", 0, &defkey));
+ assert_non_null(defkey);
+ assert_rnp_success(rnp_key_unlock(defkey, "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_key_lock(defkey));
+ rnp_key_handle_destroy(key);
+ rnp_key_handle_destroy(defkey);
+ // cleanup
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ assert_int_equal(unlink("decrypted"), 0);
+
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk_key_provider)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+ uint8_t * primary_sec_key_data = NULL;
+ size_t primary_sec_size = 0;
+ uint8_t * sub_sec_key_data = NULL;
+ size_t sub_sec_size = 0;
+
+ /* first, let's generate some encrypted data */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_non_null(ffi);
+ // load our keyrings
+ assert_true(
+ load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg", "data/keyrings/1/secring.gpg"));
+ // 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));
+ // add recipient 1
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ // cleanup
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // add recipient 2
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ // save the primary key data for later
+ assert_rnp_success(rnp_get_secret_key_data(key, &primary_sec_key_data, &primary_sec_size));
+ assert_non_null(primary_sec_key_data);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // save the appropriate encrypting subkey for the key provider to use during decryption
+ // later
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8A05B89FAD5ADED1", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_get_secret_key_data(key, &sub_sec_key_data, &sub_sec_size));
+ assert_non_null(sub_sec_key_data);
+ // cleanup
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // set the data encryption cipher
+ if (cast5_enabled()) {
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ } else {
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES256"));
+ }
+ // 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;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+ ffi = NULL;
+
+ /* decrypt */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load the primary
+ input = NULL;
+ assert_rnp_success(
+ rnp_input_from_memory(&input, primary_sec_key_data, primary_sec_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;
+
+ // decrypt (no key to decrypt, should fail)
+ 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_int_equal(RNP_ERROR_NO_SUITABLE_KEY, rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // key_data key_data_size secret keyid grip userids
+ const key_tbl_t keydb[] = {
+ {sub_sec_key_data, sub_sec_size, true, "8A05B89FAD5ADED1", NULL, {NULL}}, {0}};
+
+ // decrypt
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ 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_key_provider(ffi, tbl_getkeycb, (void *) keydb));
+ 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_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+ free(sub_sec_key_data);
+ free(primary_sec_key_data);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_and_sign)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ rnp_op_sign_signature_t signsig = NULL;
+ const char * plaintext = "data1";
+ rnp_key_handle_t key = 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
+
+ // 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", "data/keyrings/1/secring.gpg"));
+
+ // 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));
+ // add recipients
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set the data encryption cipher
+ if (cast5_enabled()) {
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ } else {
+ assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "AES256"));
+ }
+ // enable armoring
+ assert_rnp_failure(rnp_op_encrypt_set_armor(NULL, true));
+ assert_rnp_success(rnp_op_encrypt_set_armor(op, true));
+ // add signature
+ assert_rnp_failure(rnp_op_encrypt_set_hash(NULL, "SHA256"));
+ assert_rnp_failure(rnp_op_encrypt_set_hash(op, NULL));
+ assert_rnp_failure(rnp_op_encrypt_set_hash(op, "WRONG"));
+ assert_rnp_success(rnp_op_encrypt_set_hash(op, "SHA1"));
+ assert_rnp_failure(rnp_op_encrypt_set_creation_time(NULL, 0));
+ assert_rnp_success(rnp_op_encrypt_set_creation_time(op, 0));
+ assert_rnp_failure(rnp_op_encrypt_set_expiration_time(NULL, 0));
+ assert_rnp_success(rnp_op_encrypt_set_expiration_time(op, 0));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_failure(rnp_op_encrypt_add_signature(NULL, key, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_signature(op, NULL, NULL));
+ assert_rnp_success(rnp_op_encrypt_add_signature(op, key, NULL));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // attempt to add signature from the public key
+ assert_true(import_pub_keys(ffi, "data/test_stream_key_load/ecc-p256-pub.asc"));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &key));
+ assert_rnp_failure(rnp_op_encrypt_add_signature(op, key, &signsig));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // attempt to add signature by the offline secret key
+ assert_true(
+ import_pub_keys(ffi, "data/test_key_edge_cases/alice-s2k-101-no-sign-sub.pgp"));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "0451409669ffde3c", &key));
+ assert_rnp_failure(rnp_op_encrypt_add_signature(op, key, &signsig));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // add second signature with different hash/issued/expiration
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_signature(op, key, &signsig));
+ assert_rnp_success(rnp_op_sign_signature_set_creation_time(signsig, issued2));
+ assert_rnp_success(rnp_op_sign_signature_set_expiration_time(signsig, expires2));
+ assert_rnp_failure(rnp_op_sign_signature_set_hash(signsig, NULL));
+ assert_rnp_failure(rnp_op_sign_signature_set_hash(NULL, "SHA512"));
+ assert_rnp_failure(rnp_op_sign_signature_set_hash(signsig, "UNKNOWN"));
+ assert_rnp_success(rnp_op_sign_signature_set_hash(signsig, "SHA512"));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set default sig parameters after the signature is added - those should be picked up
+ assert_rnp_success(rnp_op_encrypt_set_hash(op, "SHA256"));
+ assert_rnp_success(rnp_op_encrypt_set_creation_time(op, issued));
+ assert_rnp_success(rnp_op_encrypt_set_expiration_time(op, expires));
+ // execute the operation
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+
+ // check whether keys are locked
+ rnp_identifier_iterator_t it = NULL;
+ assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
+ const char *fprint = NULL;
+ while (!rnp_identifier_iterator_next(it, &fprint)) {
+ if (!fprint) {
+ break;
+ }
+ SCOPED_TRACE(fprint);
+ rnp_key_handle_t skey = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "fingerprint", fprint, &skey));
+ bool secret = true;
+ assert_rnp_success(rnp_key_have_secret(skey, &secret));
+ if (secret) {
+ bool locked = false;
+ assert_rnp_success(rnp_key_is_locked(skey, &locked));
+ assert_true(locked);
+ }
+ rnp_key_handle_destroy(skey);
+ }
+ rnp_identifier_iterator_destroy(it);
+
+ // 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;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ 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, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ 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);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // 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 *) "password"));
+ 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_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // verify and check signatures
+ rnp_op_verify_t verify;
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "verified"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ rnp_op_verify_signature_t sig;
+ size_t sig_count;
+ uint32_t sig_create;
+ uint32_t sig_expires;
+ char * hname = NULL;
+
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 2);
+ // signature 1
+ 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);
+ hname = NULL;
+ // signature 2
+ 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);
+ hname = NULL;
+ // make sure keys are locked
+ assert_rnp_success(rnp_identifier_iterator_create(ffi, &it, "fingerprint"));
+ while (!rnp_identifier_iterator_next(it, &fprint)) {
+ if (!fprint) {
+ break;
+ }
+ SCOPED_TRACE(fprint);
+ rnp_key_handle_t skey = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "fingerprint", fprint, &skey));
+ bool secret = true;
+ assert_rnp_success(rnp_key_have_secret(skey, &secret));
+ if (secret) {
+ bool locked = false;
+ assert_rnp_success(rnp_key_is_locked(skey, &locked));
+ assert_true(locked);
+ }
+ rnp_key_handle_destroy(skey);
+ }
+ rnp_identifier_iterator_destroy(it);
+ // cleanup
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("verified").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk_subkey_selection)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ /* check whether a latest subkey is selected for encryption */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ /* case 1: three encryption subkeys, second expired, third has later creation time */
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/key0-sub02.pgp"));
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid0", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ /* get output */
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, true));
+ assert_true(buf && len);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ rnp_op_encrypt_destroy(op);
+ /* decrypt */
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_input_from_memory(&input, buf, len, true));
+ rnp_buffer_destroy(buf);
+ 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));
+
+ /* check whether we used correct subkey */
+ size_t count = 0;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ rnp_recipient_handle_t recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ char *keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* case 2: only subkeys 1-2, make sure that latest but expired subkey is not selected */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/key0-sub01.pgp"));
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ /* get output */
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, true));
+ assert_true(buf && len);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ rnp_op_encrypt_destroy(op);
+ /* decrypt */
+ assert_true(load_keys_gpg(ffi, "", "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_input_from_memory(&input, buf, len, true));
+ rnp_buffer_destroy(buf);
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+
+ /* check whether we used correct subkey */
+ count = 0;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* case 3: only expired subkey, make sure encryption operation fails */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ assert_true(load_keys_gpg(ffi, "data/test_stream_key_load/key0-sub1.pgp"));
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_int_equal(rnp_op_encrypt_add_recipient(op, key), RNP_ERROR_NO_SUITABLE_KEY);
+ rnp_key_handle_destroy(key);
+ assert_rnp_failure(rnp_op_encrypt_execute(op));
+ rnp_op_encrypt_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_decrypt_small_rsa)
+{
+ rnp_ffi_t ffi = NULL;
+ const char *plaintext = "data1";
+
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(import_all_keys(ffi, "data/test_key_validity/rsa_key_small_sig-sec.asc"));
+ rnp_input_t input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/data.enc.small-rsa"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ size_t len = 0;
+ uint8_t *buf = NULL;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, false));
+ assert_int_equal(len, 5);
+ assert_int_equal(memcmp(plaintext, buf, 5), 0);
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_decrypt_small_eg)
+{
+ /* make sure unlock and decrypt fails with invalid key */
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(
+ import_all_keys(ffi, "data/test_key_edge_cases/key-eg-small-subgroup-sec.pgp"));
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "3b8dda452b9f69b4", &key));
+ assert_non_null(key);
+ /* key is not encrypted */
+ assert_rnp_success(rnp_key_unlock(key, NULL));
+ rnp_key_handle_destroy(key);
+ rnp_input_t input = NULL;
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-eg-bad"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ rnp_ffi_destroy(ffi);
+ /* make sure unlock and decrypt fails with invalid encrypted key */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_true(
+ import_all_keys(ffi, "data/test_key_edge_cases/key-eg-small-subgroup-sec-enc.pgp"));
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "3b072c3bb2d1a8b2", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_key_unlock(key, "password"));
+ assert_rnp_success(rnp_key_lock(key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_messages/message.txt.enc-eg-bad2"));
+ assert_rnp_success(rnp_output_to_null(&output));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_no_wrap)
+{
+ rnp_ffi_t ffi = NULL;
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_true(
+ load_keys_gpg(ffi, "data/keyrings/1/pubring.gpg", "data/keyrings/1/secring.gpg"));
+
+ rnp_input_t input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_messages/message.txt.signed"));
+ rnp_output_t output = NULL;
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ rnp_op_encrypt_t op = NULL;
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ /* set nowrap flag */
+ assert_rnp_failure(rnp_op_encrypt_set_flags(NULL, RNP_ENCRYPT_NOWRAP));
+ assert_rnp_failure(rnp_op_encrypt_set_flags(op, 17));
+ assert_rnp_success(rnp_op_encrypt_set_flags(op, RNP_ENCRYPT_NOWRAP));
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+
+ assert_rnp_success(rnp_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+
+ /* decrypt via rnp_decrypt() */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(),
+ file_to_str("data/test_messages/message.txt").c_str());
+ unlink("decrypted");
+
+ /* decrypt and verify signatures */
+ rnp_op_verify_t verify;
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "verified"));
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ /* check signature */
+ 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);
+ 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_input_destroy(input));
+ assert_rnp_success(rnp_output_destroy(output));
+ rnp_op_verify_destroy(verify);
+ assert_string_equal(file_to_str("verified").c_str(),
+ file_to_str("data/test_messages/message.txt").c_str());
+ unlink("verified");
+
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}