1#[cfg(feature = "alloc")]
16use alloc::format;
17
18use pki_types::IpAddr;
19#[cfg(feature = "alloc")]
20use pki_types::ServerName;
21
22use super::{GeneralName, NameIterator};
23use crate::cert::Cert;
24use crate::error::{Error, InvalidNameContext};
25
26pub(crate) fn verify_ip_address_names(reference: &IpAddr, cert: &Cert<'_>) -> Result<(), Error> {
27 let ip_address = match reference {
28 IpAddr::V4(ip) => untrusted::Input::from(ip.as_ref()),
29 IpAddr::V6(ip) => untrusted::Input::from(ip.as_ref()),
30 };
31
32 let result = NameIterator::new(cert.subject_alt_name).find_map(|result| {
33 let name = match result {
34 Ok(name) => name,
35 Err(err) => return Some(Err(err)),
36 };
37
38 let presented_id = match name {
39 GeneralName::IpAddress(presented) => presented,
40 _ => return None,
41 };
42
43 match presented_id_matches_reference_id(presented_id, ip_address) {
44 true => Some(Ok(())),
45 false => None,
46 }
47 });
48
49 match result {
50 Some(result) => return result,
51 #[cfg(feature = "alloc")]
52 None => {}
53 #[cfg(not(feature = "alloc"))]
54 None => Err(Error::CertNotValidForName(InvalidNameContext {})),
55 }
56
57 #[cfg(feature = "alloc")]
58 {
59 Err(Error::CertNotValidForName(InvalidNameContext {
60 expected: ServerName::from(*reference),
61 presented: NameIterator::new(cert.subject_alt_name)
62 .filter_map(|result| Some(format!("{:?}", result.ok()?)))
63 .collect(),
64 }))
65 }
66}
67
68fn presented_id_matches_reference_id(
77 presented_id: untrusted::Input<'_>,
78 reference_id: untrusted::Input<'_>,
79) -> bool {
80 match (presented_id.len(), reference_id.len()) {
81 (4, 4) => (),
82 (16, 16) => (),
83 _ => {
84 return false;
85 }
86 };
87
88 let mut presented_ip_address = untrusted::Reader::new(presented_id);
89 let mut reference_ip_address = untrusted::Reader::new(reference_id);
90 while !presented_ip_address.at_end() {
91 let presented_ip_address_byte = presented_ip_address.read_byte().unwrap();
92 let reference_ip_address_byte = reference_ip_address.read_byte().unwrap();
93 if presented_ip_address_byte != reference_ip_address_byte {
94 return false;
95 }
96 }
97
98 true
99}
100
101pub(super) fn presented_id_matches_constraint(
111 name: untrusted::Input<'_>,
112 constraint: untrusted::Input<'_>,
113) -> Result<bool, Error> {
114 match (name.len(), constraint.len()) {
115 (4, 8) => (),
116 (16, 32) => (),
117
118 (4, 32) | (16, 8) => {
120 return Ok(false);
121 }
122
123 (4, _) | (16, _) => {
125 return Err(Error::InvalidNetworkMaskConstraint);
126 }
127
128 _ => {
130 return Err(Error::BadDer);
131 }
132 };
133
134 let (constraint_address, constraint_mask) = constraint.read_all(Error::BadDer, |value| {
135 let address = value.read_bytes(constraint.len() / 2).unwrap();
136 let mask = value.read_bytes(constraint.len() / 2).unwrap();
137 Ok((address, mask))
138 })?;
139
140 let mut name = untrusted::Reader::new(name);
141 let mut constraint_address = untrusted::Reader::new(constraint_address);
142 let mut constraint_mask = untrusted::Reader::new(constraint_mask);
143 let mut seen_zero_bit = false;
144
145 loop {
146 let name_byte = name.read_byte().unwrap();
149 let constraint_address_byte = constraint_address.read_byte().unwrap();
150 let constraint_mask_byte = constraint_mask.read_byte().unwrap();
151
152 let leading = constraint_mask_byte.leading_ones();
156 let trailing = constraint_mask_byte.trailing_zeros();
157
158 if leading + trailing != 8 {
162 return Err(Error::InvalidNetworkMaskConstraint);
163 }
164
165 if seen_zero_bit && constraint_mask_byte != 0x00 {
167 return Err(Error::InvalidNetworkMaskConstraint);
168 }
169
170 if constraint_mask_byte != 0xff {
172 seen_zero_bit = true;
173 }
174
175 if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 {
176 return Ok(false);
177 }
178 if name.at_end() {
179 break;
180 }
181 }
182
183 Ok(true)
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn presented_id_matches_constraint_ipv4_test() {
192 let names_and_constraints = vec![
193 (
194 [0xC0, 0x00, 0x02, 0x00],
196 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
197 Ok(true),
198 ),
199 (
200 [0xC0, 0x00, 0x02, 0x01],
202 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
203 Ok(true),
204 ),
205 (
206 [0xC0, 0x00, 0x02, 0xFF],
208 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
209 Ok(true),
210 ),
211 (
212 [0xC0, 0x00, 0x01, 0xFF],
214 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
215 Ok(false),
216 ),
217 (
218 [0xC0, 0x00, 0x03, 0x00],
220 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
221 Ok(false),
222 ),
223 ];
224 for (name, constraint, match_result) in names_and_constraints {
225 assert_eq!(
226 presented_id_matches_constraint(
227 untrusted::Input::from(&name),
228 untrusted::Input::from(&constraint),
229 ),
230 match_result
231 )
232 }
233
234 assert_eq!(
236 presented_id_matches_constraint(
237 untrusted::Input::from(&[0xC0, 0x00, 0x02]),
238 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
239 ),
240 Err(Error::BadDer),
241 );
242
243 assert_eq!(
245 presented_id_matches_constraint(
246 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0x00]),
247 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
248 ),
249 Err(Error::BadDer),
250 );
251
252 assert_eq!(
254 presented_id_matches_constraint(
255 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
256 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF]),
257 ),
258 Err(Error::InvalidNetworkMaskConstraint),
259 );
260
261 assert_eq!(
263 presented_id_matches_constraint(
264 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
265 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00]),
266 ),
267 Err(Error::InvalidNetworkMaskConstraint),
268 );
269
270 assert_eq!(
272 presented_id_matches_constraint(
273 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
274 untrusted::Input::from(&[
275 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
278 ]),
279 ),
280 Ok(false),
281 );
282 }
283
284 #[test]
285 fn presented_id_matches_constraint_ipv6_test() {
286 let names_and_constraints = vec![
287 (
288 [
291 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00,
293 ],
294 [
295 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 ],
299 Ok(true),
300 ),
301 (
302 [
305 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x01,
307 ],
308 [
309 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 ],
313 Ok(true),
314 ),
315 (
316 [
319 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
320 0xFF, 0xFF, 0xFF,
321 ],
322 [
323 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 ],
327 Ok(true),
328 ),
329 (
330 [
333 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00,
335 ],
336 [
337 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 ],
341 Ok(false),
342 ),
343 (
344 [
347 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00,
349 ],
350 [
351 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 ],
355 Ok(false),
356 ),
357 ];
358 for (name, constraint, match_result) in names_and_constraints {
359 assert_eq!(
360 presented_id_matches_constraint(
361 untrusted::Input::from(&name),
362 untrusted::Input::from(&constraint),
363 ),
364 match_result
365 )
366 }
367
368 assert_eq!(
370 presented_id_matches_constraint(
371 untrusted::Input::from(&[
372 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
373 0x00, 0x00
374 ]),
375 untrusted::Input::from(&[
376 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
379 ]),
380 ),
381 Err(Error::BadDer),
382 );
383
384 assert_eq!(
386 presented_id_matches_constraint(
387 untrusted::Input::from(&[
388 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00
390 ]),
391 untrusted::Input::from(&[
392 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
395 ]),
396 ),
397 Err(Error::BadDer),
398 );
399
400 assert_eq!(
402 presented_id_matches_constraint(
403 untrusted::Input::from(&[
404 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x00, 0x00,
406 ]),
407 untrusted::Input::from(&[
408 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
409 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
410 0x00, 0x00, 0x00, 0x00, 0x00
411 ]),
412 ),
413 Err(Error::InvalidNetworkMaskConstraint),
414 );
415
416 assert_eq!(
418 presented_id_matches_constraint(
419 untrusted::Input::from(&[
420 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0x00, 0x00, 0x00,
422 ]),
423 untrusted::Input::from(&[
424 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
425 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
427 ]),
428 ),
429 Err(Error::InvalidNetworkMaskConstraint),
430 );
431
432 assert_eq!(
434 presented_id_matches_constraint(
435 untrusted::Input::from(&[
436 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
437 0x00, 0x00, 0x00,
438 ]),
439 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
440 ),
441 Ok(false),
442 );
443 }
444
445 #[test]
446 fn test_presented_id_matches_reference_id() {
447 assert!(!presented_id_matches_reference_id(
448 untrusted::Input::from(&[]),
449 untrusted::Input::from(&[]),
450 ));
451
452 assert!(!presented_id_matches_reference_id(
453 untrusted::Input::from(&[0x01]),
454 untrusted::Input::from(&[])
455 ));
456
457 assert!(!presented_id_matches_reference_id(
458 untrusted::Input::from(&[]),
459 untrusted::Input::from(&[0x01])
460 ));
461
462 assert!(presented_id_matches_reference_id(
463 untrusted::Input::from(&[1, 2, 3, 4]),
464 untrusted::Input::from(&[1, 2, 3, 4])
465 ));
466
467 assert!(!presented_id_matches_reference_id(
468 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
469 untrusted::Input::from(&[1, 2, 3, 4])
470 ));
471
472 assert!(!presented_id_matches_reference_id(
473 untrusted::Input::from(&[1, 2, 3, 4]),
474 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
475 ));
476
477 assert!(presented_id_matches_reference_id(
478 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
479 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
480 ));
481 }
482
483 #[test]
484 fn presented_id_matches_constraint_rejects_incorrect_length_arguments() {
485 assert_eq!(
487 presented_id_matches_constraint(
488 untrusted::Input::from(b"\x00\x00\x00"),
489 untrusted::Input::from(b"")
490 ),
491 Err(Error::BadDer)
492 );
493 assert_eq!(
494 presented_id_matches_constraint(
495 untrusted::Input::from(b"\x00\x00\x00\x00\x00"),
496 untrusted::Input::from(b"")
497 ),
498 Err(Error::BadDer)
499 );
500
501 assert_eq!(
502 presented_id_matches_constraint(
503 untrusted::Input::from(
504 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
505 ),
506 untrusted::Input::from(b"")
507 ),
508 Err(Error::BadDer)
509 );
510 assert_eq!(
511 presented_id_matches_constraint(
512 untrusted::Input::from(
513 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
514 ),
515 untrusted::Input::from(b"")
516 ),
517 Err(Error::BadDer)
518 );
519
520 assert_eq!(
522 presented_id_matches_constraint(
523 untrusted::Input::from(b"\x00\x00\x00\x00"),
524 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff")
525 ),
526 Err(Error::InvalidNetworkMaskConstraint)
527 );
528 assert_eq!(
529 presented_id_matches_constraint(
530 untrusted::Input::from(b"\x00\x00\x00\x00"),
531 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff\x00")
532 ),
533 Err(Error::InvalidNetworkMaskConstraint)
534 );
535 assert_eq!(
536 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
537 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
538 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
539 Err(Error::InvalidNetworkMaskConstraint)
540 );
541 assert_eq!(
542 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
543 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
544 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
545 Err(Error::InvalidNetworkMaskConstraint)
546 );
547
548 assert_eq!(
550 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00"),
551 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
552 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
553 Ok(false)
554 );
555 assert_eq!(
556 presented_id_matches_constraint(
557 untrusted::Input::from(
558 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
559 ),
560 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff")
561 ),
562 Ok(false)
563 );
564 }
565}
566
567#[cfg(all(test, feature = "alloc"))]
568mod alloc_tests {
569 use super::*;
570
571 const PRESENTED_MATCHES_CONSTRAINT: &[(&str, &str, &str, Result<bool, Error>)] = &[
573 ("2001:db8::", "8.8.8.8", "255.255.255.255", Ok(false)),
575 ("8.8.8.8", "2001:db8::", "ffff::", Ok(false)),
576 (
578 "8.8.8.8",
579 "8.8.8.8",
580 "255.255.255.1",
581 Err(Error::InvalidNetworkMaskConstraint),
582 ),
583 (
584 "8.8.8.8",
585 "8.8.8.8",
586 "255.255.0.255",
587 Err(Error::InvalidNetworkMaskConstraint),
588 ),
589 (
590 "8.8.8.8",
591 "8.8.8.8",
592 "255.0.255.255",
593 Err(Error::InvalidNetworkMaskConstraint),
594 ),
595 (
596 "8.8.8.8",
597 "8.8.8.8",
598 "0.255.255.255",
599 Err(Error::InvalidNetworkMaskConstraint),
600 ),
601 (
602 "8.8.8.8",
603 "8.8.8.8",
604 "1.255.255.255",
605 Err(Error::InvalidNetworkMaskConstraint),
606 ),
607 (
608 "8.8.8.8",
609 "8.8.8.8",
610 "128.128.128.128",
611 Err(Error::InvalidNetworkMaskConstraint),
612 ),
613 ("8.8.8.8", "8.8.8.8", "255.255.255.255", Ok(true)),
615 ("8.8.8.9", "8.8.8.8", "255.255.255.255", Ok(false)),
616 ("8.8.8.9", "8.8.8.8", "255.255.255.254", Ok(true)),
617 ("8.8.8.10", "8.8.8.8", "255.255.255.254", Ok(false)),
618 ("8.8.8.10", "8.8.8.8", "255.255.255.0", Ok(true)),
619 ("8.8.15.10", "8.8.8.8", "255.255.248.0", Ok(true)),
620 ("8.8.16.10", "8.8.8.8", "255.255.248.0", Ok(false)),
621 ("8.8.16.10", "8.8.8.8", "255.255.0.0", Ok(true)),
622 ("8.31.16.10", "8.8.8.8", "255.224.0.0", Ok(true)),
623 ("8.32.16.10", "8.8.8.8", "255.224.0.0", Ok(false)),
624 ("8.32.16.10", "8.8.8.8", "255.0.0.0", Ok(true)),
625 ("63.32.16.10", "8.8.8.8", "192.0.0.0", Ok(true)),
626 ("64.32.16.10", "8.8.8.8", "192.0.0.0", Ok(false)),
627 ("64.32.16.10", "8.8.8.8", "0.0.0.0", Ok(true)),
628 (
630 "2001:db8::",
631 "2001:db8::",
632 "fffe:ffff::",
633 Err(Error::InvalidNetworkMaskConstraint),
634 ),
635 (
636 "2001:db8::",
637 "2001:db8::",
638 "ffff:fdff::",
639 Err(Error::InvalidNetworkMaskConstraint),
640 ),
641 (
642 "2001:db8::",
643 "2001:db8::",
644 "ffff:feff::",
645 Err(Error::InvalidNetworkMaskConstraint),
646 ),
647 (
648 "2001:db8::",
649 "2001:db8::",
650 "ffff:fcff::",
651 Err(Error::InvalidNetworkMaskConstraint),
652 ),
653 (
654 "2001:db8::",
655 "2001:db8::",
656 "7fff:ffff::",
657 Err(Error::InvalidNetworkMaskConstraint),
658 ),
659 ("2001:db8::", "2001:db8::", "ffff:ffff::", Ok(true)),
661 ("2001:db9::", "2001:db8::", "ffff:ffff::", Ok(false)),
662 ("2001:db9::", "2001:db8::", "ffff:fffe::", Ok(true)),
663 ("2001:dba::", "2001:db8::", "ffff:fffe::", Ok(false)),
664 ("2001:dba::", "2001:db8::", "ffff:ff00::", Ok(true)),
665 ("2001:dca::", "2001:db8::", "ffff:fe00::", Ok(true)),
666 ("2001:fca::", "2001:db8::", "ffff:fe00::", Ok(false)),
667 ("2001:fca::", "2001:db8::", "ffff:0000::", Ok(true)),
668 ("2000:fca::", "2001:db8::", "fffe:0000::", Ok(true)),
669 ("2003:fca::", "2001:db8::", "fffe:0000::", Ok(false)),
670 ("2003:fca::", "2001:db8::", "ff00:0000::", Ok(true)),
671 ("1003:fca::", "2001:db8::", "e000:0000::", Ok(false)),
672 ("1003:fca::", "2001:db8::", "0000:0000::", Ok(true)),
673 ];
674
675 #[cfg(feature = "std")]
676 #[test]
677 fn presented_matches_constraint_test() {
678 use std::boxed::Box;
679 use std::net::IpAddr;
680
681 for (presented, constraint_address, constraint_mask, expected_result) in
682 PRESENTED_MATCHES_CONSTRAINT
683 {
684 let presented_bytes: Box<[u8]> = match presented.parse::<IpAddr>().unwrap() {
685 IpAddr::V4(p) => Box::new(p.octets()),
686 IpAddr::V6(p) => Box::new(p.octets()),
687 };
688 let ca_bytes: Box<[u8]> = match constraint_address.parse::<IpAddr>().unwrap() {
689 IpAddr::V4(ca) => Box::new(ca.octets()),
690 IpAddr::V6(ca) => Box::new(ca.octets()),
691 };
692 let cm_bytes: Box<[u8]> = match constraint_mask.parse::<IpAddr>().unwrap() {
693 IpAddr::V4(cm) => Box::new(cm.octets()),
694 IpAddr::V6(cm) => Box::new(cm.octets()),
695 };
696 let constraint_bytes = [ca_bytes, cm_bytes].concat();
697 let actual_result = presented_id_matches_constraint(
698 untrusted::Input::from(&presented_bytes),
699 untrusted::Input::from(&constraint_bytes),
700 );
701 assert_eq!(
702 &actual_result, expected_result,
703 "presented_id_matches_constraint(\"{:?}\", \"{:?}\")",
704 presented_bytes, constraint_bytes
705 );
706 }
707 }
708}