Revision control
Copy as Markdown
Other Tools
/*
* 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"));
const char *alg = blowfish_enabled() ? "BLOWFISH" : "AES256";
assert_rnp_success(rnp_op_encrypt_add_password(op, "pass2", "SHA256", 12345, alg));
} 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"));
const char *alg = blowfish_enabled() ? "BLOWFISH" : "AES256";
assert_rnp_success(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, alg));
} 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);
}
static 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);
}
TEST_F(rnp_tests, test_ffi_mimemode_signature)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_true(import_pub_keys(ffi, "data/test_stream_key_load/ecc-25519-pub.asc"));
rnp_input_t input = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_messages/message.txt.signed-mimemode"));
rnp_output_t output = NULL;
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));
size_t sigcount = 255;
assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sigcount));
assert_int_equal(sigcount, 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));
rnp_op_verify_destroy(verify);
rnp_input_destroy(input);
rnp_output_destroy(output);
rnp_ffi_destroy(ffi);
}