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