// 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 { 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) }