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