Skip to content

Commit

Permalink
[WIP] der: replace typenum with const generics for BigUInt
Browse files Browse the repository at this point in the history
BigUInt was previously using `typenum` to define the size of an integer.
This is necessary because it maps to a signed ASN.1 INTEGER and needs to
add/remove a leading 0 when the first octet is >0x7f.

This is perhaps the one thing in RustCrypto right now where I feel that
`min_const_generics` stabilization might actually help: it's a trivial
usage, doesn't involve `generic-array` or associated constants of a
trait definition, it's just using the type system to be generic around
an integer value.

This eliminates `typenum` as a dependency and with it feature gating
`big-uint`. Presently requires `beta` until 1.51 ships on March 25th.
  • Loading branch information
tarcieri committed Mar 4, 2021
1 parent 910873b commit 647e45f
Show file tree
Hide file tree
Showing 11 changed files with 34 additions and 108 deletions.
11 changes: 4 additions & 7 deletions .github/workflows/der.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
strategy:
matrix:
rust:
- 1.46.0 # MSRV
- stable
- beta # MSRV
#- stable
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
Expand All @@ -37,17 +37,15 @@ jobs:
target: ${{ matrix.target }}
override: true
- run: cargo build --target ${{ matrix.target }} --release
- run: cargo build --target ${{ matrix.target }} --release --features big-uint
- run: cargo build --target ${{ matrix.target }} --release --features oid
- run: cargo build --target ${{ matrix.target }} --release --features big-uint,oid

test:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.46.0 # MSRV
- stable
- beta # MSRV
#- stable
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
Expand All @@ -56,6 +54,5 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- run: cargo test --release
- run: cargo test --release --features big-uint
- run: cargo test --release --features oid
- run: cargo test --release --all-features
8 changes: 4 additions & 4 deletions .github/workflows/pkcs5.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
Expand All @@ -48,8 +48,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pkcs8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
Expand All @@ -50,8 +50,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/spki.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
Expand All @@ -45,8 +45,8 @@ jobs:
strategy:
matrix:
rust:
- 1.47.0 # MSRV
- stable
- beta # MSRV
#- stable
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.47.0 # Highest MSRV in repo
toolchain: beta # Highest MSRV in repo
components: clippy
override: true
profile: minimal
Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions der/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@ readme = "README.md"
[dependencies]
const-oid = { version = "0.4.4", optional = true, path = "../const-oid" }
der_derive = { version = "0.2", optional = true, path = "derive" }
typenum = { version = "1", optional = true }

[dev-dependencies]
hex-literal = "0.3"

[features]
alloc = []
derive = ["der_derive"]
big-uint = ["typenum"]
oid = ["const-oid"]
std = ["alloc"]

Expand Down
1 change: 0 additions & 1 deletion der/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//! Includes built-in ASN.1 types and helper types for modeling ASN.1 concepts.
pub(crate) mod any;
#[cfg(feature = "big-uint")]
pub(crate) mod big_uint;
pub(crate) mod bit_string;
pub(crate) mod boolean;
Expand Down
79 changes: 13 additions & 66 deletions der/src/asn1/big_uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
use crate::{
Any, ByteSlice, Encodable, Encoder, Error, ErrorKind, Header, Length, Result, Tag, Tagged,
};
use core::{convert::TryFrom, marker::PhantomData};
use typenum::Unsigned;
use core::convert::TryFrom;

/// "Big" unsigned ASN.1 `INTEGER` type.
///
Expand All @@ -19,16 +18,12 @@ use typenum::Unsigned;
///
/// Currently supported sizes are 1 - 512 bytes.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(docsrs, doc(cfg(feature = "big-uint")))]
pub struct BigUInt<'a, N: BigUIntSize> {
pub struct BigUInt<'a, const N: usize> {
/// Inner value
inner: ByteSlice<'a>,

/// Integer size in bytes
size: PhantomData<N>,
}

impl<'a, N: BigUIntSize> BigUInt<'a, N> {
impl<'a, const N: usize> BigUInt<'a, N> {
/// Create a new [`BigUInt`] from a byte slice.
///
/// Slice may be less than or equal to `N` bytes.
Expand All @@ -38,15 +33,12 @@ impl<'a, N: BigUIntSize> BigUInt<'a, N> {
bytes = &bytes[1..];
}

if bytes.len() > N::to_usize() {
if bytes.len() > N {
return Err(ErrorKind::Length { tag: Self::TAG }.into());
}

ByteSlice::new(bytes)
.map(|inner| Self {
inner,
size: PhantomData,
})
.map(|inner| Self { inner })
.map_err(|_| ErrorKind::Length { tag: Self::TAG }.into())
}

Expand Down Expand Up @@ -86,13 +78,13 @@ impl<'a, N: BigUIntSize> BigUInt<'a, N> {
}
}

impl<'a, N: BigUIntSize> From<&BigUInt<'a, N>> for BigUInt<'a, N> {
impl<'a, const N: usize> From<&BigUInt<'a, N>> for BigUInt<'a, N> {
fn from(value: &BigUInt<'a, N>) -> BigUInt<'a, N> {
*value
}
}

impl<'a, N: BigUIntSize> TryFrom<Any<'a>> for BigUInt<'a, N> {
impl<'a, const N: usize> TryFrom<Any<'a>> for BigUInt<'a, N> {
type Error = Error;

fn try_from(any: Any<'a>) -> Result<BigUInt<'a, N>> {
Expand All @@ -112,8 +104,8 @@ impl<'a, N: BigUIntSize> TryFrom<Any<'a>> for BigUInt<'a, N> {
// The `INTEGER` type always encodes a signed value, so for unsigned
// values the leading `0x00` byte may need to be removed.
// TODO(tarcieri): validate leading 0 byte was required
if bytes.len() > N::to_usize() {
if bytes.len() != N::to_usize().checked_add(1).unwrap() {
if bytes.len() > N {
if bytes.len() != N.checked_add(1).unwrap() {
return Err(ErrorKind::Length { tag: Self::TAG }.into());
}

Expand All @@ -128,7 +120,7 @@ impl<'a, N: BigUIntSize> TryFrom<Any<'a>> for BigUInt<'a, N> {
}
}

impl<'a, N: BigUIntSize> Encodable for BigUInt<'a, N> {
impl<'a, const N: usize> Encodable for BigUInt<'a, N> {
fn encoded_len(&self) -> Result<Length> {
self.header()?.encoded_len()? + self.inner_len()?
}
Expand All @@ -145,64 +137,19 @@ impl<'a, N: BigUIntSize> Encodable for BigUInt<'a, N> {
}
}

impl<'a, N: BigUIntSize> Tagged for BigUInt<'a, N> {
impl<'a, const N: usize> Tagged for BigUInt<'a, N> {
const TAG: Tag = Tag::Integer;
}

/// Marker trait for allowed [`BigUInt`] sizes.
#[cfg_attr(docsrs, doc(cfg(feature = "big-uint")))]
pub trait BigUIntSize: Unsigned {}

macro_rules! impl_size {
($($int:ident),+) => {
$(impl BigUIntSize for typenum::consts::$int {})+
};
}

// Sizes supported by the current implementation (1 - 512 bytes)
impl_size!(
U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19, U20, U21,
U22, U23, U24, U25, U26, U27, U28, U29, U30, U31, U32, U33, U34, U35, U36, U37, U38, U39, U40,
U41, U42, U43, U44, U45, U46, U47, U48, U49, U50, U51, U52, U53, U54, U55, U56, U57, U58, U59,
U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U70, U71, U72, U73, U74, U75, U76, U77, U78,
U79, U80, U81, U82, U83, U84, U85, U86, U87, U88, U89, U90, U91, U92, U93, U94, U95, U96, U97,
U98, U99, U100, U101, U102, U103, U104, U105, U106, U107, U108, U109, U110, U111, U112, U113,
U114, U115, U116, U117, U118, U119, U120, U121, U122, U123, U124, U125, U126, U127, U128, U129,
U130, U131, U132, U133, U134, U135, U136, U137, U138, U139, U140, U141, U142, U143, U144, U145,
U146, U147, U148, U149, U150, U151, U152, U153, U154, U155, U156, U157, U158, U159, U160, U161,
U162, U163, U164, U165, U166, U167, U168, U169, U170, U171, U172, U173, U174, U175, U176, U177,
U178, U179, U180, U181, U182, U183, U184, U185, U186, U187, U188, U189, U190, U191, U192, U193,
U194, U195, U196, U197, U198, U199, U200, U201, U202, U203, U204, U205, U206, U207, U208, U209,
U210, U211, U212, U213, U214, U215, U216, U217, U218, U219, U220, U221, U222, U223, U224, U225,
U226, U227, U228, U229, U230, U231, U232, U233, U234, U235, U236, U237, U238, U239, U240, U241,
U242, U243, U244, U245, U246, U247, U248, U249, U250, U251, U252, U253, U254, U255, U256, U257,
U258, U259, U260, U261, U262, U263, U264, U265, U266, U267, U268, U269, U270, U271, U272, U273,
U274, U275, U276, U277, U278, U279, U280, U281, U282, U283, U284, U285, U286, U287, U288, U289,
U290, U291, U292, U293, U294, U295, U296, U297, U298, U299, U300, U301, U302, U303, U304, U305,
U306, U307, U308, U309, U310, U311, U312, U313, U314, U315, U316, U317, U318, U319, U320, U321,
U322, U323, U324, U325, U326, U327, U328, U329, U330, U331, U332, U333, U334, U335, U336, U337,
U338, U339, U340, U341, U342, U343, U344, U345, U346, U347, U348, U349, U350, U351, U352, U353,
U354, U355, U356, U357, U358, U359, U360, U361, U362, U363, U364, U365, U366, U367, U368, U369,
U370, U371, U372, U373, U374, U375, U376, U377, U378, U379, U380, U381, U382, U383, U384, U385,
U386, U387, U388, U389, U390, U391, U392, U393, U394, U395, U396, U397, U398, U399, U400, U401,
U402, U403, U404, U405, U406, U407, U408, U409, U410, U411, U412, U413, U414, U415, U416, U417,
U418, U419, U420, U421, U422, U423, U424, U425, U426, U427, U428, U429, U430, U431, U432, U433,
U434, U435, U436, U437, U438, U439, U440, U441, U442, U443, U444, U445, U446, U447, U448, U449,
U450, U451, U452, U453, U454, U455, U456, U457, U458, U459, U460, U461, U462, U463, U464, U465,
U466, U467, U468, U469, U470, U471, U472, U473, U474, U475, U476, U477, U478, U479, U480, U481,
U482, U483, U484, U485, U486, U487, U488, U489, U490, U491, U492, U493, U494, U495, U496, U497,
U498, U499, U500, U501, U502, U503, U504, U505, U506, U507, U508, U509, U510, U511, U512
);

#[cfg(test)]
mod tests {
use super::BigUInt;
use crate::{asn1::integer::tests::*, Any, Decodable, ErrorKind, Result, Tag};
use core::convert::TryInto;

// TODO(tarcieri): tests for more integer sizes
type BigU8<'a> = BigUInt<'a, typenum::U1>;
type BigU16<'a> = BigUInt<'a, typenum::U16>;
type BigU8<'a> = BigUInt<'a, 1>;
type BigU16<'a> = BigUInt<'a, 2>;

/// Parse a `BitU1` from an ASN.1 `Any` value to test decoding behaviors.
fn parse_bigu8_from_any(bytes: &[u8]) -> Result<BigU8<'_>> {
Expand Down
14 changes: 3 additions & 11 deletions der/src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//! DER decoder.
use crate::{
Any, BitString, Choice, Decodable, ErrorKind, GeneralizedTime, Ia5String, Length, Null,
OctetString, PrintableString, Result, Sequence, UtcTime, Utf8String,
Any, BigUInt, BitString, Choice, Decodable, ErrorKind, GeneralizedTime, Ia5String, Length,
Null, OctetString, PrintableString, Result, Sequence, UtcTime, Utf8String,
};
use core::convert::TryInto;

#[cfg(feature = "big-uint")]
use crate::{BigUInt, BigUIntSize};

#[cfg(feature = "oid")]
use crate::ObjectIdentifier;

Expand Down Expand Up @@ -108,12 +105,7 @@ impl<'a> Decoder<'a> {
}

/// Attempt to decode an ASN.1 `INTEGER` as a [`BigUInt`].
#[cfg(feature = "big-uint")]
#[cfg_attr(docsrs, doc(cfg(feature = "big-uint")))]
pub fn big_uint<N>(&mut self) -> Result<BigUInt<'a, N>>
where
N: BigUIntSize,
{
pub fn big_uint<const N: usize>(&mut self) -> Result<BigUInt<'a, N>> {
self.decode()
}

Expand Down
8 changes: 1 addition & 7 deletions der/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ mod tag;
pub use crate::{
asn1::{
any::Any,
big_uint::BigUInt,
bit_string::BitString,
choice::Choice,
generalized_time::GeneralizedTime,
Expand All @@ -378,13 +379,6 @@ pub use crate::{

pub(crate) use crate::byte_slice::ByteSlice;

#[cfg(feature = "big-uint")]
#[cfg_attr(docsrs, doc(cfg(feature = "big-uint")))]
pub use {
crate::asn1::big_uint::{BigUInt, BigUIntSize},
typenum::consts,
};

#[cfg(feature = "derive")]
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
pub use der_derive::{Choice, Message};
Expand Down

0 comments on commit 647e45f

Please sign in to comment.