From: Dan Aloni <dan@kernelim.com> To: linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Subject: [PATCHv2 6/7] tools: add dmesg decryption program Date: Sat, 13 Jan 2018 23:34:40 +0200 [thread overview] Message-ID: <20180113213441.52047-7-dan@kernelim.com> (raw) In-Reply-To: <20180113213441.52047-1-dan@kernelim.com> Example execution: dmesg | dmesg-decipher <private-key.pem> Signed-off-by: Dan Aloni <dan@kernelim.com> --- tools/Makefile | 9 +- tools/kmsg/.gitignore | 1 + tools/kmsg/Makefile | 14 ++ tools/kmsg/dmesg-decipher.c | 354 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 tools/kmsg/.gitignore create mode 100644 tools/kmsg/Makefile create mode 100644 tools/kmsg/dmesg-decipher.c diff --git a/tools/Makefile b/tools/Makefile index be02c8b904db..5a661e4c9012 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -18,6 +18,7 @@ help: @echo ' hv - tools used when in Hyper-V clients' @echo ' iio - IIO tools' @echo ' kvm_stat - top-like utility for displaying kvm statistics' + @echo ' kmsg - A tool for decrypting a dmesg using a private key' @echo ' leds - LEDs tools' @echo ' liblockdep - user-space wrapper for kernel locking-validator' @echo ' bpf - misc BPF tools' @@ -91,6 +92,9 @@ freefall: FORCE kvm_stat: FORCE $(call descend,kvm/$@) +kmsg: FORCE + $(call descend,kmsg) + all: acpi cgroup cpupower gpio hv firewire liblockdep \ perf selftests spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ @@ -167,6 +171,9 @@ tmon_clean: freefall_clean: $(call descend,laptop/freefall,clean) +kmsg_clean: + $(call descend,kmsg,clean) + build_clean: $(call descend,build,clean) @@ -174,6 +181,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ - gpio_clean objtool_clean leds_clean wmi_clean + gpio_clean objtool_clean leds_clean wmi_clean kmsg_clean .PHONY: FORCE diff --git a/tools/kmsg/.gitignore b/tools/kmsg/.gitignore new file mode 100644 index 000000000000..a5b4e26b8d0b --- /dev/null +++ b/tools/kmsg/.gitignore @@ -0,0 +1 @@ +dmesg-decipher diff --git a/tools/kmsg/Makefile b/tools/kmsg/Makefile new file mode 100644 index 000000000000..9f4ef7b11798 --- /dev/null +++ b/tools/kmsg/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +CC := $(CROSS_COMPILE)gcc + +CFLAGS := -O2 -Wall $$(pkg-config --libs openssl) + +PROGS := dmesg-decipher + +%: %.c + $(CC) $(CFLAGS) -o $@ $^ + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/tools/kmsg/dmesg-decipher.c b/tools/kmsg/dmesg-decipher.c new file mode 100644 index 000000000000..1ad2b0a27402 --- /dev/null +++ b/tools/kmsg/dmesg-decipher.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dmesg-decipher.c + * + * A sample utility to decrypt an encrypted dmesg output, for + * development with kernels having kmsg encryption enabled. + * + * base64 decoding code taken from lib/base64-armor.c + * + * Copyright (c) Dan Aloni, 2017 + * + * Compile with: + * + * gcc -O2 -Wall $(pkg-config --libs openssl) \ + * dmesg-decipher -o dmesg-decipher + */ + +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> + +#include <regex.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +/* + * The following is based on code from: + * + * https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption + */ +static int aes_256_gcm_decrypt(unsigned char *ciphertext, size_t ciphertext_len, + unsigned char *aad, size_t aad_len, + unsigned char *tag, unsigned char *key, + unsigned char *iv, size_t iv_len, + unsigned char *plaintext) +{ + EVP_CIPHER_CTX *ctx; + int len; + int plaintext_len; + int ret = -1; + + /* Create and initialise the context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + /* Initialise the decryption operation. */ + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + goto free; + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) + goto free; + + /* Initialise key and IV */ + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) + goto free; + + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if (aad_len != 0) + if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) + goto free; + + /* Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, + ciphertext_len)) + goto free; + plaintext_len = len; + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) + goto free; + + /* Finalise the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + +free: + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + if (ret > 0) { + /* Success */ + plaintext_len += len; + return plaintext_len; + } + + /* Verify failed */ + return -1; +} + +static int decode_bits(char c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 26; + if (c >= '0' && c <= '9') + return c - '0' + 52; + if (c == '+') + return 62; + if (c == '/') + return 63; + if (c == '=') + return 0; /* just non-negative, please */ + return -EINVAL; +} + +static int base64_unarmor(char *dst, int dst_max, const char *src, + const char *end) +{ + int olen = 0; + + while (src < end) { + int a, b, c, d; + + if (src[0] == '\n') { + src++; + continue; + } + if (src + 4 > end) + return -EINVAL; + a = decode_bits(src[0]); + b = decode_bits(src[1]); + c = decode_bits(src[2]); + d = decode_bits(src[3]); + if (a < 0 || b < 0 || c < 0 || d < 0) + return -EINVAL; + + if (dst_max < 1) + return -ENOSPC; + *dst++ = (a << 2) | (b >> 4); + dst_max--; + if (src[2] == '=') + return olen + 1; + if (dst_max < 1) + return -ENOSPC; + *dst++ = ((b & 15) << 4) | (c >> 2); + dst_max--; + if (src[3] == '=') + return olen + 2; + if (dst_max < 1) + return -ENOSPC; + *dst++ = ((c & 3) << 6) | d; + dst_max--; + olen += 3; + src += 4; + } + return olen; +} + +static int parse_int_regex_match(const char *source, regmatch_t match, + size_t *output) +{ + char decimal_number[0x10] = { + 0, + }; + size_t len = match.rm_eo - match.rm_so; + + if (len >= sizeof(decimal_number)) + return -1; + + memcpy(&decimal_number[0], &source[match.rm_so], len); + + *output = atoi(decimal_number); + return 0; +} + +static const char session_key_pattern[] = "(.*)K:([0-9a-zA-Z~+/=]+)"; +static const char message_pattern[] = + "(.*)M:([0-9a-zA-Z~+/=]+),([0-9]+),([0-9]+)"; + +static int decrypt_message(char *line, regmatch_t *matches, uint8_t *sess_key) +{ + char plain_text[0x1000], *enc; + uint8_t cipher_msg_bin[0x1000]; + size_t cipher_msg_size = sizeof(cipher_msg_bin); + size_t cipher_size; + const regmatch_t prefix = matches[1]; + const regmatch_t ciphermsg = matches[2]; + const regmatch_t auth_str_len = matches[3]; + const regmatch_t iv_str_len = matches[4]; + size_t auth_len; + size_t iv_len; + int ret; + + ret = parse_int_regex_match(line, auth_str_len, &auth_len); + if (ret) + return -1; + + ret = parse_int_regex_match(line, iv_str_len, &iv_len); + if (ret) + return -1; + + for (enc = &line[ciphermsg.rm_so]; enc < &line[ciphermsg.rm_eo]; enc++) + if (*enc == '~') + *enc = '\n'; + + ret = base64_unarmor((char *)cipher_msg_bin, cipher_msg_size, + &line[ciphermsg.rm_so], &line[ciphermsg.rm_eo]); + if (ret < 0) { + fprintf(stderr, "error decoding base64 message (code = %d)\n", + ret); + return -1; + } + + cipher_msg_size = ret; + + if (iv_len >= cipher_msg_size || auth_len >= cipher_msg_size + || auth_len + iv_len > cipher_msg_size) { + return -1; + } + + cipher_size = cipher_msg_size - auth_len - iv_len; + + ret = aes_256_gcm_decrypt(/* Ciphertext */ + (uint8_t *)cipher_msg_bin, cipher_size, + + /* AAD */ + NULL, 0, + + /* tag */ + (uint8_t *)&cipher_msg_bin[cipher_size], + + /* key */ + sess_key, + + /* IV */ + (uint8_t *)&cipher_msg_bin[cipher_size + + auth_len], + iv_len, + + /* Plain text */ + (uint8_t *)plain_text); + if (ret > 0) { + fwrite(line, prefix.rm_eo, 1, stdout); + fwrite(plain_text, ret, 1, stdout); + fwrite("\n", 1, 1, stdout); + } + + return ret; +} + +int main(int argc, char **argv) +{ + BIO *tbio = NULL; + RSA *rsa; + int ret = 1; + char line[0x1000]; + uint8_t enc_sess_key[0x200]; + uint8_t sess_key[0x200] = { + 0, + }; + bool got_key = false; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + regex_t session_key_regex; + regex_t message_regex; + + ret = regcomp(&session_key_regex, session_key_pattern, REG_EXTENDED); + if (ret) + goto err; + + ret = regcomp(&message_regex, message_pattern, REG_EXTENDED); + if (ret) + goto err; + + if (argc < 2) { + fprintf(stderr, "not enough parameters\n"); + return -1; + } + + /* Read in recipient certificate and private key */ + tbio = BIO_new_file(argv[1], "r"); + if (!tbio) { + fprintf(stderr, "BIO_new_file - error\n"); + goto err; + } + + rsa = PEM_read_bio_RSAPrivateKey(tbio, NULL, NULL, NULL); + if (!rsa) + goto err; + + while (true) { + regmatch_t matches[5]; + + if (!fgets(line, sizeof(line), stdin)) + break; + + if (!got_key + && !regexec(&session_key_regex, line, 5, matches, 0)) { + const regmatch_t match = matches[2]; + size_t enc_sess_key_size = sizeof(enc_sess_key); + char *enc; + + for (enc = &line[match.rm_so]; enc < &line[match.rm_eo]; + enc++) + if (*enc == '~') + *enc = '\n'; + + ret = base64_unarmor( + (char *)&enc_sess_key, enc_sess_key_size, + &line[match.rm_so], &line[match.rm_eo]); + if (ret < 0) { + fprintf(stderr, + "error decoding session key" + " (code = %d)\n", + ret); + return -1; + } + + enc_sess_key_size = ret; + + ret = RSA_private_decrypt(enc_sess_key_size, + enc_sess_key, sess_key, rsa, + RSA_PKCS1_PADDING); + if (ret < 0) + goto err; + + got_key = true; + } + + if (!regexec(&message_regex, line, 5, matches, 0)) { + if (!got_key) { + fprintf(stderr, + "session key must precede messages\n"); + break; + } + + ret = decrypt_message(line, matches, sess_key); + if (ret < 0) { + fprintf(stderr, + "error decrypting message" + " (code = %d)\n", + ret); + break; + } + } + } + + regfree(&session_key_regex); + regfree(&message_regex); + +err: + return -1; +} -- 2.14.3
WARNING: multiple messages have this Message-ID (diff)
From: Dan Aloni <dan@kernelim.com> To: linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Subject: [kernel-hardening] [PATCHv2 6/7] tools: add dmesg decryption program Date: Sat, 13 Jan 2018 23:34:40 +0200 [thread overview] Message-ID: <20180113213441.52047-7-dan@kernelim.com> (raw) In-Reply-To: <20180113213441.52047-1-dan@kernelim.com> Example execution: dmesg | dmesg-decipher <private-key.pem> Signed-off-by: Dan Aloni <dan@kernelim.com> --- tools/Makefile | 9 +- tools/kmsg/.gitignore | 1 + tools/kmsg/Makefile | 14 ++ tools/kmsg/dmesg-decipher.c | 354 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 tools/kmsg/.gitignore create mode 100644 tools/kmsg/Makefile create mode 100644 tools/kmsg/dmesg-decipher.c diff --git a/tools/Makefile b/tools/Makefile index be02c8b904db..5a661e4c9012 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -18,6 +18,7 @@ help: @echo ' hv - tools used when in Hyper-V clients' @echo ' iio - IIO tools' @echo ' kvm_stat - top-like utility for displaying kvm statistics' + @echo ' kmsg - A tool for decrypting a dmesg using a private key' @echo ' leds - LEDs tools' @echo ' liblockdep - user-space wrapper for kernel locking-validator' @echo ' bpf - misc BPF tools' @@ -91,6 +92,9 @@ freefall: FORCE kvm_stat: FORCE $(call descend,kvm/$@) +kmsg: FORCE + $(call descend,kmsg) + all: acpi cgroup cpupower gpio hv firewire liblockdep \ perf selftests spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ @@ -167,6 +171,9 @@ tmon_clean: freefall_clean: $(call descend,laptop/freefall,clean) +kmsg_clean: + $(call descend,kmsg,clean) + build_clean: $(call descend,build,clean) @@ -174,6 +181,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ - gpio_clean objtool_clean leds_clean wmi_clean + gpio_clean objtool_clean leds_clean wmi_clean kmsg_clean .PHONY: FORCE diff --git a/tools/kmsg/.gitignore b/tools/kmsg/.gitignore new file mode 100644 index 000000000000..a5b4e26b8d0b --- /dev/null +++ b/tools/kmsg/.gitignore @@ -0,0 +1 @@ +dmesg-decipher diff --git a/tools/kmsg/Makefile b/tools/kmsg/Makefile new file mode 100644 index 000000000000..9f4ef7b11798 --- /dev/null +++ b/tools/kmsg/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +CC := $(CROSS_COMPILE)gcc + +CFLAGS := -O2 -Wall $$(pkg-config --libs openssl) + +PROGS := dmesg-decipher + +%: %.c + $(CC) $(CFLAGS) -o $@ $^ + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/tools/kmsg/dmesg-decipher.c b/tools/kmsg/dmesg-decipher.c new file mode 100644 index 000000000000..1ad2b0a27402 --- /dev/null +++ b/tools/kmsg/dmesg-decipher.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dmesg-decipher.c + * + * A sample utility to decrypt an encrypted dmesg output, for + * development with kernels having kmsg encryption enabled. + * + * base64 decoding code taken from lib/base64-armor.c + * + * Copyright (c) Dan Aloni, 2017 + * + * Compile with: + * + * gcc -O2 -Wall $(pkg-config --libs openssl) \ + * dmesg-decipher -o dmesg-decipher + */ + +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> + +#include <regex.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +/* + * The following is based on code from: + * + * https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption + */ +static int aes_256_gcm_decrypt(unsigned char *ciphertext, size_t ciphertext_len, + unsigned char *aad, size_t aad_len, + unsigned char *tag, unsigned char *key, + unsigned char *iv, size_t iv_len, + unsigned char *plaintext) +{ + EVP_CIPHER_CTX *ctx; + int len; + int plaintext_len; + int ret = -1; + + /* Create and initialise the context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + /* Initialise the decryption operation. */ + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + goto free; + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) + goto free; + + /* Initialise key and IV */ + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) + goto free; + + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if (aad_len != 0) + if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) + goto free; + + /* Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, + ciphertext_len)) + goto free; + plaintext_len = len; + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) + goto free; + + /* Finalise the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + +free: + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + if (ret > 0) { + /* Success */ + plaintext_len += len; + return plaintext_len; + } + + /* Verify failed */ + return -1; +} + +static int decode_bits(char c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 26; + if (c >= '0' && c <= '9') + return c - '0' + 52; + if (c == '+') + return 62; + if (c == '/') + return 63; + if (c == '=') + return 0; /* just non-negative, please */ + return -EINVAL; +} + +static int base64_unarmor(char *dst, int dst_max, const char *src, + const char *end) +{ + int olen = 0; + + while (src < end) { + int a, b, c, d; + + if (src[0] == '\n') { + src++; + continue; + } + if (src + 4 > end) + return -EINVAL; + a = decode_bits(src[0]); + b = decode_bits(src[1]); + c = decode_bits(src[2]); + d = decode_bits(src[3]); + if (a < 0 || b < 0 || c < 0 || d < 0) + return -EINVAL; + + if (dst_max < 1) + return -ENOSPC; + *dst++ = (a << 2) | (b >> 4); + dst_max--; + if (src[2] == '=') + return olen + 1; + if (dst_max < 1) + return -ENOSPC; + *dst++ = ((b & 15) << 4) | (c >> 2); + dst_max--; + if (src[3] == '=') + return olen + 2; + if (dst_max < 1) + return -ENOSPC; + *dst++ = ((c & 3) << 6) | d; + dst_max--; + olen += 3; + src += 4; + } + return olen; +} + +static int parse_int_regex_match(const char *source, regmatch_t match, + size_t *output) +{ + char decimal_number[0x10] = { + 0, + }; + size_t len = match.rm_eo - match.rm_so; + + if (len >= sizeof(decimal_number)) + return -1; + + memcpy(&decimal_number[0], &source[match.rm_so], len); + + *output = atoi(decimal_number); + return 0; +} + +static const char session_key_pattern[] = "(.*)K:([0-9a-zA-Z~+/=]+)"; +static const char message_pattern[] = + "(.*)M:([0-9a-zA-Z~+/=]+),([0-9]+),([0-9]+)"; + +static int decrypt_message(char *line, regmatch_t *matches, uint8_t *sess_key) +{ + char plain_text[0x1000], *enc; + uint8_t cipher_msg_bin[0x1000]; + size_t cipher_msg_size = sizeof(cipher_msg_bin); + size_t cipher_size; + const regmatch_t prefix = matches[1]; + const regmatch_t ciphermsg = matches[2]; + const regmatch_t auth_str_len = matches[3]; + const regmatch_t iv_str_len = matches[4]; + size_t auth_len; + size_t iv_len; + int ret; + + ret = parse_int_regex_match(line, auth_str_len, &auth_len); + if (ret) + return -1; + + ret = parse_int_regex_match(line, iv_str_len, &iv_len); + if (ret) + return -1; + + for (enc = &line[ciphermsg.rm_so]; enc < &line[ciphermsg.rm_eo]; enc++) + if (*enc == '~') + *enc = '\n'; + + ret = base64_unarmor((char *)cipher_msg_bin, cipher_msg_size, + &line[ciphermsg.rm_so], &line[ciphermsg.rm_eo]); + if (ret < 0) { + fprintf(stderr, "error decoding base64 message (code = %d)\n", + ret); + return -1; + } + + cipher_msg_size = ret; + + if (iv_len >= cipher_msg_size || auth_len >= cipher_msg_size + || auth_len + iv_len > cipher_msg_size) { + return -1; + } + + cipher_size = cipher_msg_size - auth_len - iv_len; + + ret = aes_256_gcm_decrypt(/* Ciphertext */ + (uint8_t *)cipher_msg_bin, cipher_size, + + /* AAD */ + NULL, 0, + + /* tag */ + (uint8_t *)&cipher_msg_bin[cipher_size], + + /* key */ + sess_key, + + /* IV */ + (uint8_t *)&cipher_msg_bin[cipher_size + + auth_len], + iv_len, + + /* Plain text */ + (uint8_t *)plain_text); + if (ret > 0) { + fwrite(line, prefix.rm_eo, 1, stdout); + fwrite(plain_text, ret, 1, stdout); + fwrite("\n", 1, 1, stdout); + } + + return ret; +} + +int main(int argc, char **argv) +{ + BIO *tbio = NULL; + RSA *rsa; + int ret = 1; + char line[0x1000]; + uint8_t enc_sess_key[0x200]; + uint8_t sess_key[0x200] = { + 0, + }; + bool got_key = false; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + regex_t session_key_regex; + regex_t message_regex; + + ret = regcomp(&session_key_regex, session_key_pattern, REG_EXTENDED); + if (ret) + goto err; + + ret = regcomp(&message_regex, message_pattern, REG_EXTENDED); + if (ret) + goto err; + + if (argc < 2) { + fprintf(stderr, "not enough parameters\n"); + return -1; + } + + /* Read in recipient certificate and private key */ + tbio = BIO_new_file(argv[1], "r"); + if (!tbio) { + fprintf(stderr, "BIO_new_file - error\n"); + goto err; + } + + rsa = PEM_read_bio_RSAPrivateKey(tbio, NULL, NULL, NULL); + if (!rsa) + goto err; + + while (true) { + regmatch_t matches[5]; + + if (!fgets(line, sizeof(line), stdin)) + break; + + if (!got_key + && !regexec(&session_key_regex, line, 5, matches, 0)) { + const regmatch_t match = matches[2]; + size_t enc_sess_key_size = sizeof(enc_sess_key); + char *enc; + + for (enc = &line[match.rm_so]; enc < &line[match.rm_eo]; + enc++) + if (*enc == '~') + *enc = '\n'; + + ret = base64_unarmor( + (char *)&enc_sess_key, enc_sess_key_size, + &line[match.rm_so], &line[match.rm_eo]); + if (ret < 0) { + fprintf(stderr, + "error decoding session key" + " (code = %d)\n", + ret); + return -1; + } + + enc_sess_key_size = ret; + + ret = RSA_private_decrypt(enc_sess_key_size, + enc_sess_key, sess_key, rsa, + RSA_PKCS1_PADDING); + if (ret < 0) + goto err; + + got_key = true; + } + + if (!regexec(&message_regex, line, 5, matches, 0)) { + if (!got_key) { + fprintf(stderr, + "session key must precede messages\n"); + break; + } + + ret = decrypt_message(line, matches, sess_key); + if (ret < 0) { + fprintf(stderr, + "error decrypting message" + " (code = %d)\n", + ret); + break; + } + } + } + + regfree(&session_key_regex); + regfree(&message_regex); + +err: + return -1; +} -- 2.14.3
next prev parent reply other threads:[~2018-01-13 21:37 UTC|newest] Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-01-13 21:34 [PATCHv2 0/7] RFC: Public key encryption of dmesg by the kernel Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-13 21:34 ` [PATCHv2 1/7] crypto: fix memory leak in rsa-kcs1pad encryption Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-13 21:34 ` [PATCHv2 2/7] Move net/ceph/armor to lib/ and add docs Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-13 21:34 ` [PATCHv2 3/7] base64-armor: add bounds checking Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-13 21:34 ` [PATCHv2 4/7] certs: allow in-kernel access of trusted keys Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-13 21:34 ` [PATCHv2 5/7] printk: allow kmsg to be encrypted using public key encryption Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-14 1:48 ` Sergey Senozhatsky 2018-01-14 1:48 ` [kernel-hardening] " Sergey Senozhatsky 2018-01-14 8:01 ` Dan Aloni 2018-01-14 8:01 ` [kernel-hardening] " Dan Aloni 2018-01-15 12:52 ` Steven Rostedt 2018-01-15 12:52 ` [kernel-hardening] " Steven Rostedt 2018-01-16 2:09 ` Sergey Senozhatsky 2018-01-16 2:09 ` [kernel-hardening] " Sergey Senozhatsky 2018-01-16 23:44 ` Daniel Micay 2018-01-17 15:01 ` Steven Rostedt 2018-01-13 21:34 ` Dan Aloni [this message] 2018-01-13 21:34 ` [kernel-hardening] [PATCHv2 6/7] tools: add dmesg decryption program Dan Aloni 2018-01-13 21:34 ` [PATCHv2 7/7] docs: add dmesg encryption doc Dan Aloni 2018-01-13 21:34 ` [kernel-hardening] " Dan Aloni 2018-01-15 9:11 ` [PATCHv2 4/7] certs: allow in-kernel access of trusted keys David Howells 2018-01-15 9:11 ` [kernel-hardening] " David Howells
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20180113213441.52047-7-dan@kernelim.com \ --to=dan@kernelim.com \ --cc=kernel-hardening@lists.openwall.com \ --cc=linux-kernel@vger.kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.