/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "dcrypt.h" #include "dcrypt-iostream.h" #include "ostream-encrypt.h" #include "istream-private.h" #include "istream-decrypt.h" #include "doveadm-dump.h" #include "hex-binary.h" #include "str.h" #include #include #include #include #include #define KEY_BUF_SIZE 4096 static void dcrypt_dump_public_key_metadata(const char *buf) { const char *error = NULL; struct dcrypt_public_key *pub_key; bool ret = dcrypt_key_load_public(&pub_key, buf, &error); if (ret == FALSE) { i_error("dcrypt_key_load_public failed: %s", error); return; } enum dcrypt_key_type key_type = dcrypt_key_type_public(pub_key); if (key_type == DCRYPT_KEY_RSA) printf("key type: DCRYPT_KEY_RSA\n"); else if (key_type == DCRYPT_KEY_EC) printf("key type: DCRYPT_KEY_EC\n"); string_t *hash = t_str_new(128); if (!dcrypt_key_id_public(pub_key, "sha256", hash, &error)) { i_error("dcrypt_key_id_public failed: %s", error); } else { const char *v2_hash = binary_to_hex(hash->data, hash->used); printf("v2 hash: %s\n", v2_hash); if (key_type == DCRYPT_KEY_EC) { buffer_set_used_size(hash, 0); if (!dcrypt_key_id_public_old(pub_key, hash, &error)) { i_error("dcrypt_key_id_public_old failed: %s", error); } else { const char *v1_hash = binary_to_hex(hash->data, hash->used); printf("v1 hash: %s\n", v1_hash); } } } dcrypt_key_unref_public(&pub_key); } static void dcrypt_dump_private_key_metadata(const char *buf) { const char *error = NULL; struct dcrypt_private_key *priv_key; bool ret = dcrypt_key_load_private(&priv_key, buf, NULL, NULL, &error); if (ret == FALSE) { i_error("dcrypt_key_load_private failed: %s", error); return; } enum dcrypt_key_type key_type = dcrypt_key_type_private(priv_key); if (key_type == DCRYPT_KEY_RSA) printf("key type: DCRYPT_KEY_RSA\n"); else if (key_type == DCRYPT_KEY_EC) printf("key type: DCRYPT_KEY_EC\n"); string_t *hash = t_str_new(128); if (!dcrypt_key_id_private(priv_key, "sha256", hash, &error)) { i_error("dcrypt_key_id_private failed: %s", error); } else { const char *v2_hash = binary_to_hex(hash->data, hash->used); printf("v2 hash: %s\n", v2_hash); if (key_type == DCRYPT_KEY_EC) { buffer_set_used_size(hash, 0); if (!dcrypt_key_id_private_old(priv_key, hash, &error)) { i_error("dcrypt_key_id_private_old failed: %s", error); } else { const char *v1_hash = binary_to_hex(hash->data, hash->used); printf("v1 hash: %s\n", v1_hash); } } } dcrypt_key_unref_private(&priv_key); } static bool dcrypt_key_dump_metadata(const char *filename, bool print) { bool ret = TRUE; int fd = open(filename, O_RDONLY); if (fd < 0) { if (print) i_error("open(%s) failed: %m", filename); return FALSE; } char buf[KEY_BUF_SIZE+1]; ssize_t res = read(fd, buf, KEY_BUF_SIZE); if (res < 0) { if (print) i_error("read(%s) failed: %m", filename); i_close_fd(&fd); return FALSE; } i_close_fd(&fd); buf[res] = '\0'; enum dcrypt_key_format format; enum dcrypt_key_version version; enum dcrypt_key_kind kind; enum dcrypt_key_encryption_type encryption_type; const char *encryption_key_hash; const char *key_hash; const char *error; ret = dcrypt_key_string_get_info(buf, &format, &version, &kind, &encryption_type, &encryption_key_hash, &key_hash, &error); if (ret == FALSE) { if (print) i_error("dcrypt_key_string_get_info failed: %s", error); return FALSE; } if (!print) return TRUE; switch (format) { case DCRYPT_FORMAT_PEM: printf("format: DCRYPT_FORMAT_PEM\n"); break; case DCRYPT_FORMAT_DOVECOT: printf("format: DCRYPT_FORMAT_DOVECOT\n"); break; case DCRYPT_FORMAT_JWK: printf("format: DCRYPT_FORMAT_JWK\n"); } switch (version) { case DCRYPT_KEY_VERSION_1: printf("version: DCRYPT_KEY_VERSION_1\n"); break; case DCRYPT_KEY_VERSION_2: printf("version: DCRYPT_KEY_VERSION_2\n"); break; case DCRYPT_KEY_VERSION_NA: printf("version: DCRYPT_KEY_VERSION_NA\n"); break; } switch (kind) { case DCRYPT_KEY_KIND_PUBLIC: printf("kind: DCRYPT_KEY_KIND_PUBLIC\n"); break; case DCRYPT_KEY_KIND_PRIVATE: printf("kind: DCRYPT_KEY_KIND_PRIVATE\n"); break; } switch (encryption_type) { case DCRYPT_KEY_ENCRYPTION_TYPE_NONE: printf("encryption_type: DCRYPT_KEY_ENCRYPTION_TYPE_NONE\n"); break; case DCRYPT_KEY_ENCRYPTION_TYPE_KEY: printf("encryption_type: DCRYPT_KEY_ENCRYPTION_TYPE_KEY\n"); break; case DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD: printf("encryption_type: DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD\n"); break; } if (encryption_key_hash != NULL) printf("encryption_key_hash: %s\n", encryption_key_hash); if (key_hash != NULL) printf("key_hash: %s\n", key_hash); const char *data = t_str_rtrim(buf, "\r\n\t "); switch (kind) { case DCRYPT_KEY_KIND_PUBLIC: dcrypt_dump_public_key_metadata(data); break; case DCRYPT_KEY_KIND_PRIVATE: if (encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE) dcrypt_dump_private_key_metadata(data); break; } return TRUE; } static bool test_dump_dcrypt_key(const char *path) { if (!dcrypt_initialize("openssl", NULL, NULL)) return FALSE; bool ret = dcrypt_key_dump_metadata(path, FALSE); return ret; } static void cmd_dump_dcrypt_key(const char *path, const char *const *args ATTR_UNUSED) { const char *error = NULL; if (!dcrypt_initialize("openssl", NULL, &error)) i_fatal("dcrypt_initialize: %s", error); (void)dcrypt_key_dump_metadata(path, TRUE); } struct doveadm_cmd_dump doveadm_cmd_dump_dcrypt_key = { "dcrypt-key", test_dump_dcrypt_key, cmd_dump_dcrypt_key };