From e0cefea8f8b091f1c38a9e0e2750c5e70754c29e Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 8 May 2024 07:05:17 -0600 Subject: [PATCH] der: return `Tag::Integer.length_error()` on empty ints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From X.690 § 8.3.1: > 8.3 Encoding of an integer value > 8.3.1 The encoding of an integer value shall be primitive. > The contents octets shall consist of one or more octets. --- der/src/asn1/integer.rs | 16 +++++++++++++++- der/src/asn1/integer/int.rs | 4 ++++ der/src/asn1/integer/uint.rs | 5 ++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/der/src/asn1/integer.rs b/der/src/asn1/integer.rs index c82ac4ef5..cd85f53a8 100644 --- a/der/src/asn1/integer.rs +++ b/der/src/asn1/integer.rs @@ -38,7 +38,7 @@ where #[cfg(test)] #[allow(clippy::unwrap_used)] pub(crate) mod tests { - use crate::{Decode, Encode}; + use crate::{Decode, Encode, ErrorKind, Tag}; // Vectors from Section 5.7 of: // https://luca.ntop.org/Teaching/Appunti/asn1.html @@ -151,6 +151,20 @@ pub(crate) mod tests { assert_eq!(I65535_BYTES, 65535u16.encode_to_slice(&mut buffer).unwrap()); } + /// Integers cannot be empty. + /// + /// From X.690 § 8.3.1: "The contents octets shall consist of one or more octets" + #[test] + fn reject_empty() { + const EMPTY_INT: &[u8] = &[0x02, 0x00]; + + let err = u8::from_der(EMPTY_INT).expect_err("empty INTEGER should return error"); + assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer }); + + let err = i8::from_der(EMPTY_INT).expect_err("empty INTEGER should return error"); + assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer }); + } + /// Integers must be encoded with a minimum number of octets #[test] fn reject_non_canonical() { diff --git a/der/src/asn1/integer/int.rs b/der/src/asn1/integer/int.rs index 4e7755160..1142d576d 100644 --- a/der/src/asn1/integer/int.rs +++ b/der/src/asn1/integer/int.rs @@ -20,6 +20,10 @@ macro_rules! impl_encoding_traits { let mut buf = [0u8; Self::BITS as usize / 8]; let max_length = u32::from(header.length) as usize; + if max_length == 0 { + return Err(Tag::Integer.length_error()); + } + if max_length > buf.len() { return Err(Self::TAG.non_canonical_error()); } diff --git a/der/src/asn1/integer/uint.rs b/der/src/asn1/integer/uint.rs index 0c65f25f8..7da02eba9 100644 --- a/der/src/asn1/integer/uint.rs +++ b/der/src/asn1/integer/uint.rs @@ -24,12 +24,15 @@ macro_rules! impl_encoding_traits { let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM]; let max_length = u32::from(header.length) as usize; + if max_length == 0 { + return Err(Tag::Integer.length_error()); + } + if max_length > buf.len() { return Err(Self::TAG.non_canonical_error()); } let bytes = reader.read_into(&mut buf[..max_length])?; - let result = Self::from_be_bytes(decode_to_array(bytes)?); // Ensure we compute the same encoded length as the original any value