Skip to content

Commit 1c001b3

Browse files
authored
der+x509-cert: support for signed bigints, negative serial numbers (#823)
1 parent 7b59dbf commit 1c001b3

File tree

7 files changed

+324
-25
lines changed

7 files changed

+324
-25
lines changed

der/src/asn1.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,24 @@ mod utc_time;
2525
mod utf8_string;
2626
mod videotex_string;
2727

28+
#[cfg(feature = "oid")]
29+
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
30+
pub use const_oid::ObjectIdentifier;
31+
32+
#[cfg(feature = "alloc")]
33+
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
34+
pub use self::{
35+
any::Any, bit_string::BitString, integer::bigint::Int, integer::bigint::Uint,
36+
octet_string::OctetString, set_of::SetOfVec,
37+
};
2838
pub use self::{
2939
any::AnyRef,
3040
bit_string::{BitStringIter, BitStringRef},
3141
choice::Choice,
3242
context_specific::{ContextSpecific, ContextSpecificRef},
3343
generalized_time::GeneralizedTime,
3444
ia5_string::Ia5StringRef,
45+
integer::bigint::IntRef,
3546
integer::bigint::UintRef,
3647
null::Null,
3748
octet_string::OctetStringRef,
@@ -44,14 +55,3 @@ pub use self::{
4455
utf8_string::Utf8StringRef,
4556
videotex_string::VideotexStringRef,
4657
};
47-
48-
#[cfg(feature = "alloc")]
49-
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
50-
pub use self::{
51-
any::Any, bit_string::BitString, integer::bigint::Uint, octet_string::OctetString,
52-
set_of::SetOfVec,
53-
};
54-
55-
#[cfg(feature = "oid")]
56-
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
57-
pub use const_oid::ObjectIdentifier;

der/src/asn1/integer.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ pub(super) mod bigint;
44
pub(super) mod int;
55
pub(super) mod uint;
66

7+
use core::{cmp::Ordering, mem};
8+
79
use crate::{
810
asn1::AnyRef, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader,
911
Result, SliceWriter, Tag, ValueOrd, Writer,
1012
};
11-
use core::{cmp::Ordering, mem};
1213

1314
macro_rules! impl_int_encoding {
1415
($($int:ty => $uint:ty),+) => {

der/src/asn1/integer/bigint.rs

+252-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,94 @@
11
//! "Big" ASN.1 `INTEGER` types.
22
3-
use super::uint;
3+
use super::{int, uint};
44
use crate::{
55
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
66
FixedTag, Header, Length, Reader, Result, Tag, Writer,
77
};
88

9+
/// "Big" signed ASN.1 `INTEGER` type.
10+
///
11+
/// Provides direct access to the underlying big endian bytes which comprise
12+
/// an signed integer value.
13+
///
14+
/// Intended for use cases like very large integers that are used in
15+
/// cryptographic applications (e.g. keys, signatures).
16+
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
17+
pub struct IntRef<'a> {
18+
/// Inner value
19+
inner: ByteSlice<'a>,
20+
}
21+
22+
impl<'a> IntRef<'a> {
23+
/// Create a new [`IntRef`] from a byte slice.
24+
pub fn new(bytes: &'a [u8]) -> Result<Self> {
25+
let inner = ByteSlice::new(int::strip_leading_ones(bytes))
26+
.map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
27+
28+
Ok(Self { inner })
29+
}
30+
31+
/// Borrow the inner byte slice which contains the least significant bytes
32+
/// of a big endian integer value with all leading ones stripped.
33+
pub fn as_bytes(&self) -> &'a [u8] {
34+
self.inner.as_slice()
35+
}
36+
37+
/// Get the length of this [`IntRef`] in bytes.
38+
pub fn len(&self) -> Length {
39+
self.inner.len()
40+
}
41+
42+
/// Is the inner byte slice empty?
43+
pub fn is_empty(&self) -> bool {
44+
self.inner.is_empty()
45+
}
46+
}
47+
48+
impl<'a> DecodeValue<'a> for IntRef<'a> {
49+
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
50+
let bytes = ByteSlice::decode_value(reader, header)?.as_slice();
51+
let result = Self::new(int::decode_to_slice(bytes)?)?;
52+
53+
// Ensure we compute the same encoded length as the original any value.
54+
if result.value_len()? != header.length {
55+
return Err(Self::TAG.non_canonical_error());
56+
}
57+
58+
Ok(result)
59+
}
60+
}
61+
62+
impl<'a> EncodeValue for IntRef<'a> {
63+
fn value_len(&self) -> Result<Length> {
64+
int::encoded_len(self.inner.as_slice())
65+
}
66+
67+
fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
68+
writer.write(self.as_bytes())
69+
}
70+
}
71+
72+
impl<'a> From<&IntRef<'a>> for IntRef<'a> {
73+
fn from(value: &IntRef<'a>) -> IntRef<'a> {
74+
*value
75+
}
76+
}
77+
78+
impl<'a> TryFrom<AnyRef<'a>> for IntRef<'a> {
79+
type Error = Error;
80+
81+
fn try_from(any: AnyRef<'a>) -> Result<IntRef<'a>> {
82+
any.decode_into()
83+
}
84+
}
85+
86+
impl<'a> FixedTag for IntRef<'a> {
87+
const TAG: Tag = Tag::Integer;
88+
}
89+
90+
impl<'a> OrdIsValueOrd for IntRef<'a> {}
91+
992
/// "Big" unsigned ASN.1 `INTEGER` type.
1093
///
1194
/// Provides direct access to the underlying big endian bytes which comprise an
@@ -95,11 +178,11 @@ impl<'a> FixedTag for UintRef<'a> {
95178
impl<'a> OrdIsValueOrd for UintRef<'a> {}
96179

97180
#[cfg(feature = "alloc")]
98-
pub use self::allocating::Uint;
181+
pub use self::allocating::{Int, Uint};
99182

100183
#[cfg(feature = "alloc")]
101184
mod allocating {
102-
use super::{super::uint, UintRef};
185+
use super::{super::int, super::uint, IntRef, UintRef};
103186
use crate::{
104187
asn1::AnyRef,
105188
ord::OrdIsValueOrd,
@@ -108,6 +191,108 @@ mod allocating {
108191
Result, Tag, Writer,
109192
};
110193

194+
/// "Big" signed ASN.1 `INTEGER` type.
195+
///
196+
/// Provides direct storage for the big endian bytes which comprise an
197+
/// signed integer value.
198+
///
199+
/// Intended for use cases like very large integers that are used in
200+
/// cryptographic applications (e.g. keys, signatures).
201+
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
202+
pub struct Int {
203+
/// Inner value
204+
inner: Bytes,
205+
}
206+
207+
impl Int {
208+
/// Create a new [`Int`] from a byte slice.
209+
pub fn new(bytes: &[u8]) -> Result<Self> {
210+
let inner = Bytes::new(int::strip_leading_ones(bytes))
211+
.map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
212+
213+
Ok(Self { inner })
214+
}
215+
216+
/// Borrow the inner byte slice which contains the least significant bytes
217+
/// of a big endian integer value with all leading ones stripped.
218+
pub fn as_bytes(&self) -> &[u8] {
219+
self.inner.as_slice()
220+
}
221+
222+
/// Get the length of this [`Int`] in bytes.
223+
pub fn len(&self) -> Length {
224+
self.inner.len()
225+
}
226+
227+
/// Is the inner byte slice empty?
228+
pub fn is_empty(&self) -> bool {
229+
self.inner.is_empty()
230+
}
231+
}
232+
233+
impl<'a> DecodeValue<'a> for Int {
234+
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
235+
let bytes = Bytes::decode_value(reader, header)?;
236+
let result = Self::new(int::decode_to_slice(bytes.as_slice())?)?;
237+
238+
// Ensure we compute the same encoded length as the original any value.
239+
if result.value_len()? != header.length {
240+
return Err(Self::TAG.non_canonical_error());
241+
}
242+
243+
Ok(result)
244+
}
245+
}
246+
247+
impl EncodeValue for Int {
248+
fn value_len(&self) -> Result<Length> {
249+
int::encoded_len(self.inner.as_slice())
250+
}
251+
252+
fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
253+
writer.write(self.as_bytes())
254+
}
255+
}
256+
257+
impl<'a> From<&IntRef<'a>> for Int {
258+
fn from(value: &IntRef<'a>) -> Int {
259+
let inner = Bytes::new(value.as_bytes()).expect("Invalid Int");
260+
Int { inner }
261+
}
262+
}
263+
264+
impl<'a> TryFrom<AnyRef<'a>> for Int {
265+
type Error = Error;
266+
267+
fn try_from(any: AnyRef<'a>) -> Result<Int> {
268+
any.decode_into()
269+
}
270+
}
271+
272+
impl FixedTag for Int {
273+
const TAG: Tag = Tag::Integer;
274+
}
275+
276+
impl OrdIsValueOrd for Int {}
277+
278+
impl<'a> RefToOwned<'a> for IntRef<'a> {
279+
type Owned = Int;
280+
fn to_owned(&self) -> Self::Owned {
281+
let inner = self.inner.to_owned();
282+
283+
Int { inner }
284+
}
285+
}
286+
287+
impl OwnedToRef for Int {
288+
type Borrowed<'a> = IntRef<'a>;
289+
fn to_ref(&self) -> Self::Borrowed<'_> {
290+
let inner = self.inner.to_ref();
291+
292+
IntRef { inner }
293+
}
294+
}
295+
111296
/// "Big" unsigned ASN.1 `INTEGER` type.
112297
///
113298
/// Provides direct storage for the big endian bytes which comprise an
@@ -220,10 +405,73 @@ mod allocating {
220405
mod tests {
221406
use super::UintRef;
222407
use crate::{
223-
asn1::{integer::tests::*, AnyRef},
408+
asn1::{integer::tests::*, AnyRef, IntRef},
224409
Decode, Encode, ErrorKind, SliceWriter, Tag,
225410
};
226411

412+
#[test]
413+
fn decode_int_bytes() {
414+
// Positive numbers decode, but have zero extensions as necessary
415+
// (to distinguish them from negative representations).
416+
assert_eq!(&[0], IntRef::from_der(I0_BYTES).unwrap().as_bytes());
417+
assert_eq!(&[127], IntRef::from_der(I127_BYTES).unwrap().as_bytes());
418+
assert_eq!(&[0, 128], IntRef::from_der(I128_BYTES).unwrap().as_bytes());
419+
assert_eq!(&[0, 255], IntRef::from_der(I255_BYTES).unwrap().as_bytes());
420+
421+
assert_eq!(
422+
&[0x01, 0x00],
423+
IntRef::from_der(I256_BYTES).unwrap().as_bytes()
424+
);
425+
426+
assert_eq!(
427+
&[0x7F, 0xFF],
428+
IntRef::from_der(I32767_BYTES).unwrap().as_bytes()
429+
);
430+
431+
// Negative integers decode.
432+
assert_eq!(&[128], IntRef::from_der(INEG128_BYTES).unwrap().as_bytes());
433+
assert_eq!(
434+
&[255, 127],
435+
IntRef::from_der(INEG129_BYTES).unwrap().as_bytes()
436+
);
437+
assert_eq!(
438+
&[128, 0],
439+
IntRef::from_der(INEG32768_BYTES).unwrap().as_bytes()
440+
);
441+
}
442+
443+
#[test]
444+
fn encode_int_bytes() {
445+
for &example in &[
446+
I0_BYTES,
447+
I127_BYTES,
448+
I128_BYTES,
449+
I255_BYTES,
450+
I256_BYTES,
451+
I32767_BYTES,
452+
] {
453+
let uint = IntRef::from_der(example).unwrap();
454+
455+
let mut buf = [0u8; 128];
456+
let mut encoder = SliceWriter::new(&mut buf);
457+
uint.encode(&mut encoder).unwrap();
458+
459+
let result = encoder.finish().unwrap();
460+
assert_eq!(example, result);
461+
}
462+
463+
for &example in &[INEG128_BYTES, INEG129_BYTES, INEG32768_BYTES] {
464+
let uint = IntRef::from_der(example).unwrap();
465+
466+
let mut buf = [0u8; 128];
467+
let mut encoder = SliceWriter::new(&mut buf);
468+
uint.encode(&mut encoder).unwrap();
469+
470+
let result = encoder.finish().unwrap();
471+
assert_eq!(example, result);
472+
}
473+
}
474+
227475
#[test]
228476
fn decode_uint_bytes() {
229477
assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes());

0 commit comments

Comments
 (0)