ecdh (Botan): bounds-check public point length before reading#2390
Open
metsw24-max wants to merge 1 commit into
Open
ecdh (Botan): bounds-check public point length before reading#2390metsw24-max wants to merge 1 commit into
metsw24-max wants to merge 1 commit into
Conversation
load_public_key() previously verified only that key.p was non-empty and began with the 0x04 uncompressed-point prefix before computing &key.p[1] and &key.p[1 + curve_order] for the two coordinates. For any non-25519 curve, an input whose key.p is shorter than 2 * curve_order + 1 bytes causes botan_mp_from_bin() to read past the end of the std::vector storage backing key.p (heap-buffer-overflow read). The matching sibling routines pgp::ecdsa::load_public_key and pgp::sm2::load_public_key already reject this exact case with keydata.p.size() != 2 * curve_order + 1; mirror that check here so the Botan ECDH backend cannot dereference past the supplied buffer when validating an attacker-controlled public key during packet parsing.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2390 +/- ##
==========================================
- Coverage 85.46% 85.45% -0.01%
==========================================
Files 126 126
Lines 22711 22714 +3
==========================================
+ Hits 19409 19410 +1
- Misses 3302 3304 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
pgp::ecdh::load_public_key()insrc/lib/crypto/ecdh.cpp(Botan backend) only verifies thatkey.pis non-empty and that its first byte is0x04(the SEC1 uncompressed-point prefix) before computing pointers intokey.pfor the two coordinates:https://github.com/rnpgp/rnp/blob/main/src/lib/crypto/ecdh.cpp#L96-L103
rnp::bn(const uint8_t *val, size_t len)callsbotan_mp_from_bin(bn_, val, len), which readslenbytes starting atval. For any non-25519 curve (P-256, P-384, P-521, brainpoolP{256,384,512}r1, secp256k1) an input whosekey.pis shorter than2 * curve_order + 1bytes — in the worst case just the single byte{0x04}— causes bothbotan_mp_from_bin()calls to read past the end of thestd::vector<uint8_t>storage backingkey.p(heap out-of-bounds read of up to 64 bytes for P-256, more for larger curves).Reproduction / observation
key.pis populated directly from MPI bytes insideECKeyMaterial::parse()insrc/lib/key_material.cpp(viapgp_packet_body_t::get(pgp::mpi&)), which only enforces an upper bound (PGP_MPINT_SIZE) and that the MPI is non-empty. An attacker can therefore deliver a public ECDH key packet whosepMPI is a single0x04byte.ECDHKeyMaterial::validate_material->ecdh::validate_key->load_public_keythen performs the OOB read above before any other check rejects the malformed key.The two sibling implementations in the same directory already reject this exact case explicitly:
src/lib/crypto/ecdsa.cpplines 48-51:src/lib/crypto/sm2.cppline 48:so the ECDH backend was the outlier. The OSSL ECDH backend (
src/lib/crypto/ecdh_ossl.cpp) is unaffected because it delegates toEC_POINT_oct2point(), which validates the encoded length internally.Fix
Add the same
key.p.size() != 2 * curve_order + 1length check inload_public_key()before constructing the twornp::bncoordinates. The check is local to the callee, mirrors the established pattern inecdsa.cpp/sm2.cpp, and changes no public API or write paths (own-key generation always produces correctly-sizedp).Build evidence
Configured and built with the Botan 3.12.0 backend:
No other source files are modified.