summaryrefslogtreecommitdiffstats
path: root/src/plugins/mail-crypt/test-mail-key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/mail-crypt/test-mail-key.c')
-rw-r--r--src/plugins/mail-crypt/test-mail-key.c424
1 files changed, 424 insertions, 0 deletions
diff --git a/src/plugins/mail-crypt/test-mail-key.c b/src/plugins/mail-crypt/test-mail-key.c
new file mode 100644
index 0000000..ac89835
--- /dev/null
+++ b/src/plugins/mail-crypt/test-mail-key.c
@@ -0,0 +1,424 @@
+/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "hex-binary.h"
+#include "master-service.h"
+#include "test-mail-storage-common.h"
+#include "dcrypt.h"
+
+#include "mail-crypt-common.h"
+#include "mail-crypt-key.h"
+#include "mail-crypt-plugin.h"
+
+static const char *mcp_old_user_key = "1\t716\t0\t048FD04FD3612B22D32790C592CF21CEF417EFD2EA34AE5F688FA5B51BED29E05A308B68DA78E16E90B47A11E133BD9A208A2894FD01B0BEE865CE339EA3FB17AC\td0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0";
+static const char *mcp_old_user_key_id = "d0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0";
+static const char *mcp_old_box_key = "1\t716\t1\t0567e6bf9579813ae967314423b0fceb14bda24749303923de9a9bb9370e0026f995901a57e63113eeb2baf0c940e978d00686cbb52bd5014bc318563375876255\t0300E46DA2125427BE968EB3B649910CDC4C405E5FFDE18D433A97CABFEE28CEEFAE9EE356C792004FFB80981D67E741B8CC036A34235A8D2E1F98D1658CFC963D07EB\td0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0\t7c9a1039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00fa4f";
+static const char *mcp_old_box_key_id = "7c9a1039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00fa4f";
+
+static struct test_mail_storage_ctx *test_ctx;
+static const char *test_user_key_id;
+static const char *test_box_key_id;
+
+static struct mail_crypt_user mail_crypt_user;
+
+struct mail_crypt_user *mail_crypt_get_mail_crypt_user(struct mail_user *user ATTR_UNUSED)
+{
+ return &mail_crypt_user;
+}
+
+static
+int test_mail_attribute_get(struct mailbox *box, bool user_key, bool shared,
+ const char *pubid, const char **value_r, const char **error_r)
+{
+ const char *attr_name;
+ enum mail_attribute_type attr_type;
+
+ if (strcmp(pubid, ACTIVE_KEY_NAME) == 0) {
+ attr_name = user_key ? USER_CRYPT_PREFIX ACTIVE_KEY_NAME :
+ BOX_CRYPT_PREFIX ACTIVE_KEY_NAME;
+ attr_type = MAIL_ATTRIBUTE_TYPE_SHARED;
+ } else {
+ attr_name = t_strdup_printf("%s%s%s",
+ user_key ? USER_CRYPT_PREFIX :
+ BOX_CRYPT_PREFIX,
+ shared ? PUBKEYS_PREFIX :
+ PRIVKEYS_PREFIX,
+ pubid);
+ attr_type = shared ? MAIL_ATTRIBUTE_TYPE_SHARED : MAIL_ATTRIBUTE_TYPE_PRIVATE;
+ }
+ struct mail_attribute_value value;
+
+ int ret;
+
+ if ((ret = mailbox_attribute_get(box, attr_type,
+ attr_name, &value)) <= 0) {
+ if (ret < 0) {
+ *error_r = t_strdup_printf("mailbox_attribute_get(%s, %s) failed: %s",
+ mailbox_get_vname(box),
+ attr_name,
+ mailbox_get_last_internal_error(box, NULL));
+ }
+ } else {
+ *value_r = t_strdup(value.value);
+ }
+ return ret;
+}
+
+static int
+test_mail_attribute_set(struct mailbox_transaction_context *t,
+ bool user_key, bool shared, const char *pubid,
+ const char *value, const char **error_r)
+{
+ const char *attr_name;
+ enum mail_attribute_type attr_type;
+
+ if (strcmp(pubid, ACTIVE_KEY_NAME) == 0) {
+ attr_name = user_key ? USER_CRYPT_PREFIX ACTIVE_KEY_NAME :
+ BOX_CRYPT_PREFIX ACTIVE_KEY_NAME;
+ attr_type = MAIL_ATTRIBUTE_TYPE_SHARED;
+ } else {
+ attr_name = t_strdup_printf("%s%s%s",
+ user_key ? USER_CRYPT_PREFIX :
+ BOX_CRYPT_PREFIX,
+ shared ? PUBKEYS_PREFIX :
+ PRIVKEYS_PREFIX,
+ pubid);
+ attr_type = shared ? MAIL_ATTRIBUTE_TYPE_SHARED : MAIL_ATTRIBUTE_TYPE_PRIVATE;
+ }
+
+ struct mail_attribute_value attr_value;
+
+ int ret;
+
+ i_zero(&attr_value);
+ attr_value.value = value;
+
+ if ((ret = mailbox_attribute_set(t, attr_type,
+ attr_name, &attr_value)) <= 0) {
+ if (ret < 0) {
+ *error_r = t_strdup_printf("mailbox_attribute_set(%s, %s) failed: %s",
+ mailbox_get_vname(mailbox_transaction_get_mailbox(t)),
+ attr_name,
+ mailbox_get_last_internal_error(mailbox_transaction_get_mailbox(t), NULL));
+ }
+ }
+
+ return ret;
+}
+
+
+static void test_generate_user_key(void)
+{
+ struct dcrypt_keypair pair;
+ const char *pubid;
+ const char *error = NULL;
+
+ test_begin("generate user key");
+
+ /* try to generate a keypair for user */
+ if (mail_crypt_user_generate_keypair(test_ctx->user, &pair,
+ &pubid, &error) < 0) {
+ i_error("generate_keypair failed: %s", error);
+ test_exit(1);
+ }
+
+ test_assert(pubid != NULL);
+
+ test_user_key_id = p_strdup(test_ctx->pool, pubid);
+
+ dcrypt_keypair_unref(&pair);
+ error = NULL;
+
+ /* keys ought to be in cache or somewhere...*/
+ if (mail_crypt_user_get_private_key(test_ctx->user, NULL, &pair.priv, &error) <= 0)
+ {
+ i_error("Cannot get user private key: %s", error);
+ }
+
+ test_assert(pair.priv != NULL);
+
+ if (pair.priv != NULL)
+ dcrypt_key_unref_private(&pair.priv);
+
+ test_end();
+}
+
+static void test_generate_inbox_key(void)
+{
+ struct dcrypt_public_key *user_key;
+ struct dcrypt_keypair pair;
+ const char *error = NULL, *pubid = NULL;
+
+ test_begin("generate inbox key");
+
+ if (mail_crypt_user_get_public_key(test_ctx->user, &user_key,
+ &error) <= 0) {
+ i_error("Cannot get user private key: %s", error);
+ }
+ struct mail_namespace *ns =
+ mail_namespace_find_inbox(test_ctx->user->namespaces);
+ struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
+ MAILBOX_FLAG_READONLY);
+ if (mailbox_open(box) < 0)
+ i_fatal("mailbox_open(INBOX) failed: %s",
+ mailbox_get_last_internal_error(box, NULL));
+ if (mail_crypt_box_generate_keypair(box, &pair, user_key, &pubid,
+ &error) < 0) {
+ i_error("generate_keypair failed: %s", error);
+ test_exit(1);
+ }
+
+ i_assert(pubid != NULL);
+
+ dcrypt_keypair_unref(&pair);
+ dcrypt_key_unref_public(&user_key);
+ mailbox_free(&box);
+
+ test_box_key_id = p_strdup(test_ctx->pool, pubid);
+
+ test_end();
+}
+
+static void test_cache_reset(void)
+{
+ struct dcrypt_keypair pair;
+ const char *error = NULL;
+
+ test_begin("cache reset");
+
+ struct mail_crypt_user *muser =
+ mail_crypt_get_mail_crypt_user(test_ctx->user);
+ mail_crypt_key_cache_destroy(&muser->key_cache);
+
+ test_assert(mail_crypt_user_get_private_key(test_ctx->user, NULL,
+ &pair.priv, &error) > 0);
+ if (error != NULL)
+ i_error("mail_crypt_user_get_private_key() failed: %s", error);
+ error = NULL;
+ test_assert(mail_crypt_user_get_public_key(test_ctx->user,
+ &pair.pub, &error) > 0);
+ if (error != NULL)
+ i_error("mail_crypt_user_get_public_key() failed: %s", error);
+
+ dcrypt_keypair_unref(&pair);
+
+ test_end();
+}
+
+static void test_verify_keys(void)
+{
+ const char *value = "", *error = NULL;
+
+ const char *enc_id;
+ enum dcrypt_key_encryption_type enc_type;
+
+ test_begin("verify keys");
+
+ struct dcrypt_private_key *privkey = NULL, *user_key = NULL;
+ struct dcrypt_public_key *pubkey = NULL;
+
+ struct mail_namespace *ns =
+ mail_namespace_find_inbox(test_ctx->user->namespaces);
+ struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
+ MAILBOX_FLAG_READONLY);
+ if (mailbox_open(box) < 0)
+ i_fatal("mailbox_open(INBOX) failed: %s",
+ mailbox_get_last_internal_error(box, NULL));
+ /* verify links */
+
+ /* user's public key */
+ test_assert(test_mail_attribute_get(box, TRUE, TRUE, ACTIVE_KEY_NAME,
+ &value, &error) > 0);
+ test_assert(strcmp(value, test_user_key_id) == 0);
+
+ test_assert(test_mail_attribute_get(box, TRUE, TRUE, value, &value,
+ &error) > 0);
+
+ /* load key */
+ test_assert(dcrypt_key_load_public(&pubkey, value, &error) == TRUE);
+
+ /* see if it matches */
+ test_assert(mail_crypt_public_key_id_match(pubkey, test_user_key_id,
+ &error) > 0);
+ dcrypt_key_unref_public(&pubkey);
+
+ /* user's private key */
+ test_assert(test_mail_attribute_get(box, TRUE, FALSE, ACTIVE_KEY_NAME,
+ &value, &error) > 0);
+ test_assert(strcmp(value, test_user_key_id) == 0);
+
+ test_assert(test_mail_attribute_get(box, TRUE, FALSE, value, &value,
+ &error) > 0);
+
+ /* load key */
+ test_assert(dcrypt_key_load_private(&user_key, value, NULL, NULL,
+ &error) == TRUE);
+
+ /* see if it matches */
+ test_assert(mail_crypt_private_key_id_match(user_key, test_user_key_id,
+ &error) > 0);
+
+
+
+
+ /* inbox's public key */
+ test_assert(test_mail_attribute_get(box, FALSE, TRUE, ACTIVE_KEY_NAME,
+ &value, &error) > 0);
+ test_assert(strcmp(value, test_box_key_id) == 0);
+
+ test_assert(test_mail_attribute_get(box, FALSE, TRUE, value, &value,
+ &error) > 0);
+
+ /* load key */
+ test_assert(dcrypt_key_load_public(&pubkey, value, &error) == TRUE);
+
+ /* see if it matches */
+ test_assert(mail_crypt_public_key_id_match(pubkey, test_box_key_id,
+ &error) > 0);
+ dcrypt_key_unref_public(&pubkey);
+
+ /* user's private key */
+ test_assert(test_mail_attribute_get(box, FALSE, FALSE, ACTIVE_KEY_NAME,
+ &value, &error) > 0);
+ test_assert(strcmp(value, test_box_key_id) == 0);
+
+ test_assert(test_mail_attribute_get(box, FALSE, FALSE, value, &value,
+ &error) > 0);
+
+ test_assert(dcrypt_key_string_get_info(value, NULL, NULL, NULL,
+ &enc_type, &enc_id, NULL,
+ &error) == TRUE);
+
+ test_assert(enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_KEY);
+ test_assert(strcmp(enc_id, test_user_key_id) == 0);
+
+ /* load key */
+ test_assert(dcrypt_key_load_private(&privkey, value, NULL, user_key,
+ &error) == TRUE);
+
+ /* see if it matches */
+ test_assert(mail_crypt_private_key_id_match(privkey, test_box_key_id,
+ &error) > 0);
+ dcrypt_key_unref_private(&privkey);
+ dcrypt_key_unref_private(&user_key);
+
+ mailbox_free(&box);
+
+ test_end();
+}
+
+static void test_old_key(void)
+{
+ test_begin("old keys");
+
+ const char *error = NULL;
+ struct dcrypt_private_key *privkey = NULL;
+
+ struct mail_namespace *ns =
+ mail_namespace_find_inbox(test_ctx->user->namespaces);
+ struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
+ MAILBOX_FLAG_READONLY);
+ if (mailbox_open(box) < 0)
+ i_fatal("mailbox_open(INBOX) failed: %s",
+ mailbox_get_last_internal_error(box, NULL));
+
+ struct mailbox_transaction_context *t =
+ mailbox_transaction_begin(box, 0, __func__);
+
+ test_mail_attribute_set(t, TRUE, FALSE, mcp_old_user_key_id,
+ mcp_old_user_key, &error);
+ test_mail_attribute_set(t, FALSE, FALSE, mcp_old_box_key_id,
+ mcp_old_box_key, &error);
+
+ (void)mailbox_transaction_commit(&t);
+
+ error = NULL;
+
+ /* try to load old key */
+ test_assert(mail_crypt_get_private_key(box, mcp_old_box_key_id, FALSE, FALSE,
+ &privkey, &error) > 0);
+
+ if (error != NULL)
+ i_error("mail_crypt_get_private_key(%s) failed: %s",
+ mcp_old_box_key_id,
+ error);
+
+ test_assert(privkey != NULL);
+
+ if (privkey != NULL) {
+ buffer_t *key_id = t_buffer_create(32);
+ test_assert(dcrypt_key_id_private_old(privkey, key_id, &error));
+ test_assert(strcmp(binary_to_hex(key_id->data, key_id->used), mcp_old_box_key_id) == 0);
+ dcrypt_key_unref_private(&privkey);
+ }
+
+ mailbox_free(&box);
+
+ test_end();
+}
+
+static void test_setup(void)
+{
+ struct dcrypt_settings set = {
+ .module_dir = top_builddir "/src/lib-dcrypt/.libs"
+ };
+ if (!dcrypt_initialize(NULL, &set, NULL)) {
+ i_info("No functional dcrypt backend found - skipping tests");
+ test_exit(0);
+ }
+ test_ctx = test_mail_storage_init();
+ const char *username = "mcp_test@example.com";
+ const char *const extra_input[] = {
+ t_strdup_printf("mail_crypt_curve=prime256v1"),
+ t_strdup_printf("mail_attribute_dict=file:%s/%s/dovecot-attributes",
+ test_ctx->home_root, username),
+ NULL
+ };
+ struct test_mail_storage_settings storage_set = {
+ .username = username,
+ .driver = "maildir",
+ .hierarchy_sep = "/",
+ .extra_input = extra_input,
+ };
+ test_mail_storage_init_user(test_ctx, &storage_set);
+
+ mail_crypt_key_register_mailbox_internal_attributes();
+}
+
+static void test_teardown(void)
+{
+ struct mail_crypt_user *muser =
+ mail_crypt_get_mail_crypt_user(test_ctx->user);
+ mail_crypt_key_cache_destroy(&muser->key_cache);
+
+ test_mail_storage_deinit_user(test_ctx);
+ test_mail_storage_deinit(&test_ctx);
+ dcrypt_deinitialize();
+}
+
+int main(int argc, char **argv)
+{
+ void (*tests[])(void) = {
+ test_setup,
+ test_generate_user_key,
+ test_generate_inbox_key,
+ test_cache_reset,
+ test_verify_keys,
+ test_old_key,
+ test_teardown,
+ NULL
+ };
+
+
+ master_service = master_service_init("test-mail-key",
+ MASTER_SERVICE_FLAG_STANDALONE |
+ MASTER_SERVICE_FLAG_DONT_SEND_STATS |
+ MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS |
+ MASTER_SERVICE_FLAG_NO_SSL_INIT |
+ MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME,
+ &argc, &argv, "");
+ int ret = test_run(tests);
+ master_service_deinit(&master_service);
+ return ret;
+}