#[cfg(feature = "std")]
use core::fmt::Write;
use crate::Error;
#[cfg(feature = "alloc")]
use alloc::string::String;
const VALID_IP_BY_CONSTRUCTION: &str = "IP address is a valid string by construction";
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum IpAddr {
V4(String, [u8; 4]),
V6(String, [u8; 16]),
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl AsRef<str> for IpAddr {
fn as_ref(&self) -> &str {
match self {
IpAddr::V4(ip_address, _) | IpAddr::V6(ip_address, _) => ip_address.as_str(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IpAddrRef<'a> {
V4(&'a [u8], [u8; 4]),
V6(&'a [u8], [u8; 16]),
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'a> From<IpAddrRef<'a>> for IpAddr {
fn from(ip_address: IpAddrRef<'a>) -> IpAddr {
match ip_address {
IpAddrRef::V4(ip_address, ip_address_octets) => IpAddr::V4(
String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
ip_address_octets,
),
IpAddrRef::V6(ip_address, ip_address_octets) => IpAddr::V6(
String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
ip_address_octets,
),
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'a> From<&'a IpAddr> for IpAddrRef<'a> {
fn from(ip_address: &'a IpAddr) -> IpAddrRef<'a> {
match ip_address {
IpAddr::V4(ip_address, ip_address_octets) => {
IpAddrRef::V4(ip_address.as_bytes(), *ip_address_octets)
}
IpAddr::V6(ip_address, ip_address_octets) => {
IpAddrRef::V6(ip_address.as_bytes(), *ip_address_octets)
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AddrParseError;
impl core::fmt::Display for AddrParseError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl ::std::error::Error for AddrParseError {}
impl<'a> IpAddrRef<'a> {
pub fn try_from_ascii(ip_address: &'a [u8]) -> Result<Self, AddrParseError> {
if let Ok(ip_address) = parse_ipv4_address(ip_address) {
Ok(ip_address)
} else if let Ok(ip_address) = parse_ipv6_address(ip_address) {
Ok(ip_address)
} else {
Err(AddrParseError)
}
}
pub fn try_from_ascii_str(ip_address: &'a str) -> Result<Self, AddrParseError> {
Self::try_from_ascii(ip_address.as_bytes())
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn to_owned(&self) -> IpAddr {
match self {
IpAddrRef::V4(ip_address, ip_address_octets) => IpAddr::V4(
String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
*ip_address_octets,
),
IpAddrRef::V6(ip_address, ip_address_octets) => IpAddr::V6(
String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
*ip_address_octets,
),
}
}
}
#[cfg(feature = "std")]
fn ipv6_to_uncompressed_string(octets: [u8; 16]) -> String {
let mut result = String::with_capacity(39);
for i in 0..7 {
result
.write_fmt(format_args!(
"{:02x?}{:02x?}:",
octets[i * 2],
octets[(i * 2) + 1]
))
.expect("unexpected error while formatting IPv6 address");
}
result
.write_fmt(format_args!("{:02x?}{:02x?}", octets[14], octets[15]))
.expect("unexpected error while formatting IPv6 address");
result
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl From<std::net::IpAddr> for IpAddr {
fn from(ip_address: std::net::IpAddr) -> IpAddr {
match ip_address {
std::net::IpAddr::V4(ip_address) => {
IpAddr::V4(ip_address.to_string(), ip_address.octets())
}
std::net::IpAddr::V6(ip_address) => IpAddr::V6(
ipv6_to_uncompressed_string(ip_address.octets()),
ip_address.octets(),
),
}
}
}
impl<'a> From<IpAddrRef<'a>> for &'a str {
fn from(ip_address: IpAddrRef<'a>) -> &'a str {
match ip_address {
IpAddrRef::V4(ip_address, _) | IpAddrRef::V6(ip_address, _) => {
core::str::from_utf8(ip_address).expect(VALID_IP_BY_CONSTRUCTION)
}
}
}
}
impl<'a> From<IpAddrRef<'a>> for &'a [u8] {
fn from(ip_address: IpAddrRef<'a>) -> &'a [u8] {
match ip_address {
IpAddrRef::V4(ip_address, _) | IpAddrRef::V6(ip_address, _) => ip_address,
}
}
}
pub(super) fn presented_id_matches_reference_id(
presented_id: untrusted::Input,
reference_id: untrusted::Input,
) -> bool {
match (presented_id.len(), reference_id.len()) {
(4, 4) => (),
(16, 16) => (),
_ => {
return false;
}
};
let mut presented_ip_address = untrusted::Reader::new(presented_id);
let mut reference_ip_address = untrusted::Reader::new(reference_id);
while !presented_ip_address.at_end() {
let presented_ip_address_byte = presented_ip_address.read_byte().unwrap();
let reference_ip_address_byte = reference_ip_address.read_byte().unwrap();
if presented_ip_address_byte != reference_ip_address_byte {
return false;
}
}
true
}
pub(super) fn presented_id_matches_constraint(
name: untrusted::Input,
constraint: untrusted::Input,
) -> Result<bool, Error> {
match (name.len(), constraint.len()) {
(4, 8) => (),
(16, 32) => (),
(4, 32) | (16, 8) => {
return Ok(false);
}
(4, _) | (16, _) => {
return Err(Error::InvalidNetworkMaskConstraint);
}
_ => {
return Err(Error::BadDer);
}
};
let (constraint_address, constraint_mask) = constraint.read_all(Error::BadDer, |value| {
let address = value.read_bytes(constraint.len() / 2).unwrap();
let mask = value.read_bytes(constraint.len() / 2).unwrap();
Ok((address, mask))
})?;
let mut name = untrusted::Reader::new(name);
let mut constraint_address = untrusted::Reader::new(constraint_address);
let mut constraint_mask = untrusted::Reader::new(constraint_mask);
let mut seen_zero_bit = false;
loop {
let name_byte = name.read_byte().unwrap();
let constraint_address_byte = constraint_address.read_byte().unwrap();
let constraint_mask_byte = constraint_mask.read_byte().unwrap();
let leading = constraint_mask_byte.leading_ones();
let trailing = constraint_mask_byte.trailing_zeros();
if leading + trailing != 8 {
return Err(Error::InvalidNetworkMaskConstraint);
}
if seen_zero_bit && constraint_mask_byte != 0x00 {
return Err(Error::InvalidNetworkMaskConstraint);
}
if constraint_mask_byte != 0xff {
seen_zero_bit = true;
}
if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 {
return Ok(false);
}
if name.at_end() {
break;
}
}
Ok(true)
}
pub(crate) fn parse_ipv4_address(ip_address_: &[u8]) -> Result<IpAddrRef, AddrParseError> {
let mut ip_address = untrusted::Reader::new(untrusted::Input::from(ip_address_));
let mut is_first_byte = true;
let mut current_octet: [u8; 3] = [0, 0, 0];
let mut current_size = 0;
let mut dot_count = 0;
let mut octet = 0;
let mut octets: [u8; 4] = [0, 0, 0, 0];
fn radix10_to_octet(textual_octets: &[u8]) -> u32 {
let mut result: u32 = 0;
for digit in textual_octets.iter() {
result *= 10;
result += u32::from(*digit);
}
result
}
loop {
match ip_address.read_byte() {
Ok(b'.') => {
if is_first_byte {
return Err(AddrParseError);
}
if ip_address.at_end() {
return Err(AddrParseError);
}
if dot_count == 3 {
return Err(AddrParseError);
}
dot_count += 1;
if current_size == 0 {
return Err(AddrParseError);
}
let current_raw_octet = radix10_to_octet(¤t_octet[..current_size]);
if current_raw_octet > 255 {
return Err(AddrParseError);
}
octets[octet] =
TryInto::<u8>::try_into(current_raw_octet).expect("invalid character");
octet += 1;
current_octet = [0, 0, 0];
current_size = 0;
}
Ok(number @ b'0'..=b'9') => {
if number == b'0'
&& current_size == 0
&& !ip_address.peek(b'.')
&& !ip_address.at_end()
{
return Err(AddrParseError);
}
if current_size >= current_octet.len() {
return Err(AddrParseError);
}
current_octet[current_size] = number - b'0';
current_size += 1;
}
_ => {
return Err(AddrParseError);
}
}
is_first_byte = false;
if ip_address.at_end() {
let last_octet = radix10_to_octet(¤t_octet[..current_size]);
if current_size > 0 && last_octet > 255 {
return Err(AddrParseError);
}
octets[octet] = TryInto::<u8>::try_into(last_octet).expect("invalid character");
break;
}
}
if dot_count != 3 {
return Err(AddrParseError);
}
Ok(IpAddrRef::V4(ip_address_, octets))
}
pub(crate) fn parse_ipv6_address(ip_address_: &[u8]) -> Result<IpAddrRef, AddrParseError> {
if ip_address_.len() != 39 {
return Err(AddrParseError);
}
let mut ip_address = untrusted::Reader::new(untrusted::Input::from(ip_address_));
let mut is_first_byte = true;
let mut current_textual_block_size = 0;
let mut colon_count = 0;
let mut octet = 0;
let mut previous_character = None;
let mut octets: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
loop {
match ip_address.read_byte() {
Ok(b':') => {
if is_first_byte {
return Err(AddrParseError);
}
if ip_address.at_end() {
return Err(AddrParseError);
}
if colon_count == 7 {
return Err(AddrParseError);
}
colon_count += 1;
if current_textual_block_size == 0 {
return Err(AddrParseError);
}
if current_textual_block_size != 4 {
return Err(AddrParseError);
}
current_textual_block_size = 0;
previous_character = None;
}
Ok(character @ b'0'..=b'9')
| Ok(character @ b'a'..=b'f')
| Ok(character @ b'A'..=b'F') => {
if current_textual_block_size == 4 {
return Err(AddrParseError);
}
if let Some(previous_character_) = previous_character {
octets[octet] = (TryInto::<u8>::try_into(
TryInto::<u8>::try_into(
(TryInto::<char>::try_into(previous_character_)
.expect("invalid character"))
.to_digit(16)
.unwrap(),
)
.expect("invalid character"),
)
.expect("invalid character")
<< 4)
| (TryInto::<u8>::try_into(
TryInto::<char>::try_into(character)
.expect("invalid character")
.to_digit(16)
.unwrap(),
)
.expect("invalid character"));
previous_character = None;
octet += 1;
} else {
previous_character = Some(character);
}
current_textual_block_size += 1;
}
_ => {
return Err(AddrParseError);
}
}
is_first_byte = false;
if ip_address.at_end() {
break;
}
}
if colon_count != 7 {
return Err(AddrParseError);
}
Ok(IpAddrRef::V6(ip_address_, octets))
}
#[cfg(test)]
mod tests {
use super::*;
const fn ipv4_address(
ip_address: &[u8],
octets: [u8; 4],
) -> (&[u8], Result<IpAddrRef, AddrParseError>) {
(ip_address, Ok(IpAddrRef::V4(ip_address, octets)))
}
const IPV4_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
ipv4_address(b"0.0.0.0", [0, 0, 0, 0]),
ipv4_address(b"1.1.1.1", [1, 1, 1, 1]),
ipv4_address(b"205.0.0.0", [205, 0, 0, 0]),
ipv4_address(b"0.205.0.0", [0, 205, 0, 0]),
ipv4_address(b"0.0.205.0", [0, 0, 205, 0]),
ipv4_address(b"0.0.0.205", [0, 0, 0, 205]),
ipv4_address(b"0.0.0.20", [0, 0, 0, 20]),
(b"", Err(AddrParseError)),
(b"...", Err(AddrParseError)),
(b".0.0.0.0", Err(AddrParseError)),
(b"0.0.0.0.", Err(AddrParseError)),
(b"0.0.0", Err(AddrParseError)),
(b"0.0.0.", Err(AddrParseError)),
(b"256.0.0.0", Err(AddrParseError)),
(b"0.256.0.0", Err(AddrParseError)),
(b"0.0.256.0", Err(AddrParseError)),
(b"0.0.0.256", Err(AddrParseError)),
(b"1..1.1.1", Err(AddrParseError)),
(b"1.1..1.1", Err(AddrParseError)),
(b"1.1.1..1", Err(AddrParseError)),
(b"025.0.0.0", Err(AddrParseError)),
(b"0.025.0.0", Err(AddrParseError)),
(b"0.0.025.0", Err(AddrParseError)),
(b"0.0.0.025", Err(AddrParseError)),
(b"1234.0.0.0", Err(AddrParseError)),
(b"0.1234.0.0", Err(AddrParseError)),
(b"0.0.1234.0", Err(AddrParseError)),
(b"0.0.0.1234", Err(AddrParseError)),
];
#[test]
fn parse_ipv4_address_test() {
for &(ip_address, expected_result) in IPV4_ADDRESSES {
assert_eq!(parse_ipv4_address(ip_address), expected_result,);
}
}
const fn ipv6_address(
ip_address: &[u8],
octets: [u8; 16],
) -> (&[u8], Result<IpAddrRef, AddrParseError>) {
(ip_address, Ok(IpAddrRef::V6(ip_address, octets)))
}
const IPV6_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
ipv6_address(
b"2a05:d018:076c:b685:e8ab:afd3:af51:3aed",
[
0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
0x3a, 0xed,
],
),
ipv6_address(
b"2A05:D018:076C:B685:E8AB:AFD3:AF51:3AED",
[
0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
0x3a, 0xed,
],
),
ipv6_address(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
],
),
ipv6_address(
b"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
],
),
ipv6_address(
b"FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
],
),
(
b"aaa:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:aaa:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:aaa:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:aaa:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:aaa:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:aaa:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:aaa:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:aaa",
Err(AddrParseError),
),
(
b"ffgf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:gfff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:fffg:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffgf:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:gfff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:fgff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffgf:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffgf:fffg",
Err(AddrParseError),
),
(
b":ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff::ffff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff::ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff::ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff::ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff::ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffff::ffff",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:",
Err(AddrParseError),
),
(
b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
Err(AddrParseError),
),
(
b"\xc3\x28a05:d018:076c:b685:e8ab:afd3:af51:3aed",
Err(AddrParseError),
),
(
b"ga05:d018:076c:b685:e8ab:afd3:af51:3aed",
Err(AddrParseError),
),
(
b":a05:d018:076c:b685:e8ab:afd3:af51:3aed",
Err(AddrParseError),
),
(
b"2a05:d018:076c:b685:e8ab:afd3:af51:3ae:",
Err(AddrParseError),
),
(
b"2a05:d018:076c:b685:e8ab:afd3:af51:3a::",
Err(AddrParseError),
),
(
b"2a05::018:076c:b685:e8ab:afd3:af51:3aed",
Err(AddrParseError),
),
(
b"2a056:d018:076c:b685:e8ab:afd3:af51:3ae",
Err(AddrParseError),
),
(
b"2a0:d018:076c:b685:e8ab:afd3:af51:3aed ",
Err(AddrParseError),
),
(b"d018:076c:b685:e8ab:afd3:af51:3aed", Err(AddrParseError)),
(
b"2a05:d018:076c:b685:e8ab:afd3:af51:3aed3aed",
Err(AddrParseError),
),
(b"0:0:0:0:0:0:0:1", Err(AddrParseError)),
(
b"2a05:d018:76c:b685:e8ab:afd3:af51:3aed",
Err(AddrParseError),
),
];
#[test]
fn parse_ipv6_address_test() {
for &(ip_address, expected_result) in IPV6_ADDRESSES {
assert_eq!(parse_ipv6_address(ip_address), expected_result,);
}
}
#[test]
fn try_from_ascii_ip_address_test() {
const IP_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
(
b"127.0.0.1",
Ok(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1])),
),
(
b"127.0.0.",
Err(AddrParseError),
),
(
b"0000:0000:0000:0000:0000:0000:0000:0001",
Ok(IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
)),
),
(
b"0:0:0:0:0:0:0:1",
Err(AddrParseError),
),
(
b"example.com",
Err(AddrParseError),
),
];
for &(ip_address, expected_result) in IP_ADDRESSES {
assert_eq!(IpAddrRef::try_from_ascii(ip_address), expected_result)
}
}
#[test]
fn try_from_ascii_str_ip_address_test() {
const IP_ADDRESSES: &[(&str, Result<IpAddrRef, AddrParseError>)] = &[
("127.0.0.1", Ok(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]))),
(
"127.0.0.",
Err(AddrParseError),
),
(
"0000:0000:0000:0000:0000:0000:0000:0001",
Ok(IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
)),
),
(
"0:0:0:0:0:0:0:1",
Err(AddrParseError),
),
(
"example.com",
Err(AddrParseError),
),
];
for &(ip_address, expected_result) in IP_ADDRESSES {
assert_eq!(IpAddrRef::try_from_ascii_str(ip_address), expected_result)
}
}
#[test]
fn str_from_ip_address_ref_test() {
let ip_addresses = vec![
(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]), "127.0.0.1"),
(
IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
),
"0000:0000:0000:0000:0000:0000:0000:0001",
),
];
for (ip_address, expected_ip_address) in ip_addresses {
assert_eq!(Into::<&str>::into(ip_address), expected_ip_address,)
}
}
#[test]
fn u8_array_from_ip_address_ref_test() {
let ip_addresses = vec![
(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]), "127.0.0.1"),
(
IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
),
"0000:0000:0000:0000:0000:0000:0000:0001",
),
];
for (ip_address, expected_ip_address) in ip_addresses {
assert_eq!(
Into::<&[u8]>::into(ip_address),
expected_ip_address.as_bytes()
)
}
}
#[test]
fn presented_id_matches_constraint_ipv4_test() {
let names_and_constraints = vec![
(
[0xC0, 0x00, 0x02, 0x00],
[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
Ok(true),
),
(
[0xC0, 0x00, 0x02, 0x01],
[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
Ok(true),
),
(
[0xC0, 0x00, 0x02, 0xFF],
[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
Ok(true),
),
(
[0xC0, 0x00, 0x01, 0xFF],
[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
Ok(false),
),
(
[0xC0, 0x00, 0x03, 0x00],
[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
Ok(false),
),
];
for (name, constraint, match_result) in names_and_constraints {
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&name),
untrusted::Input::from(&constraint),
),
match_result
)
}
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[0xC0, 0x00, 0x02]),
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
),
Err(Error::BadDer),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0x00]),
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
),
Err(Error::BadDer),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF]),
),
Err(Error::InvalidNetworkMaskConstraint),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00]),
),
Err(Error::InvalidNetworkMaskConstraint),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
),
Ok(false),
);
}
#[test]
fn presented_id_matches_constraint_ipv6_test() {
let names_and_constraints = vec![
(
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
],
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
Ok(true),
),
(
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01,
],
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
Ok(true),
),
(
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
],
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
Ok(true),
),
(
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
],
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
Ok(false),
),
(
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
],
[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
Ok(false),
),
];
for (name, constraint, match_result) in names_and_constraints {
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&name),
untrusted::Input::from(&constraint),
),
match_result
)
}
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
]),
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
),
Err(Error::BadDer),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
]),
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
),
Err(Error::BadDer),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
]),
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
]),
),
Err(Error::InvalidNetworkMaskConstraint),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
]),
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
),
Err(Error::InvalidNetworkMaskConstraint),
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(&[
0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
]),
untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
),
Ok(false),
);
}
#[test]
fn test_presented_id_matches_reference_id() {
assert!(!presented_id_matches_reference_id(
untrusted::Input::from(&[]),
untrusted::Input::from(&[]),
));
assert!(!presented_id_matches_reference_id(
untrusted::Input::from(&[0x01]),
untrusted::Input::from(&[])
));
assert!(!presented_id_matches_reference_id(
untrusted::Input::from(&[]),
untrusted::Input::from(&[0x01])
));
assert!(presented_id_matches_reference_id(
untrusted::Input::from(&[1, 2, 3, 4]),
untrusted::Input::from(&[1, 2, 3, 4])
));
assert!(!presented_id_matches_reference_id(
untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
untrusted::Input::from(&[1, 2, 3, 4])
));
assert!(!presented_id_matches_reference_id(
untrusted::Input::from(&[1, 2, 3, 4]),
untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
));
assert!(presented_id_matches_reference_id(
untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
));
}
#[test]
fn presented_id_matches_constraint_rejects_incorrect_length_arguments() {
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(b"\x00\x00\x00"),
untrusted::Input::from(b"")
),
Err(Error::BadDer)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(b"\x00\x00\x00\x00\x00"),
untrusted::Input::from(b"")
),
Err(Error::BadDer)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
),
untrusted::Input::from(b"")
),
Err(Error::BadDer)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
),
untrusted::Input::from(b"")
),
Err(Error::BadDer)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(b"\x00\x00\x00\x00"),
untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff")
),
Err(Error::InvalidNetworkMaskConstraint)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(b"\x00\x00\x00\x00"),
untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff\x00")
),
Err(Error::InvalidNetworkMaskConstraint)
);
assert_eq!(
presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
Err(Error::InvalidNetworkMaskConstraint)
);
assert_eq!(
presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
Err(Error::InvalidNetworkMaskConstraint)
);
assert_eq!(
presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00"),
untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
Ok(false)
);
assert_eq!(
presented_id_matches_constraint(
untrusted::Input::from(
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
),
untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff")
),
Ok(false)
);
}
}
#[cfg(all(test, feature = "alloc"))]
mod alloc_tests {
use super::*;
#[test]
fn as_ref_ip_address_test() {
assert_eq!(
IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]).as_ref(),
"127.0.0.1",
);
assert_eq!(
IpAddr::V6(
String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
)
.as_ref(),
"0000:0000:0000:0000:0000:0000:0000:0001",
);
}
#[test]
fn from_ip_address_ref_for_ip_address_test() {
{
let (ip_address, ip_address_octets) = ("127.0.0.1", [127, 0, 0, 1]);
assert_eq!(
IpAddr::from(IpAddrRef::V4(ip_address.as_bytes(), ip_address_octets)),
IpAddr::V4(String::from(ip_address), ip_address_octets),
)
}
{
let (ip_address, ip_address_octets) = (
"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
);
assert_eq!(
IpAddr::from(IpAddrRef::V6(ip_address.as_bytes(), ip_address_octets)),
IpAddr::V6(String::from(ip_address), ip_address_octets),
)
}
}
#[test]
fn from_ip_address_for_ip_address_ref_test() {
{
let ip_address = IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]);
assert_eq!(
IpAddrRef::from(&ip_address),
IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]),
)
}
{
let ip_address = IpAddr::V6(
String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
);
assert_eq!(
IpAddrRef::from(&ip_address),
IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
),
)
}
}
#[test]
fn display_invalid_ip_address_error_test() {
assert_eq!(AddrParseError.to_string(), String::from("AddrParseError"),)
}
#[test]
fn ip_address_ref_to_owned_test() {
{
assert_eq!(
IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]).to_owned(),
IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]),
)
}
{
assert_eq!(
IpAddrRef::V6(
b"0000:0000:0000:0000:0000:0000:0000:0001",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
)
.to_owned(),
IpAddr::V6(
String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
),
)
}
}
#[test]
fn ip_address_from_std_net_ipaddr_test() {
let ip_addresses = vec![
(
std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]),
),
(
std::net::IpAddr::V6(std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
IpAddr::V6(
String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
),
),
];
for (ip_address, expected_ip_address) in ip_addresses {
assert_eq!(IpAddr::from(ip_address), expected_ip_address,)
}
}
#[test]
fn ipv6_to_uncompressed_string_test() {
let ip_addresses = vec![
(
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
),
(
[
0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x84, 0x8e, 0x48, 0x47, 0xc9, 0x84,
0xaa, 0xb3, 0x4d,
],
String::from("2a05:d018:076c:b684:8e48:47c9:84aa:b34d"),
),
];
for (ip_address_octets, expected_result) in ip_addresses {
assert_eq!(
ipv6_to_uncompressed_string(ip_address_octets),
expected_result,
)
}
}
const PRESENTED_MATCHES_CONSTRAINT: &[(&str, &str, &str, Result<bool, Error>)] = &[
("2001:db8::", "8.8.8.8", "255.255.255.255", Ok(false)),
("8.8.8.8", "2001:db8::", "ffff::", Ok(false)),
(
"8.8.8.8",
"8.8.8.8",
"255.255.255.1",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"8.8.8.8",
"8.8.8.8",
"255.255.0.255",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"8.8.8.8",
"8.8.8.8",
"255.0.255.255",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"8.8.8.8",
"8.8.8.8",
"0.255.255.255",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"8.8.8.8",
"8.8.8.8",
"1.255.255.255",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"8.8.8.8",
"8.8.8.8",
"128.128.128.128",
Err(Error::InvalidNetworkMaskConstraint),
),
("8.8.8.8", "8.8.8.8", "255.255.255.255", Ok(true)),
("8.8.8.9", "8.8.8.8", "255.255.255.255", Ok(false)),
("8.8.8.9", "8.8.8.8", "255.255.255.254", Ok(true)),
("8.8.8.10", "8.8.8.8", "255.255.255.254", Ok(false)),
("8.8.8.10", "8.8.8.8", "255.255.255.0", Ok(true)),
("8.8.15.10", "8.8.8.8", "255.255.248.0", Ok(true)),
("8.8.16.10", "8.8.8.8", "255.255.248.0", Ok(false)),
("8.8.16.10", "8.8.8.8", "255.255.0.0", Ok(true)),
("8.31.16.10", "8.8.8.8", "255.224.0.0", Ok(true)),
("8.32.16.10", "8.8.8.8", "255.224.0.0", Ok(false)),
("8.32.16.10", "8.8.8.8", "255.0.0.0", Ok(true)),
("63.32.16.10", "8.8.8.8", "192.0.0.0", Ok(true)),
("64.32.16.10", "8.8.8.8", "192.0.0.0", Ok(false)),
("64.32.16.10", "8.8.8.8", "0.0.0.0", Ok(true)),
(
"2001:db8::",
"2001:db8::",
"fffe:ffff::",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"2001:db8::",
"2001:db8::",
"ffff:fdff::",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"2001:db8::",
"2001:db8::",
"ffff:feff::",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"2001:db8::",
"2001:db8::",
"ffff:fcff::",
Err(Error::InvalidNetworkMaskConstraint),
),
(
"2001:db8::",
"2001:db8::",
"7fff:ffff::",
Err(Error::InvalidNetworkMaskConstraint),
),
("2001:db8::", "2001:db8::", "ffff:ffff::", Ok(true)),
("2001:db9::", "2001:db8::", "ffff:ffff::", Ok(false)),
("2001:db9::", "2001:db8::", "ffff:fffe::", Ok(true)),
("2001:dba::", "2001:db8::", "ffff:fffe::", Ok(false)),
("2001:dba::", "2001:db8::", "ffff:ff00::", Ok(true)),
("2001:dca::", "2001:db8::", "ffff:fe00::", Ok(true)),
("2001:fca::", "2001:db8::", "ffff:fe00::", Ok(false)),
("2001:fca::", "2001:db8::", "ffff:0000::", Ok(true)),
("2000:fca::", "2001:db8::", "fffe:0000::", Ok(true)),
("2003:fca::", "2001:db8::", "fffe:0000::", Ok(false)),
("2003:fca::", "2001:db8::", "ff00:0000::", Ok(true)),
("1003:fca::", "2001:db8::", "e000:0000::", Ok(false)),
("1003:fca::", "2001:db8::", "0000:0000::", Ok(true)),
];
#[cfg(feature = "std")]
#[test]
fn presented_matches_constraint_test() {
use std::boxed::Box;
use std::net::IpAddr;
for &(presented, constraint_address, constraint_mask, expected_result) in
PRESENTED_MATCHES_CONSTRAINT
{
let presented_bytes: Box<[u8]> = match presented.parse::<IpAddr>().unwrap() {
IpAddr::V4(p) => Box::new(p.octets()),
IpAddr::V6(p) => Box::new(p.octets()),
};
let ca_bytes: Box<[u8]> = match constraint_address.parse::<IpAddr>().unwrap() {
IpAddr::V4(ca) => Box::new(ca.octets()),
IpAddr::V6(ca) => Box::new(ca.octets()),
};
let cm_bytes: Box<[u8]> = match constraint_mask.parse::<IpAddr>().unwrap() {
IpAddr::V4(cm) => Box::new(cm.octets()),
IpAddr::V6(cm) => Box::new(cm.octets()),
};
let constraint_bytes = [ca_bytes, cm_bytes].concat();
let actual_result = presented_id_matches_constraint(
untrusted::Input::from(&presented_bytes),
untrusted::Input::from(&constraint_bytes),
);
assert_eq!(
actual_result, expected_result,
"presented_id_matches_constraint(\"{:?}\", \"{:?}\")",
presented_bytes, constraint_bytes
);
}
}
}