From c4b5bca1e86e481a0376881e5b5eaedfcbedc6bd Mon Sep 17 00:00:00 2001 From: Gyorgy Sarvari Date: Mon, 6 Apr 2026 20:32:53 +0200 Subject: [PATCH] botan: patch CVE-2026-32877 Details: https://nvd.nist.gov/vuln/detail/CVE-2026-32877 Backport the patch that was identified by Debian[1]. The included test passed successfully (along with the other tests). [1]: https://security-tracker.debian.org/tracker/CVE-2026-32877 Signed-off-by: Gyorgy Sarvari Signed-off-by: Anuj Mittal --- .../botan/botan/CVE-2026-32877.patch | 158 ++++++++++++++++++ meta-oe/recipes-crypto/botan/botan_3.10.0.bb | 4 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 meta-oe/recipes-crypto/botan/botan/CVE-2026-32877.patch diff --git a/meta-oe/recipes-crypto/botan/botan/CVE-2026-32877.patch b/meta-oe/recipes-crypto/botan/botan/CVE-2026-32877.patch new file mode 100644 index 0000000000..871f5c9a1b --- /dev/null +++ b/meta-oe/recipes-crypto/botan/botan/CVE-2026-32877.patch @@ -0,0 +1,158 @@ +From a0048a6b97a349a3cb4a5f955d350ab2921719cc Mon Sep 17 00:00:00 2001 +From: Jack Lloyd +Date: Sun, 15 Mar 2026 11:39:50 -0400 +Subject: [PATCH] In SM2 verify the C3 field is of the required length + +Previously the decryption step assumed that C3 was equal in length to the MAC +output. If C3 is shorter than expected, up to 31 bytes of arbitrary heap data +would be compared with the computed MAC. This heap over-read would potentially +result in denial of service. + +CVE: CVE-2026-32877 +Upstream-Status: Backport [https://github.com/randombit/botan/commit/f3c31f96f58f1d1d482032d8f4286dc9ebbc6712] +Signed-off-by: Gyorgy Sarvari +--- + src/lib/pubkey/sm2/sm2_enc.cpp | 7 +++- + src/tests/data/pubkey/sm2_invalid.vec | 60 +++++++++++++++++++++++++++ + src/tests/test_sm2.cpp | 31 ++++++++++++++ + 3 files changed, 97 insertions(+), 1 deletion(-) + create mode 100644 src/tests/data/pubkey/sm2_invalid.vec + +diff --git a/src/lib/pubkey/sm2/sm2_enc.cpp b/src/lib/pubkey/sm2/sm2_enc.cpp +index 7a1b990..1141089 100644 +--- a/src/lib/pubkey/sm2/sm2_enc.cpp ++++ b/src/lib/pubkey/sm2/sm2_enc.cpp +@@ -133,6 +133,11 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption { + .end_cons() + .verify_end(); + ++ // Wrong length so certainly invalid, reject immediately ++ if(C3.size() != m_hash->output_length()) { ++ return secure_vector(); ++ } ++ + std::vector recode_ctext; + DER_Encoder(recode_ctext) + .start_sequence() +@@ -170,7 +175,7 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption { + m_hash->update(y2_bytes); + const auto u = m_hash->final(); + +- if(!CT::is_equal(u.data(), C3.data(), m_hash->output_length()).as_bool()) { ++ if(!CT::is_equal(u, C3).as_bool()) { + return secure_vector(); + } + +diff --git a/src/tests/data/pubkey/sm2_invalid.vec b/src/tests/data/pubkey/sm2_invalid.vec +new file mode 100644 +index 0000000..2517510 +--- /dev/null ++++ b/src/tests/data/pubkey/sm2_invalid.vec +@@ -0,0 +1,60 @@ ++ ++Key = 8C84F7F069CD09D59543ED980CFEB77E68C7D39B9B73D359EA67C0CDB2A86B6F ++ ++ ++# Empty ++Ctext = ++ ++# Just the SEQUENCE marker ++Ctext = 30 ++ ++# Truncated ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E51 ++ ++# C3 MAC too short ++Ctext = 3071022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF041F2E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F36826493860409CA311F43DB0E5E516F ++ ++# C3 MAC too long ++Ctext = 3073022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04212E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F368264938696000409CA311F43DB0E5E516F ++ ++# C3 and C2 fields swapped ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF0409CA311F43DB0E5E516F04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F368264938696 ++ ++# C3 MAC last bit flipped ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386970409CA311F43DB0E5E516F ++ ++# C3 MAC first byte inverted ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF0420D11B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C1 y off by one ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27D004202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C1 x/y serialization boundary shift ++Ctext = 3073022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E500200022100C055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E2704202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C1 is generator point ++Ctext = 3072022032C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7022100BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A004202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C1 is origin (0,0) ++Ctext = 303302010002010004202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C1 x equals field prime ++Ctext = 3072022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# C2 last bit flipped ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516E ++ ++# C2 replaced with empty ++Ctext = 3069022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960400 ++ ++# Trailing byte after SEQUENCE ++Ctext = 3072022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F00 ++ ++# SEQUENCE with non-minimal long-form length ++Ctext = 308172022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# INTEGER x1 with non-minimal leading zero ++Ctext = 307302220000A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF04202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F ++ ++# OCTET STRING C3 with non-minimal long-form length ++Ctext = 3073022100A772DF5FFFDA85C05D9B82233B1E5F7DF7A87788504ABD4F74D265D49E5002C0022055C8A934A29DE58B31A063CDA81F12ABC712FB9ADC8988DA0FBD9FFF304E27CF0481202E1B8A86EF14243EE2E9D74E0D0E7498DFAC2F0EFA8C5883D74F3682649386960409CA311F43DB0E5E516F +diff --git a/src/tests/test_sm2.cpp b/src/tests/test_sm2.cpp +index 2ffb14a..c5d2360 100644 +--- a/src/tests/test_sm2.cpp ++++ b/src/tests/test_sm2.cpp +@@ -9,6 +9,7 @@ + + #if defined(BOTAN_HAS_SM2) + #include "test_pubkey.h" ++ #include + #include + #endif + +@@ -108,4 +109,34 @@ BOTAN_REGISTER_TEST("pubkey", "sm2_keygen", SM2_Keygen_Tests); + + #endif + ++namespace { ++ ++class SM2_Invalid_Ciphertexts : public Text_Based_Test { ++ public: ++ SM2_Invalid_Ciphertexts() : Text_Based_Test("pubkey/sm2_invalid.vec", "Key,Ctext") {} ++ ++ bool clear_between_callbacks() const override { return false; } ++ ++ Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override { ++ Test::Result result("SM2 invalid ciphertext"); ++ ++ const auto key = vars.get_req_bin("Key"); ++ const auto ctext = vars.get_req_bin("Ctext"); ++ ++ const auto group = Botan::EC_Group::from_name("sm2p256v1"); ++ const auto pkey = Botan::SM2_PrivateKey(group, Botan::EC_Scalar::deserialize(group, key).value()); ++ ++ Botan::PK_Decryptor_EME dec(pkey, rng(), "SM3"); ++ ++ result.test_throws("Decryption should fail for invalid ciphertext", ++ [&] { dec.decrypt(ctext); }); ++ ++ return result; ++ } ++}; ++ ++BOTAN_REGISTER_TEST("pubkey", "sm2_invalid_ctext", SM2_Invalid_Ciphertexts); ++ ++} // namespace ++ + } // namespace Botan_Tests diff --git a/meta-oe/recipes-crypto/botan/botan_3.10.0.bb b/meta-oe/recipes-crypto/botan/botan_3.10.0.bb index e079dd73de..392c1aac94 100644 --- a/meta-oe/recipes-crypto/botan/botan_3.10.0.bb +++ b/meta-oe/recipes-crypto/botan/botan_3.10.0.bb @@ -4,7 +4,9 @@ LICENSE = "BSD-2-Clause" LIC_FILES_CHKSUM = "file://license.txt;md5=3f911cecfc74a2d9f1ead9a07bd92a6e" SECTION = "libs" -SRC_URI = "https://botan.randombit.net/releases/Botan-${PV}.tar.xz" +SRC_URI = "https://botan.randombit.net/releases/Botan-${PV}.tar.xz \ + file://CVE-2026-32877.patch \ + " SRC_URI[sha256sum] = "fde194236f6d5434f136ea0a0627f6cc9d26af8b96e9f1e1c7d8c82cd90f4f24" S = "${UNPACKDIR}/Botan-${PV}"