1 // Copyright 2015-2020 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 use crate::Error;
16 
17 // https://tools.ietf.org/html/rfc5280#section-4.2.1.10 says:
18 //
19 //     For IPv4 addresses, the iPAddress field of GeneralName MUST contain
20 //     eight (8) octets, encoded in the style of RFC 4632 (CIDR) to represent
21 //     an address range [RFC4632].  For IPv6 addresses, the iPAddress field
22 //     MUST contain 32 octets similarly encoded.  For example, a name
23 //     constraint for "class C" subnet 192.0.2.0 is represented as the
24 //     octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
25 //     192.0.2.0/24 (mask 255.255.255.0).
presented_id_matches_constraint( name: untrusted::Input, constraint: untrusted::Input, ) -> Result<bool, Error>26 pub(super) fn presented_id_matches_constraint(
27     name: untrusted::Input,
28     constraint: untrusted::Input,
29 ) -> Result<bool, Error> {
30     if name.len() != 4 && name.len() != 16 {
31         return Err(Error::BadDer);
32     }
33     if constraint.len() != 8 && constraint.len() != 32 {
34         return Err(Error::BadDer);
35     }
36 
37     // an IPv4 address never matches an IPv6 constraint, and vice versa.
38     if name.len() * 2 != constraint.len() {
39         return Ok(false);
40     }
41 
42     let (constraint_address, constraint_mask) = constraint.read_all(Error::BadDer, |value| {
43         let address = value.read_bytes(constraint.len() / 2).unwrap();
44         let mask = value.read_bytes(constraint.len() / 2).unwrap();
45         Ok((address, mask))
46     })?;
47 
48     let mut name = untrusted::Reader::new(name);
49     let mut constraint_address = untrusted::Reader::new(constraint_address);
50     let mut constraint_mask = untrusted::Reader::new(constraint_mask);
51     loop {
52         let name_byte = name.read_byte().unwrap();
53         let constraint_address_byte = constraint_address.read_byte().unwrap();
54         let constraint_mask_byte = constraint_mask.read_byte().unwrap();
55         if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 {
56             return Ok(false);
57         }
58         if name.at_end() {
59             break;
60         }
61     }
62 
63     Ok(true)
64 }
65