]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Add option to disable RSAES-PKCS1-v1_5
authorZoltan Fridrich <zfridric@redhat.com>
Tue, 26 Mar 2024 10:48:58 +0000 (11:48 +0100)
committerZoltan Fridrich <zfridric@redhat.com>
Tue, 2 Apr 2024 12:25:42 +0000 (14:25 +0200)
A new option `allow-rsa-pkcs1-encrypt` has been added into the
system-wide library configuration which allows to enable/disable
the RSAES-PKCS1-v1_5. Currently, the RSAES-PKCS1-v1_5 is enabled
by default.

Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
12 files changed:
.gitignore
NEWS
doc/cha-config.texi
lib/errors.c
lib/fips.c
lib/gnutls_int.h
lib/includes/gnutls/gnutls.h.in
lib/nettle/pk.c
lib/priority.c
tests/Makefile.am
tests/rsaes-pkcs1-v1_5.c [new file with mode: 0644]
tests/system-override-allow-rsa-pkcs1-encrypt.sh [new file with mode: 0755]

index ecc89316e57c21896a7e0a2099b5af32458bba20..5a66fa4e6a2d890a30d73be08374b9f222715c85 100644 (file)
@@ -672,6 +672,7 @@ tests/rsa-psk
 tests/rsa-psk-cb
 tests/rsa-rsa-oaep
 tests/rsa-rsa-pss
+tests/rsaes-pkcs1-v1_5
 tests/safe-renegotiation/Makefile
 tests/safe-renegotiation/Makefile.in
 tests/safe-renegotiation/srn*
diff --git a/NEWS b/NEWS
index 85efb5680ccc0f250ced4b96cbd396d387e23731..afefaec0cb213ae5911457037b1fd34412ea51d7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,20 @@ Copyright (C) 2000-2016 Free Software Foundation, Inc.
 Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
 See the end for copying conditions.
 
+* Version 3.8.5 (unreleased ????-??-??)
+
+** libgnutls: Due to majority of usages and implementations of
+   RSA decryption with PKCS#1 v1.5 padding being incorrect,
+   leaving them vulnerable to Marvin attack, the RSAES-PKCS1-v1_5
+   is being deprecated (encryption and decryption) and will be
+   disabled in the future. A new option `allow-rsa-pkcs1-encrypt`
+   has been added into the system-wide library configuration which
+   allows to enable/disable the RSAES-PKCS1-v1_5. Currently, the
+   RSAES-PKCS1-v1_5 is enabled by default.
+
+** API and ABI modifications:
+No changes since last version.
+
 * Version 3.8.4 (released 2024-03-18)
 
 ** libgnutls: RSA-OAEP encryption scheme is now supported
index eaab7fd799ec33d4edf52a80e8c1ce1306bf8b46..ab74157a42e33ebe5f4eeab0df092aa5efa1450d 100644 (file)
@@ -27,6 +27,7 @@ used can be queried using @funcref{gnutls_get_system_config_file}.
 * Overriding the parameter verification profile::
 * Overriding the default priority string::
 * Enabling/Disabling system/acceleration protocols::
+* Enabling/Disabling RSAES-PKCS1-v1_5
 @end menu
 
 @node Application-specific priority strings
@@ -264,3 +265,17 @@ ktls = true
 @subsection Enabling KTLS
 When GnuTLS is build with -–enable-ktls configuration, KTLS is disabled by default.
 This can be enabled by setting @code{ktls = true} in @code{[global]} section.
+
+
+@node Enabling/Disabling RSAES-PKCS1-v1_5
+@section Enabling/Disabling RSAES-PKCS1-v1_5
+
+This option can be used to enable/disable RSA PKCS1 v1.5 encryption and decryption
+in GnuTLS. The RSAES-PKCS1-v1_5 is enabled by default.
+
+Below example shows how to explicitely disable the RSAES-PKCS1-v1_5.
+@example
+[overrides]
+allow-rsa-pkcs1-encrypt = false
+
+@end example
index 29b97bedfb48e6ac37693da390670ab72fab30db..e6bb4bd9f8b94ca3172b1049450bb915174fb7f3 100644 (file)
@@ -417,6 +417,8 @@ static const gnutls_error_entry error_entries[] = {
                    GNUTLS_E_NO_COMMON_KEY_SHARE),
        ERROR_ENTRY(N_("The early data were rejected."),
                    GNUTLS_E_EARLY_DATA_REJECTED),
+       ERROR_ENTRY(N_("The encryption algorithm is not supported."),
+                   GNUTLS_E_UNSUPPORTED_ENCRYPTION_ALGORITHM),
        { NULL, NULL, 0 }
 };
 
index 4d3b4f608991ee3e25b8904065cd88a3a5343399..59e0808689ced766e1e1d4d9aabb4418a4cec665 100644 (file)
@@ -594,9 +594,11 @@ int _gnutls_fips_perform_self_checks2(void)
        }
 
        /* PK */
-       ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
-       if (ret < 0) {
-               return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+       if (_gnutls_config_is_rsa_pkcs1_encrypt_allowed()) {
+               ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
+               if (ret < 0) {
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
        }
 
        ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA);
index 8cf9a8715794c184a3520f290cad1391d464e3bf..cb407e6eb620b068c3c1444820088fe1d2b13d54 100644 (file)
@@ -1793,5 +1793,6 @@ get_certificate_type(gnutls_session_t session, gnutls_ctype_target_t target)
 extern unsigned int _gnutls_global_version;
 
 bool _gnutls_config_is_ktls_enabled(void);
+bool _gnutls_config_is_rsa_pkcs1_encrypt_allowed(void);
 
 #endif /* GNUTLS_LIB_GNUTLS_INT_H */
index e31aad3a0ce0ab8ea6db28c29c8ddcfdb0d9ddf4..afecfaa3998cfc49f3c8b1d72f1179f271b98bb3 100644 (file)
@@ -3379,6 +3379,7 @@ gnutls_transport_is_ktls_enabled(gnutls_session_t session);
 #define GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS -81
 #define GNUTLS_E_RECEIVED_DISALLOWED_NAME -82 /* GNUTLS_A_ILLEGAL_PARAMETER */
 #define GNUTLS_E_CERTIFICATE_REQUIRED -112 /* GNUTLS_A_CERTIFICATE_REQUIRED */
+#define GNUTLS_E_UNSUPPORTED_ENCRYPTION_ALGORITHM -113
 
 /* returned if you need to generate temporary RSA
    * parameters. These are needed for export cipher suites.
index 13546673eb24f05f58c39dd7fa43f62bfb432af9..3232ff1b0d12d51adf60af298f6230c4129e2fe0 100644 (file)
@@ -769,6 +769,12 @@ static int _wrap_nettle_pk_encrypt(gnutls_pk_algorithm_t algo,
                struct rsa_public_key pub;
                nettle_random_func *random_func;
 
+               if (!_gnutls_config_is_rsa_pkcs1_encrypt_allowed()) {
+                       ret = gnutls_assert_val(
+                               GNUTLS_E_UNSUPPORTED_ENCRYPTION_ALGORITHM);
+                       goto cleanup;
+               }
+
                /* RSA encryption with PKCS#1 v1.5 padding is not approved */
                not_approved = true;
 
@@ -939,6 +945,12 @@ static int _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
                size_t length;
                nettle_random_func *random_func;
 
+               if (!_gnutls_config_is_rsa_pkcs1_encrypt_allowed()) {
+                       ret = gnutls_assert_val(
+                               GNUTLS_E_UNSUPPORTED_ENCRYPTION_ALGORITHM);
+                       goto cleanup;
+               }
+
                /* RSA decryption with PKCS#1 v1.5 padding is not approved */
                not_approved = true;
 
@@ -1115,6 +1127,12 @@ static int _wrap_nettle_pk_decrypt2(gnutls_pk_algorithm_t algo,
 
        switch (algo) {
        case GNUTLS_PK_RSA:
+               if (!_gnutls_config_is_rsa_pkcs1_encrypt_allowed()) {
+                       ret = gnutls_assert_val(
+                               GNUTLS_E_UNSUPPORTED_ENCRYPTION_ALGORITHM);
+                       goto fail;
+               }
+
                /* RSA decryption with PKCS#1 v1.5 padding is not approved */
                not_approved = true;
 
index d84af07f99b5edfc0affccc85c10e2a0d4b6a173..8abe00d1ff6b6c844d7959a385a57268d6b46acd 100644 (file)
@@ -996,6 +996,7 @@ static void dummy_func(gnutls_priority_t c)
 struct cfg {
        bool allowlisting;
        bool ktls_enabled;
+       bool allow_rsa_pkcs1_encrypt;
 
        name_val_array_t priority_strings;
        char *priority_string;
@@ -1119,6 +1120,7 @@ static inline void cfg_steal(struct cfg *dst, struct cfg *src)
 
        dst->allowlisting = src->allowlisting;
        dst->ktls_enabled = src->ktls_enabled;
+       dst->allow_rsa_pkcs1_encrypt = src->allow_rsa_pkcs1_encrypt;
        dst->force_ext_master_secret = src->force_ext_master_secret;
        dst->force_ext_master_secret_set = src->force_ext_master_secret_set;
        memcpy(dst->ciphers, src->ciphers, sizeof(src->ciphers));
@@ -1421,6 +1423,9 @@ static inline int cfg_apply(struct cfg *cfg, struct ini_ctx *ctx)
                _gnutls_default_priority_string = cfg->default_priority_string;
        }
 
+       /* enable RSA-PKCS1-V1_5 by default */
+       cfg->allow_rsa_pkcs1_encrypt = true;
+
        if (cfg->allowlisting) {
                /* also updates `flags` of global `hash_algorithms[]` */
                ret = cfg_hashes_set_array(cfg, ctx->hashes, ctx->hashes_size);
@@ -2051,6 +2056,20 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name,
                                        return 0;
                                goto exit;
                        }
+               } else if (c_strcasecmp(name, "allow-rsa-pkcs1-encrypt") == 0) {
+                       p = clear_spaces(value, str);
+                       if (c_strcasecmp(p, "true") == 0) {
+                               cfg->allow_rsa_pkcs1_encrypt = true;
+                       } else if (c_strcasecmp(p, "false") == 0) {
+                               cfg->allow_rsa_pkcs1_encrypt = false;
+                       } else {
+                               _gnutls_debug_log(
+                                       "cfg: unknown RSA PKCS1 encryption mode %s\n",
+                                       p);
+                               if (fail_on_invalid_config)
+                                       return 0;
+                               goto exit;
+                       }
                } else {
                        _gnutls_debug_log("unknown parameter %s\n", name);
                        if (fail_on_invalid_config)
@@ -3897,6 +3916,11 @@ bool _gnutls_config_is_ktls_enabled(void)
        return system_wide_config.ktls_enabled;
 }
 
+bool _gnutls_config_is_rsa_pkcs1_encrypt_allowed(void)
+{
+       return system_wide_config.allow_rsa_pkcs1_encrypt;
+}
+
 /*
  * high-level interface for overriding configuration files
  */
index fb9e55a978ef461778cf99faceb15d2a95e69f1a..e39a3b3f134b748a76734c5b47489b302d7b96b9 100644 (file)
@@ -556,6 +556,11 @@ dist_check_SCRIPTS += system-override-sig-allowlist.sh \
        protocol-set-allowlist.sh
 indirect_tests += system-override-curves-allowlist
 indirect_tests += protocol-set-allowlist
+
+dist_check_SCRIPTS += system-override-allow-rsa-pkcs1-encrypt.sh
+indirect_tests += rsaes-pkcs1-v1_5
+rsaes_pkcs1_v1_5_SOURCES = rsaes-pkcs1-v1_5.c
+rsaes_pkcs1_v1_5_LDADD = $(COMMON_GNUTLS_LDADD)
 endif
 
 dist_check_SCRIPTS += gnutls-cli-self-signed.sh gnutls-cli-invalid-crl.sh gnutls-cli-rawpk.sh
diff --git a/tests/rsaes-pkcs1-v1_5.c b/tests/rsaes-pkcs1-v1_5.c
new file mode 100644 (file)
index 0000000..ac5e375
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Author: Zoltan Fridrich
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+
+static const char pem[] =
+       "-----BEGIN RSA PRIVATE KEY-----\n"
+       "MIICXAIBAAKBgQC7ZkP18sXXtozMxd/1iDuxyUtqDqGtIFBACIChT1yj0Phsz+Y8\n"
+       "9+wEdhMXi2SJIlvA3VN8O+18BLuAuSi+jpvGjqClEsv1Vx6i57u3M0mf47tKrmpN\n"
+       "aP/JEeIyjc49gAuNde/YAIGPKAQDoCKNYQQH+rY3fSEHSdIJYWmYkKNYqQIDAQAB\n"
+       "AoGADpmARG5CQxS+AesNkGmpauepiCz1JBF/JwnyiX6vEzUh0Ypd39SZztwrDxvF\n"
+       "PJjQaKVljml1zkJpIDVsqvHdyVdse8M+Qn6hw4x2p5rogdvhhIL1mdWo7jWeVJTF\n"
+       "RKB7zLdMPs3ySdtcIQaF9nUAQ2KJEvldkO3m/bRJFEp54k0CQQDYy+RlTmwRD6hy\n"
+       "7UtMjR0H3CSZJeQ8svMCxHLmOluG9H1UKk55ZBYfRTsXniqUkJBZ5wuV1L+pR9EK\n"
+       "ca89a+1VAkEA3UmBelwEv2u9cAU1QjKjmwju1JgXbrjEohK+3B5y0ESEXPAwNQT9\n"
+       "TrDM1m9AyxYTWLxX93dI5QwNFJtmbtjeBQJARSCWXhsoaDRG8QZrCSjBxfzTCqZD\n"
+       "ZXtl807ymCipgJm60LiAt0JLr4LiucAsMZz6+j+quQbSakbFCACB8SLV1QJBAKZQ\n"
+       "YKf+EPNtnmta/rRKKvySsi3GQZZN+Dt3q0r094XgeTsAqrqujVNfPhTMeP4qEVBX\n"
+       "/iVX2cmMTSh3w3z8MaECQEp0XJWDVKOwcTW6Ajp9SowtmiZ3YDYo1LF9igb4iaLv\n"
+       "sWZGfbnU3ryjvkb6YuFjgtzbZDZHWQCo8/cOtOBmPdk=\n"
+       "-----END RSA PRIVATE KEY-----\n";
+
+const gnutls_datum_t privkey_datum = { (void *)pem, sizeof(pem) };
+const gnutls_datum_t in_message = { (void *)"hello", 5 };
+
+int main(void)
+{
+       int ret = EXIT_FAILURE;
+       gnutls_datum_t crypt = { NULL, 0 };
+       gnutls_datum_t out_message = { NULL, 0 };
+       gnutls_pubkey_t pubkey = NULL;
+       gnutls_privkey_t privkey = NULL;
+
+       gnutls_global_init();
+       assert(gnutls_privkey_init(&privkey) >= 0);
+       assert(gnutls_pubkey_init(&pubkey) >= 0);
+       assert(gnutls_privkey_import_x509_raw(privkey, &privkey_datum,
+                                             GNUTLS_X509_FMT_PEM, NULL,
+                                             0) >= 0);
+       assert(gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0) >= 0);
+
+       if (gnutls_pubkey_encrypt_data(pubkey, 0, &in_message, &crypt) < 0 ||
+           gnutls_privkey_decrypt_data(privkey, 0, &crypt, &out_message) < 0)
+               goto cleanup;
+
+       assert(in_message.size == out_message.size);
+       assert(memcmp(out_message.data, in_message.data, in_message.size) == 0);
+       ret = EXIT_SUCCESS;
+cleanup:
+       gnutls_free(crypt.data);
+       gnutls_free(out_message.data);
+       gnutls_privkey_deinit(privkey);
+       gnutls_pubkey_deinit(pubkey);
+       gnutls_global_deinit();
+       return ret;
+}
diff --git a/tests/system-override-allow-rsa-pkcs1-encrypt.sh b/tests/system-override-allow-rsa-pkcs1-encrypt.sh
new file mode 100755 (executable)
index 0000000..b7d477c
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# Copyright (C) 2024 Red Hat, Inc.
+#
+# Author: Zoltan Fridrich
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>
+
+: ${srcdir=.}
+TEST=${srcdir}/rsaes-pkcs1-v1_5
+CONF=${srcdir}/config.$$.tmp
+export GNUTLS_SYSTEM_PRIORITY_FILE=${CONF}
+export GNUTLS_SYSTEM_PRIORITY_FAIL_ON_INVALID=1
+
+if test "${WINDIR}" != ""; then
+       exit 77
+fi
+
+if test "${GNUTLS_FORCE_FIPS_MODE}" = 1; then
+       exit 77
+fi
+
+cat <<_EOF_ > ${CONF}
+[overrides]
+allow-rsa-pkcs1-encrypt = true
+_EOF_
+
+${TEST} && fail "RSAES-PKCS1-v1_5 expected to succeed"
+
+cat <<_EOF_ > ${CONF}
+[overrides]
+allow-rsa-pkcs1-encrypt = false
+_EOF_
+
+${TEST} || fail "RSAES-PKCS1-v1_5 expected to fail"
+
+unset GNUTLS_SYSTEM_PRIORITY_FILE
+unset GNUTLS_SYSTEM_PRIORITY_FAIL_ON_INVALID
+exit 0