Skip to content

Commit

Permalink
Merge branch 'RustCrypto:master' into cms-ecc-kari
Browse files Browse the repository at this point in the history
  • Loading branch information
nemynm authored Nov 7, 2024
2 parents 8dde07b + 48eac00 commit 1bcc5b6
Show file tree
Hide file tree
Showing 21 changed files with 534 additions and 255 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/tai64_update_leap_seconds.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Update Leap Seconds
on:
schedule:
- cron: 0 0 * * 1

jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Update leap seconds in code
run: |
curl -o leap_seconds_list -L https://data.iana.org/time-zones/data/leap-seconds.list
number=$(grep -v '^#' leap_seconds_list | tail -n1 | awk '{print $2}')
sed -i "s/\(1970-01-01 00:00:\)[0-9]\+ TAI/\1${number} TAI/" tai64/src/lib.rs
sed -i -E 's/(Self\()[0-9]+ \+ \(1 << 62\)\)/\1'"${number}"' + (1 << 62))/' tai64/src/lib.rs
rm leap_seconds_list
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
commit-message: update leap seconds in tai64
title: Update leap seconds in tai64
body: 'Following this source: https://data.iana.org/time-zones/data/leap-seconds.list, the leap seconds counter has been updated.'
branch: update-leap-seconds
base: master
delete-branch: true
18 changes: 10 additions & 8 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion cms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ rand = "0.8.5"
rsa = { version = "=0.10.0-pre.3", features = ["sha2"] }
ecdsa = { version = "=0.17.0-pre.9", features = ["digest", "pem"] }
p256 = "=0.14.0-pre.2"
tokio = { version = "1.40.0", features = ["macros", "rt"] }
tokio = { version = "1.41.0", features = ["macros", "rt"] }
x509-cert = { version = "=0.3.0-pre.0", features = ["pem"] }

[features]
Expand Down
4 changes: 3 additions & 1 deletion const-oid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "const-oid"
version = "0.10.0-rc.2"
version = "0.10.0-rc.3"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
description = """
Expand All @@ -22,6 +22,8 @@ arbitrary = { version = "1.2", optional = true, features = ["derive"] }

[dev-dependencies]
hex-literal = "0.4"
proptest = "1"
regex = "1"

[features]
db = []
Expand Down
21 changes: 12 additions & 9 deletions const-oid/src/arcs.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//! Arcs are integer values which exist within an OID's hierarchy.

use crate::{Error, Result};
use core::mem::size_of;

#[cfg(doc)]
use crate::ObjectIdentifier;

/// Type alias used to represent an "arc" (i.e. integer identifier value).
/// Type alias used to represent an "arc", i.e. integer identifier value, where an OID comprises a
/// sequence of arcs.
///
/// X.660 does not define a maximum size of an arc.
/// X.660 does not define a maximum size of an arc. We instead follow Mozilla* conventions for
/// maximum values of an arc, with a maximum value of 2^32-1 (4294967295), a.k.a. [`u32::MAX`]
/// with [`Arc`] being a type alias for [`u32`].
///
/// The current representation is `u32`, which has been selected as being
/// sufficient to cover the current PKCS/PKIX use cases this library has been
/// used in conjunction with.
/// Note that this means we deliberately do *NOT* support UUIDs used as OIDs.
///
/// Future versions may potentially make it larger if a sufficiently important
/// use case is discovered.
/// *NOTE: please see this study for a survey of how various OID libraries handle maximum arcs:
/// <https://misc.daniel-marschall.de/asn.1/oid_facts.html>
pub type Arc = u32;

/// Maximum value of the first arc in an OID.
Expand All @@ -25,7 +25,10 @@ pub(crate) const ARC_MAX_FIRST: Arc = 2;
pub(crate) const ARC_MAX_SECOND: Arc = 39;

/// Maximum number of bytes supported in an arc.
const ARC_MAX_BYTES: usize = size_of::<Arc>();
///
/// Note that OIDs are base 128 encoded (with continuation bits), so we must consider how many bytes
/// are required when each byte can only represent 7-bits of the input.
const ARC_MAX_BYTES: usize = (Arc::BITS as usize).div_ceil(7);

/// Maximum value of the last byte in an arc.
const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits
Expand Down
22 changes: 21 additions & 1 deletion const-oid/src/checked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,27 @@ macro_rules! checked_add {
($a:expr, $b:expr) => {
match $a.checked_add($b) {
Some(n) => n,
None => return Err(Error::Length),
None => return Err(Error::Overflow),
}
};
}

/// `const fn`-friendly checked subtraction helper.
macro_rules! checked_sub {
($a:expr, $b:expr) => {
match $a.checked_sub($b) {
Some(n) => n,
None => return Err(Error::Overflow),
}
};
}

/// `const fn`-friendly checked multiplication helper.
macro_rules! checked_mul {
($a:expr, $b:expr) => {
match $a.checked_mul($b) {
Some(n) => n,
None => return Err(Error::Overflow),
}
};
}
93 changes: 47 additions & 46 deletions const-oid/src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ enum State {
/// Initial state - no arcs yet encoded.
Initial,

/// First arc parsed.
/// First arc has been supplied and stored as the wrapped [`Arc`].
FirstArc(Arc),

/// Encoding base 128 body of the OID.
Expand Down Expand Up @@ -61,22 +61,20 @@ impl<const MAX_SIZE: usize> Encoder<MAX_SIZE> {
self.state = State::FirstArc(arc);
Ok(self)
}
// Ensured not to overflow by `ARC_MAX_SECOND` check
#[allow(clippy::arithmetic_side_effects)]
State::FirstArc(first_arc) => {
if arc > ARC_MAX_SECOND {
return Err(Error::ArcInvalid { arc });
}

self.state = State::Body;
self.bytes[0] = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + arc as u8;
self.bytes[0] = checked_add!(
checked_mul!(checked_add!(ARC_MAX_SECOND, 1), first_arc),
arc
) as u8;
self.cursor = 1;
Ok(self)
}
State::Body => {
let nbytes = base128_len(arc);
self.encode_base128(arc, nbytes)
}
State::Body => self.encode_base128(arc),
}
}

Expand All @@ -94,56 +92,48 @@ impl<const MAX_SIZE: usize> Encoder<MAX_SIZE> {
Ok(ObjectIdentifier { ber })
}

/// Encode a single byte of a Base 128 value.
const fn encode_base128(mut self, n: u32, remaining_len: usize) -> Result<Self> {
if self.cursor >= MAX_SIZE {
/// Encode base 128.
const fn encode_base128(mut self, arc: Arc) -> Result<Self> {
let nbytes = base128_len(arc);
let end_pos = checked_add!(self.cursor, nbytes);

if end_pos > MAX_SIZE {
return Err(Error::Length);
}

let mask = if remaining_len > 0 { 0b10000000 } else { 0 };
let (hi, lo) = split_high_bits(n);
self.bytes[self.cursor] = hi | mask;
self.cursor = checked_add!(self.cursor, 1);

match remaining_len.checked_sub(1) {
Some(len) => self.encode_base128(lo, len),
None => Ok(self),
let mut i = 0;
while i < nbytes {
// TODO(tarcieri): use `?` when stable in `const fn`
self.bytes[self.cursor] = match base128_byte(arc, i, nbytes) {
Ok(byte) => byte,
Err(e) => return Err(e),
};
self.cursor = checked_add!(self.cursor, 1);
i = checked_add!(i, 1);
}

Ok(self)
}
}

/// Compute the length - 1 of an arc when encoded in base 128.
/// Compute the length of an arc when encoded in base 128.
const fn base128_len(arc: Arc) -> usize {
match arc {
0..=0x7f => 0,
0x80..=0x3fff => 1,
0x4000..=0x1fffff => 2,
0x200000..=0x1fffffff => 3,
_ => 4,
0..=0x7f => 1,
0x80..=0x3fff => 2,
0x4000..=0x1fffff => 3,
0x200000..=0x1fffffff => 4,
_ => 5,
}
}

/// Split the highest 7-bits of an [`Arc`] from the rest of an arc.
///
/// Returns: `(hi, lo)`
// TODO(tarcieri): always use checked arithmetic
#[allow(clippy::arithmetic_side_effects)]
const fn split_high_bits(arc: Arc) -> (u8, Arc) {
if arc < 0x80 {
return (arc as u8, 0);
}

let hi_bit = 32 - arc.leading_zeros();
let hi_bit_mod7 = hi_bit % 7;
let upper_bit_pos = hi_bit
- if hi_bit > 0 && hi_bit_mod7 == 0 {
7
} else {
hi_bit_mod7
};
let upper_bits = arc >> upper_bit_pos;
let lower_bits = arc ^ (upper_bits << upper_bit_pos);
(upper_bits as u8, lower_bits)
/// Compute the big endian base 128 encoding of the given [`Arc`] at the given byte.
const fn base128_byte(arc: Arc, pos: usize, total: usize) -> Result<u8> {
debug_assert!(pos < total);
let last_byte = checked_add!(pos, 1) == total;
let mask = if last_byte { 0 } else { 0b10000000 };
let shift = checked_sub!(checked_sub!(total, pos), 1) * 7;
Ok(((arc >> shift) & 0b1111111) as u8 | mask)
}

#[cfg(test)]
Expand All @@ -155,6 +145,17 @@ mod tests {
/// OID `1.2.840.10045.2.1` encoded as ASN.1 BER/DER
const EXAMPLE_OID_BER: &[u8] = &hex!("2A8648CE3D0201");

#[test]
fn base128_byte() {
let example_arc = 0x44332211;
assert_eq!(super::base128_len(example_arc), 5);
assert_eq!(super::base128_byte(example_arc, 0, 5).unwrap(), 0b10000100);
assert_eq!(super::base128_byte(example_arc, 1, 5).unwrap(), 0b10100001);
assert_eq!(super::base128_byte(example_arc, 2, 5).unwrap(), 0b11001100);
assert_eq!(super::base128_byte(example_arc, 3, 5).unwrap(), 0b11000100);
assert_eq!(super::base128_byte(example_arc, 4, 5).unwrap(), 0b10001);
}

#[test]
fn encode() {
let encoder = Encoder::<7>::new();
Expand Down
12 changes: 12 additions & 0 deletions const-oid/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ pub enum Error {
/// OID length is invalid (too short or too long).
Length,

/// Arithmetic overflow (or underflow) errors.
///
/// These generally indicate a bug in the `const-oid` crate.
Overflow,

/// Repeated `..` characters in input data.
RepeatedDot,

/// Trailing `.` character at end of input.
TrailingDot,
}
Expand All @@ -53,6 +61,8 @@ impl Error {
Error::DigitExpected { .. } => panic!("OID expected to start with digit"),
Error::Empty => panic!("OID value is empty"),
Error::Length => panic!("OID length invalid"),
Error::Overflow => panic!("arithmetic calculation overflowed"),
Error::RepeatedDot => panic!("repeated consecutive '..' characters in OID"),
Error::TrailingDot => panic!("OID ends with invalid trailing '.'"),
}
}
Expand All @@ -69,6 +79,8 @@ impl fmt::Display for Error {
}
Error::Empty => f.write_str("OID value is empty"),
Error::Length => f.write_str("OID length invalid"),
Error::Overflow => f.write_str("arithmetic calculation overflowed"),
Error::RepeatedDot => f.write_str("repeated consecutive '..' characters in OID"),
Error::TrailingDot => f.write_str("OID ends with invalid trailing '.'"),
}
}
Expand Down
Loading

0 comments on commit 1bcc5b6

Please sign in to comment.