Skip to content

const-oid: reject over-u32 arcs in BER decoder instead of truncating - #2412

Open
jaideeppyne wants to merge 2 commits into
RustCrypto:masterfrom
jaideeppyne:fix/const-oid-arc-decode-overflow
Open

const-oid: reject over-u32 arcs in BER decoder instead of truncating#2412
jaideeppyne wants to merge 2 commits into
RustCrypto:masterfrom
jaideeppyne:fix/const-oid-arc-decode-overflow

Conversation

@jaideeppyne

Copy link
Copy Markdown

Arcs::try_next (used by ObjectIdentifier::from_bytes) accumulated base-128 arc digits with an unchecked result << 7, guarded only by arc_bytes > ARC_MAX_BYTES. Since a u32 arc can span up to five base-128 bytes, that guard never fires for a five-byte arc, so the final shift can push the value past u32::MAX and silently truncate it.

As a result from_bytes accepted encodings denoting arcs greater than u32::MAX and returned a wrong value instead of ArcTooBig:

  • 2A 90 80 80 80 00 (arc 2³²) decoded to 1.2.0
  • 2A 90 80 80 80 05 (arc 2³²+5) decoded to 1.2.5

This is the byte-decode counterpart of the base-10 parse overflow fixed for #1585/#1592, which only touched parser.rs.

Fix: accumulate with checked_mul/checked_add and return ArcTooBig on overflow. The largest in-range arc (u32::MAX, 2A 8F FF FF FF 7F) still decodes correctly. Adds a regression test.

The BER byte decoder (`Arcs::try_next`) accumulated base-128 arc digits
with an unchecked `result << 7` shift, guarded only by
`arc_bytes > ARC_MAX_BYTES`. Because a `u32` arc can occupy up to five
base-128 bytes, that guard never fired for a five-byte arc, so the final
shift could push the value past `u32::MAX` and silently truncate it.

As a result `ObjectIdentifier::from_bytes` accepted encodings denoting
arcs greater than `u32::MAX` and returned a wrong value rather than
`ArcTooBig`. For example `2A 90 80 80 80 00` (arc 2^32) decoded to
`1.2.0` and `2A 90 80 80 80 05` (arc 2^32+5) decoded to `1.2.5`.

Accumulate the digits with `checked_mul`/`checked_add` and return
`ArcTooBig` on overflow. The largest in-range arc (`u32::MAX`,
`2A 8F FF FF FF 7F`) still decodes correctly. Add a regression test.
Comment thread const-oid/src/arcs.rs Outdated
Comment on lines +76 to +84
// Accumulate the base 128 digits with overflow checking.
//
// An arc whose value does not fit in `Arc` (`u32`) is
// rejected as `ArcTooBig` rather than being silently
// truncated by the `<< 7` shift. Note that a `u32` arc can
// be up to five base 128 bytes long, so checking the number
// of consumed bytes alone is not sufficient: the final byte
// of a five-byte arc can still push the value past
// `u32::MAX`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems overly verbose and also references the previous bug which is somewhat irrelevant after it's fixed.

Can you whittle it down to something shorter? And no need to mention the truncation bug in a fixed implementation.

It can stay on the comment on the tests, since those are talking about desirable or undesirable behavior.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cut down to three lines and the truncation reference is gone:

// A five byte arc can still exceed `Arc`, so the digits are
// accumulated with overflow checking rather than by counting
// bytes.

Left the test comments as they are, since those are describing the behaviour being asserted.

@tarcieri

Copy link
Copy Markdown
Member

Nice catch, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants