fs-crypt-common.c revision 4c78d9e646c4a1158d7167806937c02d86cdfc25
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi/* Copyright (c) 2015-2016 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "lib.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "randgen.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "istream.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "ostream.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "istream-decrypt.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "ostream-encrypt.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "iostream-temp.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mailbox-list.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-namespace.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-common.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-key.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "dcrypt-iostream.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "fs-api-private.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistruct crypt_fs {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct fs fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_global_keys keys;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool keys_loaded;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *enc_algo;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *set_prefix;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *public_key_path;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *private_key_path;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *password;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistruct crypt_fs_file {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct fs_file file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs *fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct fs_file *super_read;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum fs_open_mode open_mode;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct istream *input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ostream *super_output;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ostream *temp_output;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi/* defined outside this file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiextern const struct fs FS_CLASS_CRYPT;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint fs_crypt_load_keys(struct crypt_fs *fs, const char **error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct fs *fs_crypt_alloc(void)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs *fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs = i_new(struct crypt_fs, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->fs = FS_CLASS_CRYPT;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return &fs->fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomifs_crypt_init(struct fs *_fs, const char *args, const
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct fs_settings *set)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs *fs = (struct crypt_fs *)_fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *enc_algo, *set_prefix;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *p, *arg, *value, *error, *parent_name, *parent_args;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *public_key_path = "", *private_key_path = "", *password = "";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi random_init();
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!dcrypt_initialize("openssl", NULL, &error))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_fatal("dcrypt_initialize(): %s", error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* [algo=<s>:][set_prefix=<n>:][public_key_path=<s>:]
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi [private_key_path=<s>:[password=<s>:]]<parent fs> */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi set_prefix = "mail_crypt_global";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enc_algo = "aes-256-gcm-sha256";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi for (;;) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi p = strchr(args, ':');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (p == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_set_error(_fs, "Missing parameters");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi arg = t_strdup_until(args, p);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((value = strchr(arg, '=')) == NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi arg = t_strdup_until(arg, value++);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi args = p+1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(arg, "algo") == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enc_algo = value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else if (strcmp(arg, "set_prefix") == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi set_prefix = value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else if (strcmp(arg, "public_key_path") == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi public_key_path = value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else if (strcmp(arg, "private_key_path") == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi private_key_path = value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else if (strcmp(arg, "password") == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi password = value;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_set_error(_fs, "Invalid parameter '%s'", arg);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi parent_args = strchr(args, ':');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (parent_args == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi parent_name = args;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi parent_args = "";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi parent_name = t_strdup_until(args, parent_args);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi parent_args++;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_set_error(_fs, "%s: %s", parent_name, error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->enc_algo = i_strdup(enc_algo);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->set_prefix = i_strdup(set_prefix);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->public_key_path = i_strdup_empty(public_key_path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->private_key_path = i_strdup_empty(private_key_path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->password = i_strdup_empty(password);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void fs_crypt_deinit(struct fs *_fs)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs *fs = (struct crypt_fs *)_fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_global_keys_free(&fs->keys);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (_fs->parent != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_deinit(&_fs->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs->enc_algo);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs->set_prefix);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs->public_key_path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs->private_key_path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs->password);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(fs);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi random_deinit();
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct fs_file *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomifs_crypt_file_init(struct fs *_fs, const char *path,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum fs_open_mode mode, enum fs_open_flags flags)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs *fs = (struct crypt_fs *)_fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file = i_new(struct crypt_fs_file, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->file.fs = _fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->file.path = i_strdup(path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->fs = fs;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->open_mode = mode;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* avoid unnecessarily creating two seekable streams */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi flags &= ~FS_OPEN_FLAG_SEEKABLE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->file.parent = fs_file_init(_fs->parent, path, mode | flags);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mode == FS_OPEN_MODE_READONLY &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (flags & FS_OPEN_FLAG_ASYNC) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* use async stream for super, so fs_read_stream() won't create
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi another seekable stream unneededly */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->super_read = fs_file_init(_fs->parent, path, mode | flags |
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi FS_OPEN_FLAG_ASYNC);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->super_read = file->file.parent;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return &file->file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void fs_crypt_file_deinit(struct fs_file *_file)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->super_read != _file->parent && file->super_read != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_deinit(&file->super_read);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_deinit(&_file->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(file->file.path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(file);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void fs_crypt_file_close(struct fs_file *_file)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->input != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_unref(&file->input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->super_read != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_close(file->super_read);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (_file->parent != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_close(_file->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int fs_crypt_read_file(const char *set_name, const char *path,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char **key_data_r, const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct istream *input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input = i_stream_create_file(path, (size_t)-1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while (i_stream_read(input) > 0) ;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (input->stream_errno != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("%s: read(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi set_name, path, i_stream_get_error(input));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi size_t size;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const unsigned char *data = i_stream_get_data(input, &size);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *key_data_r = i_strndup(data, size);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_unref(&input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomifs_crypt_load_keys_from_path(struct crypt_fs *fs, const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi char *key_data;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_global_keys_init(&fs->keys);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs->public_key_path != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs_crypt_read_file("crypt:public_key_path",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->public_key_path,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key_data, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_load_global_public_key("crypt:public_key_path",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_data, &fs->keys,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(key_data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(key_data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs->private_key_path != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs_crypt_read_file("crypt:private_key_path",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->private_key_path,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key_data, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_load_global_private_key("crypt:private_key_path",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key_data, "crypt:password",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs->password, &fs->keys,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(key_data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(key_data);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomifs_crypt_istream_get_key(const char *pubkey_digest,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **priv_key_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r, void *context)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = context;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs_crypt_load_keys(file->fs, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *priv_key_r = mail_crypt_global_key_find(&file->fs->keys, pubkey_digest);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return *priv_key_r == NULL ? 0 : 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct istream *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomifs_crypt_read_stream(struct fs_file *_file, size_t max_buffer_size)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct istream *input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->input != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_ref(file->input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_seek(file->input, 0);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return file->input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input = fs_read_stream(file->super_read, max_buffer_size);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->input = i_stream_create_decrypt_callback(input,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_crypt_istream_get_key, file);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_unref(&input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_ref(file->input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return file->input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void fs_crypt_write_stream(struct fs_file *_file)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *error;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(_file->output == NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (fs_crypt_load_keys(file->fs, &error) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi _file->output = o_stream_create_error_str(EIO,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Couldn't read settings: %s", error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->fs->keys.public_key == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (_file->fs->set.debug)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_debug("No public key provided, "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "NOT encrypting stream %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_path(_file));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->super_output = fs_write_stream(_file->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi _file->output = file->super_output;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum io_stream_encrypt_flags flags;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strstr(file->fs->enc_algo, "gcm") != NULL ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strstr(file->fs->enc_algo, "ccm") != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi flags = IO_STREAM_ENC_INTEGRITY_AEAD;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi flags = IO_STREAM_ENC_INTEGRITY_HMAC;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->temp_output =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi iostream_temp_create_named(_file->fs->temp_path_prefix,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi IOSTREAM_TEMP_FLAG_TRY_FD_DUP,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_file_path(_file));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi _file->output = o_stream_create_encrypt(file->temp_output,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->fs->enc_algo, file->fs->keys.public_key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi flags);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int fs_crypt_write_stream_finish(struct fs_file *_file, bool success)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct istream *input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (_file->output != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (_file->output == file->super_output)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi _file->output = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi o_stream_unref(&_file->output);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!success) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->super_output != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* no encryption */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(file->temp_output == NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fs_write_stream_abort_error(_file->parent, &file->super_output,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "write(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi o_stream_get_name(file->super_output),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi o_stream_get_error(file->super_output));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (file->temp_output != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi o_stream_destroy(&file->temp_output);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->super_output != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* no encrypt */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(file->temp_output == NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return fs_write_stream_finish(_file->parent, &file->super_output);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (file->temp_output == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* finishing up */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(file->super_output == NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return fs_write_stream_finish_async(_file->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* finish writing the temporary file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input = iostream_temp_finish(&file->temp_output, IO_BLOCK_SIZE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi file->super_output = fs_write_stream(_file->parent);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi o_stream_nsend_istream(file->super_output, input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = fs_write_stream_finish(_file->parent, &file->super_output);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_stream_unref(&input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}