bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "lib.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "str.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "dict.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "array.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "var-expand.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-storage.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mailbox-attribute.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-common.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-key.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-plugin.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-user.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "hex-binary.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "safe-memset.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "base64.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "sha2.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistruct mail_crypt_key_cache_entry {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_key_cache_entry *next;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *pubid;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* this is lazily initialized */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair pair;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_get_key_cache(struct mail_crypt_key_cache_entry *cache,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **privkey_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key **pubkey_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi for(struct mail_crypt_key_cache_entry *ent = cache;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent != NULL; ent = ent->next)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, ent->pubid) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (privkey_r != NULL && ent->pair.priv != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_private(ent->pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *privkey_r = ent->pair.priv;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (pubkey_r != NULL && ent->pair.pub != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_public(ent->pair.pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *pubkey_r = ent->pair.pub;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((privkey_r == NULL && pubkey_r == NULL) ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (ent->pair.priv == NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pair.pub == NULL)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_unreached();
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_put_key_cache(struct mail_crypt_key_cache_entry **cache,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *privkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *pubkey)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi for(struct mail_crypt_key_cache_entry *ent = *cache;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent != NULL; ent = ent->next)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, ent->pubid) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (privkey != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ent->pair.priv == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pair.priv = privkey;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_private(ent->pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (pubkey != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ent->pair.pub == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pair.pub = pubkey;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_public(ent->pair.pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_unreached();
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* not found */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_key_cache_entry *ent =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_new(struct mail_crypt_key_cache_entry, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pubid = i_strdup(pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pair.priv = privkey;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->pair.pub = pubkey;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ent->pair.priv != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_private(ent->pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ent->pair.pub != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_public(ent->pair.pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (*cache == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *cache = ent;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ent->next = *cache;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *cache = ent;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_key_cache_destroy(struct mail_crypt_key_cache_entry **cache)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_key_cache_entry *next, *cur = *cache;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *cache = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while(cur != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi next = cur->next;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(cur->pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (cur->pair.priv != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&cur->pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (cur->pair.pub != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_public(&cur->pair.pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(cur);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi cur = next;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_private_key_id_match(struct dcrypt_private_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid, const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *key_id = t_str_new(MAIL_CRYPT_HASH_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_private(key, MAIL_CRYPT_KEY_ID_ALGORITHM, key_id,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *hash = binary_to_hex(key_id->data, key_id->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, hash) == 0) return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_set_used_size(key_id, 0);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_private_old(key, key_id, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hash = binary_to_hex(key_id->data, key_id->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, hash) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Key %s does not match given ID %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hash, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_public_key_id_match(struct dcrypt_public_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid, const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *key_id = t_str_new(MAIL_CRYPT_HASH_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_public(key, MAIL_CRYPT_KEY_ID_ALGORITHM, key_id,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *hash = binary_to_hex(key_id->data, key_id->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, hash) == 0) return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_set_used_size(key_id, 0);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_public_old(key, key_id, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hash = binary_to_hex(key_id->data, key_id->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(pubid, hash) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Key %s does not match given ID %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hash, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_env_get_private_key(struct mail_user *user, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_global_keys global_keys;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_global_keys_load(user, "mail_crypt", &global_keys,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi TRUE, error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_global_keys_free(&global_keys);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* see if we got a key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_global_key_find(&global_keys, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_private(key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_r = key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_global_keys_free(&global_keys);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiconst char *mail_crypt_get_key_path(bool user_key, bool public, const char *pubid)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *ret = t_strdup_printf("%s%s%s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi user_key ? USER_CRYPT_PREFIX :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi public ? PUBKEYS_PREFIX :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi PRIVKEYS_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_decrypt_private_key(struct mailbox *box, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *data,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum dcrypt_key_kind key_kind;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum dcrypt_key_encryption_type enc_type;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *enc_hash = NULL, *key_hash = NULL, *pw = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key = NULL, *dec_key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(pubid != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(data != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* see what the key needs for decrypting */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_string_get_info(data, NULL, NULL, &key_kind,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &enc_type, &enc_hash, &key_hash, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key_kind != DCRYPT_KEY_KIND_PRIVATE) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot use key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Expected private key, got public key",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key_hash != NULL && strcmp(key_hash, pubid) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot use key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Incorrect key hash %s stored",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_hash);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* see if it needs decrypting */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* no key or password */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pw = mail_user_plugin_getenv(user, MAIL_CRYPT_USERENV_PASSWORD);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (pw == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot decrypt key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Password not available",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_KEY) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_user_get_private_key(user, enc_hash,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &dec_key, error_r)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* last resort, look at environment */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret == 0 && (ret = mail_crypt_env_get_private_key(user, enc_hash,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &dec_key, error_r)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot decrypt key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Private key %s not available:",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid, enc_hash);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot decrypt key %s: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid, *error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool res = dcrypt_key_load_private(&key, data, pw, dec_key, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (dec_key != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&dec_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!res)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_private_key_id_match(key, pubid, error_r) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_r = key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_get_private_key(struct mailbox *box, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool user_key, bool shared,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_user *muser = mail_crypt_get_mail_crypt_user(user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* check cache */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_get_key_cache(muser->key_cache, pubid, key_r, NULL) > 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = mail_crypt_get_key_path(user_key, FALSE, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi shared ? MAIL_ATTRIBUTE_TYPE_SHARED :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_PRIVATE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name, &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, %s%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi shared ? "/shared/" :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "/priv/",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_decrypt_private_key(box, pubid, value.value,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key, error_r)) <= 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, pubid, key, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_r = key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_get_private_key(struct mail_user *user, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_namespace *ns = mail_namespace_find_inbox(user->namespaces);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAILBOX_FLAG_READONLY);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* try retrieve currently active user key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_open(box) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "INBOX",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (pubid == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid = value.value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* try to open key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret > 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_get_private_key(box, pubid, TRUE, FALSE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_r, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_get_private_key(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* get active key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX ACTIVE_KEY_NAME, &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return mail_crypt_get_private_key(box, value.value,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi FALSE, FALSE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_r, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_set_private_key(struct mailbox_transaction_context *t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool user_key, bool shared, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *enc_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* folder keys must be encrypted with some other key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi unless they are shared keys */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(user_key || shared || enc_key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *data = t_str_new(MAIL_CRYPT_KEY_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pw = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *algo = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_storage(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t)));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = mail_crypt_get_key_path(user_key, FALSE, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (enc_key != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi algo = MAIL_CRYPT_KEY_CIPHER;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (user_key &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (pw = mail_user_plugin_getenv(user,MAIL_CRYPT_USERENV_PASSWORD))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi algo = MAIL_CRYPT_PW_CIPHER;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* export key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_store_private(key, DCRYPT_FORMAT_DOVECOT, algo, data,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pw, enc_key, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* store it */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value_stream = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value = str_c(data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.last_change = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_set(t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi shared ? MAIL_ATTRIBUTE_TYPE_SHARED :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_PRIVATE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_set(%s, %s/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(mailbox_transaction_get_mailbox(t)),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi shared ? "/shared" : "/priv",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t), NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi safe_memset(buffer_get_modifiable_data(data, NULL), 0, data->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_set_private_key(struct mail_user *user, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_namespace *ns = mail_namespace_find_inbox(user->namespaces);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAILBOX_FLAG_READONLY);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *env_key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *enc_key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_env_get_private_key(user, NULL, &env_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret > 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_convert_private_to_public(env_key, &enc_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&env_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_user_plugin_getenv(user, MAIL_CRYPT_REQUIRE_ENCRYPTED_USER_KEY) != NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_user_plugin_getenv(user, MAIL_CRYPT_USERENV_PASSWORD) == NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_user_plugin_getenv(user, MAIL_CRYPT_USERENV_KEY) == NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = MAIL_CRYPT_REQUIRE_ENCRYPTED_USER_KEY " set, cannot "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "generate user keypair without password or key";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_open(box) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "INBOX",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_set_private_key(t, TRUE, FALSE, pubid, enc_key, key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_rollback(&t);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mailbox_transaction_commit(&t)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_transaction_commit(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_set_private_key(struct mailbox *box, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_set_private_key(t, FALSE, FALSE, pubid, user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key, error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_rollback(&t);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mailbox_transaction_commit(&t)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_transaction_commit(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_get_public_key(struct mailbox *box, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool user_key, struct dcrypt_public_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_user *muser = mail_crypt_get_mail_crypt_user(user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* check cache */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_get_key_cache(muser->key_cache, pubid, NULL, key_r) > 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum dcrypt_key_kind key_kind;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *key_hash = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = mail_crypt_get_key_path(user_key, TRUE, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name, &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_string_get_info(value.value, NULL, NULL, &key_kind,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi NULL, NULL, &key_hash, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key_kind != DCRYPT_KEY_KIND_PUBLIC) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot use key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Expected public key, got private key",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (key_hash != NULL && strcmp(key_hash, pubid) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("Cannot use key %s: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Incorrect key hash %s stored",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid, key_hash);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* load the key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_load_public(&key, value.value, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (pubid != NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_public_key_id_match(key, pubid, error_r) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_public(&key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, pubid, NULL, key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_r = key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_get_public_key(struct mail_user *user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_namespace *ns = mail_namespace_find_inbox(user->namespaces);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAILBOX_FLAG_READONLY);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* try retrieve currently active user key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_open(box) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "INBOX",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_get_public_key(box, value.value, TRUE, key_r, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_get_public_key(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX ACTIVE_KEY_NAME,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return mail_crypt_get_public_key(box, value.value, FALSE, key_r, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_set_public_key(struct mailbox_transaction_context *t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool user_key, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *data = t_str_new(MAIL_CRYPT_KEY_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = mail_crypt_get_key_path(user_key, TRUE, pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* export key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_store_public(key, DCRYPT_FORMAT_DOVECOT, data,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* store it */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value_stream = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value = str_c(data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.last_change = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_attribute_set(t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_set(%s, %s/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(mailbox_transaction_get_mailbox(t)),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "/shared",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t), NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_set_public_key(struct mail_user *user, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_namespace *ns = mail_namespace_find_inbox(user->namespaces);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(ns->list, "INBOX",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAILBOX_FLAG_READONLY);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* try retrieve currently active user key */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_open(box) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "INBOX",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_set_public_key(t, TRUE, pubid, key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value_stream = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value = pubid;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.last_change = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_set(t, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_set(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi USER_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_rollback(&t);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (mailbox_transaction_commit(&t) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_transaction_commit(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_set_public_key(struct mailbox *box, const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_set_public_key(t, FALSE, pubid, key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value_stream = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value = pubid;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.last_change = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_set(t, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX ACTIVE_KEY_NAME,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &value)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_set(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX ACTIVE_KEY_NAME,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_rollback(&t);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (mailbox_transaction_commit(&t) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_transaction_commit(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_set_keys(struct mail_user *user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *privkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *pubkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_set_private_key(user, pubid, privkey, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_set_public_key(user, pubid, pubkey, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_set_keys(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *privkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *pubkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_set_private_key(box, pubid, privkey, user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_set_public_key(box, pubid, pubkey, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_get_shared_key(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_user *muser = mail_crypt_get_mail_crypt_user(user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* check cache */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_get_key_cache(muser->key_cache, pubid, key_r, NULL) > 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *hexname =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi binary_to_hex((const unsigned char*)user->username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strlen(user->username));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = t_strdup_printf(BOX_CRYPT_PREFIX
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi PRIVKEYS_PREFIX"%s/%s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hexname,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_get(box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name, &value)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_get(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return mail_crypt_get_private_key(box, pubid, FALSE, TRUE, key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_decrypt_private_key(box, pubid, value.value,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key, error_r)) <= 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, pubid, key, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_r = key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_set_shared_key(struct mailbox_transaction_context *t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *privkey,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *target_uid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_attribute_value value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *data = t_str_new(MAIL_CRYPT_KEY_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *algo = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(target_uid == NULL || user_key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (target_uid != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* hash target UID */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi algo = MAIL_CRYPT_KEY_CIPHER;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *hexname =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi binary_to_hex((const unsigned char*)target_uid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strlen(target_uid));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name = t_strdup_printf(BOX_CRYPT_PREFIX
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi PRIVKEYS_PREFIX"%s/%s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hexname,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name = t_strdup_printf(BOX_CRYPT_PREFIX
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi PRIVKEYS_PREFIX"%s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_store_private(privkey, DCRYPT_FORMAT_DOVECOT,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi algo, data,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi NULL, user_key, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value_stream = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.value = str_c(data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi value.last_change = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_set(t, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name, &value)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_set(%s, /shared/%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t)),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi safe_memset(buffer_get_modifiable_data(data, NULL), 0, data->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_unset_shared_key(struct mailbox_transaction_context *t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *target_uid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *hexname =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi binary_to_hex((const unsigned char*)target_uid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strlen(target_uid));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *attr_name = t_strdup_printf(BOX_CRYPT_PREFIX
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi PRIVKEYS_PREFIX"%s/%s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi hexname,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pubid);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_attribute_unset(t, MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mailbox_attribute_unset(%s, "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi " /shared/%s): failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t)),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi attr_name,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_get_mailbox(t),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_generate_keypair(const char *curve,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair *pair_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **pubid_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (curve == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = MAIL_CRYPT_USERENV_CURVE " not set, cannot generate EC key";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_keypair_generate(pair_r, DCRYPT_KEY_EC, 0, curve, error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *key_id = t_str_new(MAIL_CRYPT_HASH_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_public(pair_r->pub, MAIL_CRYPT_KEY_ID_ALGORITHM, key_id,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_keypair_unref(pair_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *pubid_r = binary_to_hex(key_id->data, key_id->used);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4d26a40934cadc1d5f07fc90a4567eb43008c23cTimo Sirainen}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_user_generate_keypair(struct mail_user *user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair *pair,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **pubid_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_user *muser = mail_crypt_get_mail_crypt_user(user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *curve = mail_user_plugin_getenv(user, MAIL_CRYPT_USERENV_CURVE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_generate_keypair(curve, pair, pubid_r, error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_set_keys(user, *pubid_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi pair->priv, pair->pub, error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_keypair_unref(pair);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, *pubid_r, pair->priv, pair->pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_generate_keypair(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair *pair,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **pubid_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_user *muser = mail_crypt_get_mail_crypt_user(user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *curve = mail_user_plugin_getenv(user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_USERENV_CURVE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (user_key == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_user_get_public_key(user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* generate keypair */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair user_pair;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *user_pubid;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_generate_keypair(user, &user_pair,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &user_pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, user_pubid,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi user_pair.priv, user_pair.pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi user_key = user_pair.pub;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&user_pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_ref_public(user_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
156e2ce64bdacb1c5242f023a4b5e229d19510f9Aki Tuomi if ((ret = mail_crypt_generate_keypair(curve, pair, pubid_r, error_r)) < 0) {
156e2ce64bdacb1c5242f023a4b5e229d19510f9Aki Tuomi /* failed */
156e2ce64bdacb1c5242f023a4b5e229d19510f9Aki Tuomi } else if ((ret = mail_crypt_box_set_keys(box, *pubid_r,
156e2ce64bdacb1c5242f023a4b5e229d19510f9Aki Tuomi pair->priv, user_key, pair->pub,
156e2ce64bdacb1c5242f023a4b5e229d19510f9Aki Tuomi error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_keypair_unref(pair);
179e0558e25673191ac7f1728fd7243fc17ec343Aki Tuomi } else {
179e0558e25673191ac7f1728fd7243fc17ec343Aki Tuomi mail_crypt_put_key_cache(&muser->key_cache, *pubid_r, pair->priv,
179e0558e25673191ac7f1728fd7243fc17ec343Aki Tuomi pair->pub);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_public(&user_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_get_pvt_digests(struct mailbox *box, pool_t pool,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum mail_attribute_type type,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ARRAY_TYPE(const_string) *digests,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_attribute_iter *iter;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi iter = mailbox_attribute_iter_init(box, type,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX PRIVKEYS_PREFIX);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while ((key = mailbox_attribute_iter_next(iter)) != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key = p_strdup(pool, key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi array_append(digests, &key, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mailbox_attribute_iter_deinit(&iter);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0)
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi *error_r = mailbox_get_last_internal_error(box, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_get_private_keys(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ARRAY_TYPE(dcrypt_private_key) *keys_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_attribute_iter *iter;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi iter = mailbox_attribute_iter_init(box, MAIL_ATTRIBUTE_TYPE_PRIVATE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi BOX_CRYPT_PREFIX PRIVKEYS_PREFIX);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *id;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while ((id = mailbox_attribute_iter_next(iter)) != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_get_private_key(box, id, FALSE, FALSE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key, error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)mailbox_attribute_iter_deinit(&iter);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret > 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi array_append(keys_r, &key, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mailbox_attribute_iter_deinit(&iter);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0)
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi *error_r = mailbox_get_last_internal_error(box, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint mail_crypt_box_share_private_keys(struct mailbox_transaction_context *t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *dest_pub_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const ARRAY_TYPE(dcrypt_private_key) *priv_keys,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(dest_user == NULL || dest_pub_key != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key *const *priv_keyp, *priv_key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi buffer_t *key_id = t_str_new(MAIL_CRYPT_HASH_BUF_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi array_foreach(priv_keys, priv_keyp) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi priv_key = *priv_keyp;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_key_id_private(priv_key, MAIL_CRYPT_KEY_ID_ALGORITHM,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_id, error_r) ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (ret = mail_crypt_box_set_shared_key(t,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi binary_to_hex(key_id->data,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_id->used),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi priv_key, dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_pub_key, error_r)) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_user_get_or_gen_public_key(struct mail_user *user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key **pub_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(user != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(pub_r != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(error_r != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_user_get_public_key(user, pub_r, error_r)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair pair;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_generate_keypair(user, &pair,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &pubid, error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *pub_r = pair.pub;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_box_get_or_gen_public_key(struct mailbox *box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key **pub_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(box != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(pub_r != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(error_r != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *user =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_get_user(mailbox_get_storage(box));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_box_get_public_key(box, pub_r, error_r)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *user_key;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_user_get_or_gen_public_key(user, &user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_keypair pair;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *pubid = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_generate_keypair(box, &pair, user_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &pubid, error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *pub_r = pair.pub;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_public(&user_key);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(&pair.priv);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomibool mail_crypt_acl_secure_sharing_enabled(struct mail_user *user)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *env =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_user_plugin_getenv(user, MAIL_CRYPT_ACL_SECURE_SHARE_SETTING);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* disabled by default */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool ret = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (env != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* enable unless specifically
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi requested not to */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = TRUE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi switch (env[0]) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case 'n':
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case 'N':
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case '0':
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case 'f':
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case 'F':
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const struct mailbox_attribute_internal mailbox_internal_attributes[] = {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi { .type = MAIL_ATTRIBUTE_TYPE_PRIVATE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .key = BOX_CRYPT_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .flags = MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi },
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi { .type = MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .key = BOX_CRYPT_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .flags = MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi },
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi { .type = MAIL_ATTRIBUTE_TYPE_PRIVATE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .key = USER_CRYPT_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .flags = MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi },
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi { .type = MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .key = USER_CRYPT_PREFIX,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .flags = MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_key_register_mailbox_internal_attributes(void)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_attribute_register_internals(mailbox_internal_attributes,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi N_ELEMENTS(mailbox_internal_attributes));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}