From 4c9fee33f3dd0b97e23aadda4a31e530dceef86c Mon Sep 17 00:00:00 2001 From: Denys Date: Tue, 10 Sep 2024 01:49:27 +0300 Subject: [PATCH] Add old ciphers check on library level --- src/lib/rnp.cpp | 30 +++++++++++ src/tests/ffi-enc.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++ src/tests/support.h | 1 + 3 files changed, 151 insertions(+) diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 5d2fbc62c9..36388eb76e 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -2714,6 +2714,32 @@ try { } FFI_GUARD +static bool +rnp_check_old_ciphers(rnp_ffi_t ffi, const char *cipher) +{ + uint32_t security_level = 0; + + if (rnp_get_security_rule(ffi, + RNP_FEATURE_SYMM_ALG, + cipher, + ffi->context.time(), + NULL, + NULL, + &security_level)) { + FFI_LOG(ffi, "Failed to get security rules for cipher algorithm \'%s\'!", + cipher); + return false; + } + + if (security_level < RNP_SECURITY_DEFAULT) { + FFI_LOG(ffi, "Cipher algorithm \'%s\' is cryptographically weak!", + cipher); + return false; + } + /* TODO: check other weak algorithms and key sizes */ + return true; +} + rnp_result_t rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op, const char *cipher) try { @@ -2721,6 +2747,10 @@ try { if (!op || !cipher) { return RNP_ERROR_NULL_POINTER; } + if (!rnp_check_old_ciphers(op->ffi, cipher)) { + FFI_LOG(op->ffi, "Deprecated cipher: %s", cipher); + return RNP_ERROR_BAD_PARAMETERS; + } if (!str_to_cipher(cipher, &op->rnpctx.ealg)) { FFI_LOG(op->ffi, "Invalid cipher: %s", cipher); return RNP_ERROR_BAD_PARAMETERS; diff --git a/src/tests/ffi-enc.cpp b/src/tests/ffi-enc.cpp index c7308dbef4..6493f58140 100644 --- a/src/tests/ffi-enc.cpp +++ b/src/tests/ffi-enc.cpp @@ -691,6 +691,126 @@ TEST_F(rnp_tests, test_ffi_encrypt_pk) rnp_ffi_destroy(ffi); } +TEST_F(rnp_tests, test_ffi_select_deprecated_ciphers) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + rnp_op_encrypt_t op = NULL; + const char * plaintext = "data1"; + + // setup FFI + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + + assert_rnp_success( + rnp_input_from_memory(&input, (const uint8_t *) plaintext, strlen(plaintext), false)); + assert_rnp_success(rnp_output_to_path(&output, "encrypted")); + // create encrypt operation + assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output)); + + /* check predefined rules */ + uint32_t flags = 0; + uint64_t from = 0; + uint32_t level = 0; + assert_rnp_success(rnp_get_security_rule( + ffi, RNP_FEATURE_SYMM_ALG, "CAST5", CAST5_3DES_IDEA_BLOWFISH_FROM + 1, &flags, &from, &level)); + assert_int_equal(from, CAST5_3DES_IDEA_BLOWFISH_FROM); + assert_int_equal(level, RNP_SECURITY_INSECURE); + + ffi->context.set_time(CAST5_3DES_IDEA_BLOWFISH_FROM + 1); + // set the data encryption cipher + if (cast5_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5")); + } + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "TRIPLEDES")); + if (idea_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "IDEA")); + } + if (blowfish_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "BLOWFISH")); + } + + ffi->context.set_time(CAST5_3DES_IDEA_BLOWFISH_FROM - 1); + + if (cast5_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5")); + } + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "TRIPLEDES")); + if (idea_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "IDEA")); + } + if (blowfish_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "BLOWFISH")); + } + + // cleanup + assert_rnp_success(rnp_op_encrypt_destroy(op)); + op = NULL; + rnp_ffi_destroy(ffi); + + // check again but with removing rules now + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + // create encrypt operation + assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output)); + + ffi->context.set_time(CAST5_3DES_IDEA_BLOWFISH_FROM + 1); + // set the data encryption cipher + if (cast5_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "CAST5")); + } + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "TRIPLEDES")); + if (idea_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "IDEA")); + } + if (blowfish_enabled()) { + assert_rnp_failure(rnp_op_encrypt_set_cipher(op, "BLOWFISH")); + } + + size_t removed = 0; + if (cast5_enabled()) { + removed = 0; + assert_rnp_success(rnp_remove_security_rule( + ffi, RNP_FEATURE_SYMM_ALG, "CAST5", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed)); + assert_int_equal(removed, 1); + } + removed = 0; + assert_rnp_success( + rnp_remove_security_rule(ffi, RNP_FEATURE_SYMM_ALG, "TRIPLEDES", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed)); + assert_int_equal(removed, 1); + if (idea_enabled()) { + removed = 0; + assert_rnp_success(rnp_remove_security_rule( + ffi, RNP_FEATURE_SYMM_ALG, "IDEA", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed)); + assert_int_equal(removed, 1); + } + if (blowfish_enabled()) { + removed = 0; + assert_rnp_success(rnp_remove_security_rule( + ffi, RNP_FEATURE_SYMM_ALG, "BLOWFISH", 0, RNP_SECURITY_REMOVE_ALL, 0, &removed)); + assert_int_equal(removed, 1); + } + + if (cast5_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5")); + } + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "TRIPLEDES")); + if (idea_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "IDEA")); + } + if (blowfish_enabled()) { + assert_rnp_success(rnp_op_encrypt_set_cipher(op, "BLOWFISH")); + } + + // cleanup + assert_rnp_success(rnp_input_destroy(input)); + input = NULL; + assert_rnp_success(rnp_output_destroy(output)); + output = NULL; + assert_rnp_success(rnp_op_encrypt_destroy(op)); + op = NULL; + rnp_ffi_destroy(ffi); +} + static bool first_key_password_provider(rnp_ffi_t ffi, void * app_ctx, diff --git a/src/tests/support.h b/src/tests/support.h index 0468598048..20dbde833e 100644 --- a/src/tests/support.h +++ b/src/tests/support.h @@ -313,5 +313,6 @@ bool test_load_gpg_check_key(rnp::KeyStore *pub, rnp::KeyStore *sec, const char #define MD5_FROM 1325376000 #define SHA1_DATA_FROM 1547856000 #define SHA1_KEY_FROM 1705629600 +#define CAST5_3DES_IDEA_BLOWFISH_FROM 1727730000 // TODO: tbd #endif /* SUPPORT_H_ */