From 554730b01b5e5687a869387d1a5b0a2fd55aa880 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 3 Jun 2024 14:23:58 -0400 Subject: [PATCH] Add test to verify TLS depadding works correctly Signed-off-by: Simo Sorce --- tests/meson.build | 24 +++++----- tests/tcmpkeys.c | 81 +------------------------------- tests/tlsctx.c | 114 ++++++++++++++++++++++++++++++++++++++-------- tests/util.c | 94 ++++++++++++++++++++++++++++++++++++++ tests/util.h | 5 ++ 5 files changed, 206 insertions(+), 112 deletions(-) create mode 100644 tests/util.c create mode 100644 tests/util.h diff --git a/tests/meson.build b/tests/meson.build index 07c53607..2dcb1e5a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -93,20 +93,20 @@ if get_option('b_sanitize') == 'address' endif endif -test_programs = [ - 'tsession', - 'tgenkey', - 'tlsctx', - 'tdigests', - 'treadkeys', - 'tcmpkeys', - 'tfork', - 'pincache', -] +test_programs = { + 'tsession': ['tsession.c'], + 'tgenkey': ['tgenkey.c'], + 'tlsctx': ['tlsctx.c', 'util.c'], + 'tdigests': ['tdigests.c'], + 'treadkeys': ['treadkeys.c'], + 'tcmpkeys': ['tcmpkeys.c', 'util.c'], + 'tfork': ['tfork.c'], + 'pincache': ['pincache.c'], +} test_executables = [] -foreach t : test_programs - t = executable(t, '@0@.c'.format(t), +foreach t, sources : test_programs + t = executable(t, sources, build_by_default: false, include_directories: [configinc], dependencies: [libcrypto, libssl]) diff --git a/tests/tcmpkeys.c b/tests/tcmpkeys.c index b261729c..8402c0cb 100644 --- a/tests/tcmpkeys.c +++ b/tests/tcmpkeys.c @@ -7,86 +7,7 @@ #include #include #include - -static void ossl_err_print(void) -{ - bool first = true; - unsigned long err = 0; - while (true) { - const char *file, *func, *data; - int line; - err = ERR_get_error_all(&file, &line, &func, &data, NULL); - if (err == 0) { - break; - } - - char buf[1024]; - ERR_error_string_n(err, buf, sizeof(buf)); - - const char *fmt = - first ? ": %s (in function %s in %s:%d): %s\n" - : " caused by: %s (in function %s in %s:%d): %s\n"; - fprintf(stderr, fmt, buf, func, file, line, data); - - first = false; - } - if (first) { - fprintf(stderr, "\n"); - } -} - -static EVP_PKEY *load_key(const char *uri) -{ - OSSL_STORE_CTX *store; - OSSL_STORE_INFO *info; - EVP_PKEY *key = NULL; - - store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); - if (store == NULL) { - fprintf(stderr, "Failed to open store: %s\n", uri); - ossl_err_print(); - exit(EXIT_FAILURE); - } - - if (strncmp(uri, "pkcs11:", 7) && strstr(uri, "type=private") == NULL) { - /* This is a workaround for OpenSSL < 3.2.0 where the code fails - * to correctly source public keys unless explicitly requested - * via an expect hint */ - if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PUBKEY) != 1) { - fprintf(stderr, "Failed to expect Public Key File\n"); - exit(EXIT_FAILURE); - } - } - - for (info = OSSL_STORE_load(store); info != NULL; - info = OSSL_STORE_load(store)) { - int type = OSSL_STORE_INFO_get_type(info); - - if (key != NULL) { - fprintf(stderr, "Multiple keys matching URI: %s\n", uri); - exit(EXIT_FAILURE); - } - - switch (type) { - case OSSL_STORE_INFO_PUBKEY: - key = OSSL_STORE_INFO_get1_PUBKEY(info); - break; - case OSSL_STORE_INFO_PKEY: - key = OSSL_STORE_INFO_get1_PKEY(info); - break; - } - OSSL_STORE_INFO_free(info); - } - - if (key == NULL) { - fprintf(stderr, "Failed to load key from URI: %s\n", uri); - ossl_err_print(); - exit(EXIT_FAILURE); - } - OSSL_STORE_close(store); - - return key; -} +#include "util.h" int main(int argc, char *argv[]) { diff --git a/tests/tlsctx.c b/tests/tlsctx.c index 8e159430..882d872d 100644 --- a/tests/tlsctx.c +++ b/tests/tlsctx.c @@ -4,32 +4,104 @@ #include #include #include -#include +#include +#include +#include +#include "util.h" -static void ossl_err_print(void) +static void test_pkcs1_with_tls_padding(void) { - bool first = true; - unsigned long err = 0; - while (true) { - const char *file, *func, *data; - int line; - err = ERR_get_error_all(&file, &line, &func, &data, NULL); - if (err == 0) { - break; - } + EVP_PKEY_CTX *ctx; + EVP_PKEY *prikey; + EVP_PKEY *pubkey; + unsigned char plain[SSL_MAX_MASTER_KEY_LENGTH + 2] = { 0x03, 0x03, 0x01 }; + unsigned char enc[1024]; + unsigned char dec[1024]; + size_t enclen; + size_t declen; + unsigned int ver = 0x0303; + const OSSL_PARAM ver_params[] = { + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, &ver), + OSSL_PARAM_END + }; + int err; - char buf[1024]; - ERR_error_string_n(err, buf, sizeof(buf)); + pubkey = load_key(getenv("PUBURI")); - const char *fmt = - first ? ": %s (in function %s in %s:%d): %s\n" - : " caused by: %s (in function %s in %s:%d): %s\n"; - fprintf(stderr, fmt, buf, func, file, line, data); + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pubkey, NULL); + if (!ctx) { + fprintf(stderr, "Failed to init pkey ctx for puburi\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + err = EVP_PKEY_encrypt_init(ctx); + if (err != 1) { + fprintf(stderr, "Failed to init encrypt ctx\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); + if (err != 1) { + fprintf(stderr, "Failed to set padding on encrypt ctx\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + + enclen = sizeof(enc); + err = EVP_PKEY_encrypt(ctx, enc, &enclen, plain, sizeof(plain)); + if (err != 1) { + fprintf(stderr, "Failed to encrypt TLS master key\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pubkey); + + prikey = load_key(getenv("PRIURI")); + + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, prikey, NULL); + if (!ctx) { + fprintf(stderr, "Failed to init pkey ctx for priuri\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + err = EVP_PKEY_decrypt_init(ctx); + if (err != 1) { + fprintf(stderr, "Failed to init decrypt ctx\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_WITH_TLS_PADDING); + if (err != 1) { + fprintf(stderr, "Failed to set padding on decrypt ctx\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } - first = false; + err = EVP_PKEY_CTX_set_params(ctx, ver_params); + if (err != 1) { + fprintf(stderr, "Failed to set version params\n"); + ossl_err_print(); + exit(EXIT_FAILURE); } - if (first) { - fprintf(stderr, "\n"); + + declen = sizeof(dec); + err = EVP_PKEY_decrypt(ctx, dec, &declen, enc, enclen); + if (err != 1) { + fprintf(stderr, "Failed to decrypt TLS master key\n"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(prikey); + + if ((declen != sizeof(plain) - 2) + || (memcmp(plain + 2, dec, declen) != 0)) { + fprintf(stderr, "Fail, decrypted master secret differs from input\n"); + ossl_err_print(); + exit(EXIT_FAILURE); } } @@ -48,5 +120,7 @@ int main(int argc, char *argv[]) SSL_CTX_free(ctx); + test_pkcs1_with_tls_padding(); + exit(EXIT_SUCCESS); } diff --git a/tests/util.c b/tests/util.c new file mode 100644 index 00000000..eedb4cb7 --- /dev/null +++ b/tests/util.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2024 Simo Sorce + SPDX-License-Identifier: Apache-2.0 */ + +#include +#include +#include +#include +#include "util.h" + +void ossl_err_print(void) +{ + bool first = true; + unsigned long err = 0; + while (true) { + const char *file, *func, *data; + int line; + err = ERR_get_error_all(&file, &line, &func, &data, NULL); + if (err == 0) { + break; + } + + char buf[1024]; + ERR_error_string_n(err, buf, sizeof(buf)); + + const char *fmt = + first ? ": %s (in function %s in %s:%d): %s\n" + : " caused by: %s (in function %s in %s:%d): %s\n"; + fprintf(stderr, fmt, buf, func, file, line, data); + + first = false; + } + if (first) { + fprintf(stderr, "\n"); + } +} + +EVP_PKEY *load_key(const char *uri) +{ + OSSL_STORE_CTX *store; + OSSL_STORE_INFO *info; + EVP_PKEY *key = NULL; + + if (!uri) { + fprintf(stderr, "Invalid NULL uri"); + ossl_err_print(); + exit(EXIT_FAILURE); + } + + store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (store == NULL) { + fprintf(stderr, "Failed to open store: %s\n", uri); + ossl_err_print(); + exit(EXIT_FAILURE); + } + + if (strncmp(uri, "pkcs11:", 7) && strstr(uri, "type=private") == NULL) { + /* This is a workaround for OpenSSL < 3.2.0 where the code fails + * to correctly source public keys unless explicitly requested + * via an expect hint */ + if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PUBKEY) != 1) { + fprintf(stderr, "Failed to expect Public Key File\n"); + exit(EXIT_FAILURE); + } + } + + for (info = OSSL_STORE_load(store); info != NULL; + info = OSSL_STORE_load(store)) { + int type = OSSL_STORE_INFO_get_type(info); + + if (key != NULL) { + fprintf(stderr, "Multiple keys matching URI: %s\n", uri); + exit(EXIT_FAILURE); + } + + switch (type) { + case OSSL_STORE_INFO_PUBKEY: + key = OSSL_STORE_INFO_get1_PUBKEY(info); + break; + case OSSL_STORE_INFO_PKEY: + key = OSSL_STORE_INFO_get1_PKEY(info); + break; + } + OSSL_STORE_INFO_free(info); + } + + if (key == NULL) { + fprintf(stderr, "Failed to load key from URI: %s\n", uri); + ossl_err_print(); + exit(EXIT_FAILURE); + } + OSSL_STORE_close(store); + + return key; +} diff --git a/tests/util.h b/tests/util.h new file mode 100644 index 00000000..1fdc9a13 --- /dev/null +++ b/tests/util.h @@ -0,0 +1,5 @@ +/* Copyright (C) 2024 Simo Sorce + SPDX-License-Identifier: Apache-2.0 */ + +void ossl_err_print(void); +EVP_PKEY *load_key(const char *uri);