blob: fac53625e8083c0909d56d7faed4777b45e059a4 [file] [log] [blame]
// Copyright 2015-2020 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 AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 crate::Error;
// https://tools.ietf.org/html/rfc5280#section-4.2.1.10 says:
//
// For IPv4 addresses, the iPAddress field of GeneralName MUST contain
// eight (8) octets, encoded in the style of RFC 4632 (CIDR) to represent
// an address range [RFC4632]. For IPv6 addresses, the iPAddress field
// MUST contain 32 octets similarly encoded. For example, a name
// constraint for "class C" subnet 192.0.2.0 is represented as the
// octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
// 192.0.2.0/24 (mask 255.255.255.0).
pub(super) fn presented_id_matches_constraint(
name: untrusted::Input,
constraint: untrusted::Input,
) -> Result<bool, Error> {
if name.len() != 4 && name.len() != 16 {
return Err(Error::BadDer);
}
if constraint.len() != 8 && constraint.len() != 32 {
return Err(Error::BadDer);
}
// an IPv4 address never matches an IPv6 constraint, and vice versa.
if name.len() * 2 != constraint.len() {
return Ok(false);
}
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);
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();
if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 {
return Ok(false);
}
if name.at_end() {
break;
}
}
Ok(true)
}