chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

301
vendor/ring/src/io/der.rs vendored Normal file
View File

@@ -0,0 +1,301 @@
// Copyright 2015 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Building blocks for parsing DER-encoded ASN.1 structures.
//!
//! This module contains the foundational parts of an ASN.1 DER parser.
use super::Positive;
use crate::error;
pub const CONSTRUCTED: u8 = 1 << 5;
pub const CONTEXT_SPECIFIC: u8 = 2 << 6;
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum Tag {
Boolean = 0x01,
Integer = 0x02,
BitString = 0x03,
OctetString = 0x04,
Null = 0x05,
OID = 0x06,
Sequence = CONSTRUCTED | 0x10, // 0x30
UTCTime = 0x17,
GeneralizedTime = 0x18,
ContextSpecific1 = CONTEXT_SPECIFIC | 1,
ContextSpecificConstructed0 = CONTEXT_SPECIFIC | CONSTRUCTED | 0,
ContextSpecificConstructed1 = CONTEXT_SPECIFIC | CONSTRUCTED | 1,
ContextSpecificConstructed3 = CONTEXT_SPECIFIC | CONSTRUCTED | 3,
}
impl From<Tag> for usize {
fn from(tag: Tag) -> Self {
Self::from(Tag::into(tag))
}
}
impl From<Tag> for u8 {
fn from(tag: Tag) -> Self {
Tag::into(tag)
}
}
// `impl From<Tag> for u8` but as a `const fn`.
impl Tag {
pub const fn into(self) -> u8 {
self as u8
}
}
pub fn expect_tag_and_get_value<'a>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
) -> Result<untrusted::Input<'a>, error::Unspecified> {
let (actual_tag, inner) = read_tag_and_get_value(input)?;
if usize::from(tag) != usize::from(actual_tag) {
return Err(error::Unspecified);
}
Ok(inner)
}
pub fn read_tag_and_get_value<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<(u8, untrusted::Input<'a>), error::Unspecified> {
let tag = input.read_byte()?;
if (tag & 0x1F) == 0x1F {
return Err(error::Unspecified); // High tag number form is not allowed.
}
// If the high order bit of the first byte is set to zero then the length
// is encoded in the seven remaining bits of that byte. Otherwise, those
// seven bits represent the number of bytes used to encode the length.
let length = match input.read_byte()? {
n if (n & 0x80) == 0 => usize::from(n),
0x81 => {
let second_byte = input.read_byte()?;
if second_byte < 128 {
return Err(error::Unspecified); // Not the canonical encoding.
}
usize::from(second_byte)
}
0x82 => {
let second_byte = usize::from(input.read_byte()?);
let third_byte = usize::from(input.read_byte()?);
let combined = (second_byte << 8) | third_byte;
if combined < 256 {
return Err(error::Unspecified); // Not the canonical encoding.
}
combined
}
_ => {
return Err(error::Unspecified); // We don't support longer lengths.
}
};
let inner = input.read_bytes(length)?;
Ok((tag, inner))
}
#[inline]
pub fn bit_string_with_no_unused_bits<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<untrusted::Input<'a>, error::Unspecified> {
bit_string_tagged_with_no_unused_bits(Tag::BitString, input)
}
pub(crate) fn bit_string_tagged_with_no_unused_bits<'a>(
tag: Tag,
input: &mut untrusted::Reader<'a>,
) -> Result<untrusted::Input<'a>, error::Unspecified> {
nested(input, tag, error::Unspecified, |value| {
let unused_bits_at_end = value.read_byte().map_err(|_| error::Unspecified)?;
if unused_bits_at_end != 0 {
return Err(error::Unspecified);
}
Ok(value.read_bytes_to_end())
})
}
// TODO: investigate taking decoder as a reference to reduce generated code
// size.
pub fn nested<'a, F, R, E: Copy>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
error: E,
decoder: F,
) -> Result<R, E>
where
F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, E>,
{
let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?;
inner.read_all(error, decoder)
}
pub(crate) fn nonnegative_integer<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<untrusted::Input<'a>, error::Unspecified> {
let value = expect_tag_and_get_value(input, Tag::Integer)?;
match value
.as_slice_less_safe()
.split_first()
.ok_or(error::Unspecified)?
{
// Zero or leading zero.
(0, rest) => {
match rest.first() {
// Zero.
None => Ok(value),
// Necessary leading zero.
Some(&second) if second & 0x80 == 0x80 => Ok(untrusted::Input::from(rest)),
// Unnecessary leading zero.
_ => Err(error::Unspecified),
}
}
// Positive value with no leading zero.
(first, _) if first & 0x80 == 0 => Ok(value),
// Negative value.
(_, _) => Err(error::Unspecified),
}
}
/// Parse as integer with a value in the in the range [0, 255], returning its
/// numeric value. This is typically used for parsing version numbers.
#[inline]
pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, error::Unspecified> {
let value = nonnegative_integer(input)?;
match *value.as_slice_less_safe() {
[b] => Ok(b),
_ => Err(error::Unspecified),
}
}
/// Parses a positive DER integer, returning the big-endian-encoded value,
/// sans any leading zero byte.
pub fn positive_integer<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<Positive<'a>, error::Unspecified> {
let value = nonnegative_integer(input)?;
Positive::from_be_bytes(value)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error;
fn with_i<'a, F, R>(value: &'a [u8], f: F) -> Result<R, error::Unspecified>
where
F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, error::Unspecified>,
{
untrusted::Input::from(value).read_all(error::Unspecified, f)
}
static ZERO_INTEGER: &[u8] = &[0x02, 0x01, 0x00];
static GOOD_POSITIVE_INTEGERS_SMALL: &[(&[u8], u8)] = &[
(&[0x02, 0x01, 0x01], 0x01),
(&[0x02, 0x01, 0x02], 0x02),
(&[0x02, 0x01, 0x7e], 0x7e),
(&[0x02, 0x01, 0x7f], 0x7f),
// Values that need to have an 0x00 prefix to disambiguate them from
// them from negative values.
(&[0x02, 0x02, 0x00, 0x80], 0x80),
(&[0x02, 0x02, 0x00, 0x81], 0x81),
(&[0x02, 0x02, 0x00, 0xfe], 0xfe),
(&[0x02, 0x02, 0x00, 0xff], 0xff),
];
static GOOD_POSITIVE_INTEGERS_LARGE: &[(&[u8], &[u8])] = &[
(&[0x02, 0x02, 0x01, 0x00], &[0x01, 0x00]),
(&[0x02, 0x02, 0x02, 0x01], &[0x02, 0x01]),
(&[0x02, 0x02, 0x7e, 0xfe], &[0x7e, 0xfe]),
(&[0x02, 0x02, 0x7f, 0xff], &[0x7f, 0xff]),
// Values that need to have an 0x00 prefix to disambiguate them from
// them from negative values.
(&[0x02, 0x03, 0x00, 0x80, 0x00], &[0x80, 0x00]),
(&[0x02, 0x03, 0x00, 0x81, 0x01], &[0x81, 0x01]),
(&[0x02, 0x03, 0x00, 0xfe, 0xfe], &[0xfe, 0xfe]),
(&[0x02, 0x03, 0x00, 0xff, 0xff], &[0xff, 0xff]),
];
static BAD_NONNEGATIVE_INTEGERS: &[&[u8]] = &[
&[], // At end of input
&[0x02], // Tag only
&[0x02, 0x00], // Empty value
// Length mismatch
&[0x02, 0x00, 0x01],
&[0x02, 0x01],
// Would be valid if leading zero is ignored when comparing length.
&[0x02, 0x01, 0x00, 0x01],
&[0x02, 0x01, 0x01, 0x00], // Would be valid if last byte is ignored.
&[0x02, 0x02, 0x01],
// Values that are missing a necessary leading 0x00
&[0x02, 0x01, 0x80],
&[0x02, 0x01, 0x81],
&[0x02, 0x01, 0xfe],
&[0x02, 0x01, 0xff],
// Values that have an unnecessary leading 0x00
&[0x02, 0x02, 0x00, 0x00],
&[0x02, 0x02, 0x00, 0x01],
&[0x02, 0x02, 0x00, 0x02],
&[0x02, 0x02, 0x00, 0x7e],
&[0x02, 0x02, 0x00, 0x7f],
];
#[test]
fn test_small_nonnegative_integer() {
let zero = (ZERO_INTEGER, 0x00);
for &(test_in, test_out) in
core::iter::once(&zero).chain(GOOD_POSITIVE_INTEGERS_SMALL.iter())
{
let result = with_i(test_in, |input| {
assert_eq!(small_nonnegative_integer(input)?, test_out);
Ok(())
});
assert_eq!(result, Ok(()));
}
for &test_in in BAD_NONNEGATIVE_INTEGERS
.iter()
.chain(GOOD_POSITIVE_INTEGERS_LARGE.iter().map(|(input, _)| input))
{
let result = with_i(test_in, small_nonnegative_integer);
assert_eq!(result, Err(error::Unspecified));
}
}
#[test]
fn test_positive_integer() {
for (test_in, test_out) in GOOD_POSITIVE_INTEGERS_SMALL
.iter()
.map(|(test_in, test_out)| (*test_in, core::slice::from_ref(test_out)))
.chain(GOOD_POSITIVE_INTEGERS_LARGE.iter().copied())
{
let result = with_i(test_in, |input| {
assert_eq!(
positive_integer(input)?.big_endian_without_leading_zero(),
test_out
);
Ok(())
});
assert_eq!(result, Ok(()))
}
for &test_in in core::iter::once(&ZERO_INTEGER).chain(BAD_NONNEGATIVE_INTEGERS.iter()) {
let result = with_i(test_in, positive_integer);
assert!(matches!(result, Err(error::Unspecified)));
}
}
}

71
vendor/ring/src/io/der_writer.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2018 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{der::*, writer::*, *};
use alloc::boxed::Box;
pub(crate) fn write_positive_integer(
output: &mut dyn Accumulator,
value: &Positive,
) -> Result<(), TooLongError> {
let first_byte = value.first_byte();
let value = value.big_endian_without_leading_zero_as_input();
write_tlv(output, Tag::Integer, |output| {
if (first_byte & 0x80) != 0 {
output.write_byte(0)?; // Disambiguate negative number.
}
write_copy(output, value)
})
}
pub(crate) fn write_all(
tag: Tag,
write_value: &dyn Fn(&mut dyn Accumulator) -> Result<(), TooLongError>,
) -> Result<Box<[u8]>, TooLongError> {
let length = {
let mut length = LengthMeasurement::zero();
write_tlv(&mut length, tag, write_value)?;
length
};
let mut output = Writer::with_capacity(length);
write_tlv(&mut output, tag, write_value)?;
Ok(output.into())
}
fn write_tlv<F>(output: &mut dyn Accumulator, tag: Tag, write_value: F) -> Result<(), TooLongError>
where
F: Fn(&mut dyn Accumulator) -> Result<(), TooLongError>,
{
let length: usize = {
let mut length = LengthMeasurement::zero();
write_value(&mut length)?;
length.into()
};
let length: u16 = length.try_into().map_err(|_| TooLongError::new())?;
output.write_byte(tag.into())?;
let [lo, hi] = length.to_le_bytes();
if length >= 0x1_00 {
output.write_byte(0x82)?;
output.write_byte(hi)?;
} else if length >= 0x80 {
output.write_byte(0x81)?;
}
output.write_byte(lo)?;
write_value(output)
}

98
vendor/ring/src/io/positive.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
// Copyright 2018 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Serialization and deserialization.
use crate::error;
/// A serialized positive integer.
#[derive(Copy, Clone)]
pub struct Positive<'a>(untrusted::Input<'a>);
impl<'a> Positive<'a> {
#[inline]
pub(crate) fn from_be_bytes(input: untrusted::Input<'a>) -> Result<Self, error::Unspecified> {
// Empty inputs are not allowed.
let &first_byte = input
.as_slice_less_safe()
.first()
.ok_or(error::Unspecified)?;
// Zero isn't allowed and leading zeros aren't allowed.
if first_byte == 0 {
return Err(error::Unspecified);
}
Ok(Self(input))
}
/// Returns the value, ordered from significant byte to least significant
/// byte, without any leading zeros. The result is guaranteed to be
/// non-empty.
#[inline]
pub fn big_endian_without_leading_zero(&self) -> &'a [u8] {
self.big_endian_without_leading_zero_as_input()
.as_slice_less_safe()
}
#[inline]
pub(crate) fn big_endian_without_leading_zero_as_input(&self) -> untrusted::Input<'a> {
self.0
}
}
impl Positive<'_> {
/// Returns the first byte.
///
/// Will not panic because the value is guaranteed to have at least one
/// byte.
pub fn first_byte(&self) -> u8 {
// This won't panic because
self.0.as_slice_less_safe()[0]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_be_bytes() {
static TEST_CASES: &[(&[u8], Result<&[u8], error::Unspecified>)] = &[
// An empty input isn't a number.
(&[], Err(error::Unspecified)),
// Zero is not positive.
(&[0x00], Err(error::Unspecified)),
// Minimum value. No leading zero required or allowed.
(&[0x00, 0x01], Err(error::Unspecified)),
(&[0x01], Ok(&[0x01])),
// Maximum first byte. No leading zero required or allowed.
(&[0xff], Ok(&[0xff])),
(&[0x00, 0xff], Err(error::Unspecified)),
// The last byte can be zero.
(&[0x01, 0x00], Ok(&[0x01, 0x00])),
(&[0x01, 0x00, 0x00], Ok(&[0x01, 0x00, 0x00])),
// Having no zero bytes are also allowed.
(&[0x01, 0x01], Ok(&[0x01, 0x01])),
// A middle byte can be zero.
(&[0x01, 0x00, 0x01], Ok(&[0x01, 0x00, 0x01])),
(&[0x01, 0x01, 0x01], Ok(&[0x01, 0x01, 0x01])),
];
for &(input, result) in TEST_CASES {
let input = untrusted::Input::from(input);
assert_eq!(
Positive::from_be_bytes(input).map(|p| p.big_endian_without_leading_zero()),
result
);
}
}
}

97
vendor/ring/src/io/writer.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
// Copyright 2018 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use alloc::{boxed::Box, vec::Vec};
pub trait Accumulator {
fn write_byte(&mut self, value: u8) -> Result<(), TooLongError>;
fn write_bytes(&mut self, value: &[u8]) -> Result<(), TooLongError>;
}
pub(super) struct LengthMeasurement {
len: usize,
}
impl From<LengthMeasurement> for usize {
fn from(len: LengthMeasurement) -> usize {
len.len
}
}
impl LengthMeasurement {
pub fn zero() -> Self {
Self { len: 0 }
}
}
impl Accumulator for LengthMeasurement {
fn write_byte(&mut self, _value: u8) -> Result<(), TooLongError> {
self.len = self.len.checked_add(1).ok_or_else(TooLongError::new)?;
Ok(())
}
fn write_bytes(&mut self, value: &[u8]) -> Result<(), TooLongError> {
self.len = self
.len
.checked_add(value.len())
.ok_or_else(TooLongError::new)?;
Ok(())
}
}
pub(super) struct Writer {
bytes: Vec<u8>,
requested_capacity: usize,
}
impl Writer {
pub(super) fn with_capacity(capacity: LengthMeasurement) -> Self {
Self {
bytes: Vec::with_capacity(capacity.len),
requested_capacity: capacity.len,
}
}
}
impl From<Writer> for Box<[u8]> {
fn from(writer: Writer) -> Self {
assert_eq!(writer.requested_capacity, writer.bytes.len());
writer.bytes.into_boxed_slice()
}
}
impl Accumulator for Writer {
fn write_byte(&mut self, value: u8) -> Result<(), TooLongError> {
self.bytes.push(value);
Ok(())
}
fn write_bytes(&mut self, value: &[u8]) -> Result<(), TooLongError> {
self.bytes.extend(value);
Ok(())
}
}
pub fn write_copy(
accumulator: &mut dyn Accumulator,
to_copy: untrusted::Input,
) -> Result<(), TooLongError> {
accumulator.write_bytes(to_copy.as_slice_less_safe())
}
pub struct TooLongError(());
impl TooLongError {
pub fn new() -> Self {
Self(())
}
}