blob: b3a3adc429d71f15b11e97b156d80fb77df5db6a [file] [log] [blame]
// Copyright 2014-2017 Brian Smith.
// (name, is_valid)
static DNS_NAME_VALIDITY: &[(&[u8], bool)] = &[
(b"a", true),
(b"a.b", true),
(b"a.b.c", true),
(b"a.b.c.d", true),
// Hyphens, one component.
(b"-", false),
(b"-a", false),
(b"a-", false),
(b"a-b", true),
// Hyphens, last component.
(b"a.-", false),
(b"a.-a", false),
(b"a.a-", false),
(b"a.a-b", true),
// Hyphens, not last component.
(b"-.a", false),
(b"-a.a", false),
(b"a-.a", false),
(b"a-b.a", true),
// Underscores, one component.
(b"_", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
(b"_a", true), // TODO: Perhaps this should be rejected for '_' being 1st?
(b"a_", true),
(b"a_b", true),
// Underscores, last component.
(b"a._", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
(b"a._a", true), // TODO: Perhaps this should be rejected for '_' being 1st?
(b"a.a_", true),
(b"a.a_b", true),
// Underscores, not last component.
(b"_.a", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
(b"_a.a", true),
(b"a_.a", true),
(b"a_b.a", true),
// empty labels
(b"", false),
(b".", false),
(b"a", true),
(b".a", false),
(b".a.b", false),
(b"..a", false),
(b"a..b", false),
(b"a...b", false),
(b"a..b.c", false),
(b"a.b..c", false),
(b".a.b.c.", false),
// absolute names
(b"a.", true),
(b"a.b.", true),
(b"a.b.c.", true),
// absolute names with empty label at end
(b"a..", false),
(b"a.b..", false),
(b"a.b.c..", false),
(b"a...", false),
// Punycode
(b"xn--", false),
(b"xn--.", false),
(b"xn--.a", false),
(b"a.xn--", false),
(b"a.xn--.", false),
(b"a.xn--.b", false),
(b"a.xn--.b", false),
(b"a.xn--\0.b", false),
(b"a.xn--a.b", true),
(b"xn--a", true),
(b"a.xn--a", true),
(b"a.xn--a.a", true),
(b"\xc4\x95.com", false), // UTF-8 ĕ
(b"xn--jea.com", true), // punycode ĕ
(b"xn--\xc4\x95.com", false), // UTF-8 ĕ, malformed punycode + UTF-8 mashup
// Surprising punycode
(b"xn--google.com", true), // 䕮䕵䕶䕱.com
(b"xn--citibank.com", true), // 岍岊岊岅岉岎.com
(b"xn--cnn.com", true), // 䁾.com
(b"a.xn--cnn", true), // a.䁾
(b"a.xn--cnn.com", true), // a.䁾.com
(b"1.2.3.4", false), // IPv4 address
(b"1::2", false), // IPV6 address
// whitespace not allowed anywhere.
(b" ", false),
(b" a", false),
(b"a ", false),
(b"a b", false),
(b"a.b 1", false),
(b"a\t", false),
// Nulls not allowed
(b"\0", false),
(b"a\0", false),
(b"example.org\0.example.com", false), // Hi Moxie!
(b"\0a", false),
(b"xn--\0", false),
// Allowed character set
(b"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", true),
(b"A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z", true),
(b"0.1.2.3.4.5.6.7.8.9.a", true), // "a" needed to avoid numeric last label
(b"a-b", true), // hyphen (a label cannot start or end with a hyphen)
// An invalid character in various positions
(b"!", false),
(b"!a", false),
(b"a!", false),
(b"a!b", false),
(b"a.!", false),
(b"a.a!", false),
(b"a.!a", false),
(b"a.a!a", false),
(b"a.!a.a", false),
(b"a.a!.a", false),
(b"a.a!a.a", false),
// Various other invalid characters
(b"a!", false),
(b"a@", false),
(b"a#", false),
(b"a$", false),
(b"a%", false),
(b"a^", false),
(b"a&", false),
(b"a*", false),
(b"a(", false),
(b"a)", false),
// last label can't be fully numeric
(b"1", false),
(b"a.1", false),
// other labels can be fully numeric
(b"1.a", true),
(b"1.2.a", true),
(b"1.2.3.a", true),
// last label can be *partly* numeric
(b"1a", true),
(b"1.1a", true),
(b"1-1", true),
(b"a.1-1", true),
(b"a.1-a", true),
// labels cannot start with a hyphen
(b"-", false),
(b"-1", false),
// labels cannot end with a hyphen
(b"1-", false),
(b"1-.a", false),
(b"a-", false),
(b"a-.a", false),
(b"a.1-.a", false),
(b"a.a-.a", false),
// labels can contain a hyphen in the middle
(b"a-b", true),
(b"1-2", true),
(b"a.a-1", true),
// multiple consecutive hyphens allowed
(b"a--1", true),
(b"1---a", true),
(b"a-----------------b", true),
// Wildcard specifications are not valid reference names.
(b"*.a", false),
(b"a*", false),
(b"a*.", false),
(b"a*.a", false),
(b"a*.a.", false),
(b"*.a.b", false),
(b"*.a.b.", false),
(b"a*.b.c", false),
(b"*.a.b.c", false),
(b"a*.b.c.d", false),
// Multiple wildcards.
(b"a**.b.c", false),
(b"a*b*.c.d", false),
(b"a*.b*.c", false),
// Wildcards not in the first label.
(b"a.*", false),
(b"a.*.b", false),
(b"a.b.*", false),
(b"a.b*.c", false),
(b"*.b*.c", false),
(b".*.a.b", false),
(b".a*.b.c", false),
// Wildcards not at the end of the first label.
(b"*a.b.c", false),
(b"a*b.c.d", false),
// Wildcards and IDNA prefix.
(b"x*.a.b", false),
(b"xn*.a.b", false),
(b"xn-*.a.b", false),
(b"xn--*.a.b", false),
(b"xn--w*.a.b", false),
// Redacted labels from RFC6962bis draft 4
// https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-04#section-3.2.2
(b"(PRIVATE).foo", false),
// maximum label length is 63 characters
(b"123456789012345678901234567890123456789012345678901234567890abc", true),
(b"123456789012345678901234567890123456789012345678901234567890abcd", false),
// maximum total length is 253 characters
(b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678a",
true),
(b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.1234567890123456789012345678901234567890123456789a",
false),
];
// (IP address, is valid DNS name). The comments here refer to the validity of
// the string as an IP address, not as a DNS name validity.
static IP_ADDRESS_DNS_VALIDITY: &[(&[u8], bool)] = &[
(b"", false),
(b"1", false),
(b"1.2", false),
(b"1.2.3", false),
(b"1.2.3.4", false),
(b"1.2.3.4.5", false),
(b"1.2.3.4a", true), // a DNS name!
(b"a.2.3.4", false), // not even a DNS name!
(b"1::2", false), // IPv6 address
// Whitespace not allowed
(b" 1.2.3.4", false),
(b"1.2.3.4 ", false),
(b"1 .2.3.4", false),
(b"\n1.2.3.4", false),
(b"1.2.3.4\n", false),
// Nulls not allowed
(b"\0", false),
(b"\01.2.3.4", false),
(b"1.2.3.4\0", false),
(b"1.2.3.4\0.5", false),
// Range
(b"0.0.0.0", false),
(b"255.255.255.255", false),
(b"256.0.0.0", false),
(b"0.256.0.0", false),
(b"0.0.256.0", false),
(b"0.0.0.256", false),
(b"999.0.0.0", false),
(b"9999999999999999999.0.0.0", false),
// All digits allowed
(b"0.1.2.3", false),
(b"4.5.6.7", false),
(b"8.9.0.1", false),
// Leading zeros not allowed
(b"01.2.3.4", false),
(b"001.2.3.4", false),
(b"00000000001.2.3.4", false),
(b"010.2.3.4", false),
(b"1.02.3.4", false),
(b"1.2.03.4", false),
(b"1.2.3.04", false),
// Empty components
(b".2.3.4", false),
(b"1..3.4", false),
(b"1.2..4", false),
(b"1.2.3.", false),
// Too many components
(b"1.2.3.4.5", false),
(b"1.2.3.4.5.6", false),
(b"0.1.2.3.4", false),
(b"1.2.3.4.0", false),
// Leading/trailing dot
(b".1.2.3.4", false),
(b"1.2.3.4.", false),
// Other common forms of IPv4 address
// http://en.wikipedia.org/wiki/IPv4#Address_representations
(b"192.0.2.235", false), // dotted decimal (control value)
(b"0xC0.0x00.0x02.0xEB", true), // dotted hex - actually a DNS name!
(b"0301.0000.0002.0353", false), // dotted octal
(b"0xC00002EB", true), // non-dotted hex, actually a DNS name!
(b"3221226219", false), // non-dotted decimal
(b"030000001353", false), // non-dotted octal
(b"192.0.0002.0xEB", true), // mixed, actually a DNS name!
(b"1234", false),
(b"1234:5678", false),
(b"1234:5678:9abc", false),
(b"1234:5678:9abc:def0", false),
(b"1234:5678:9abc:def0:1234:", false),
(b"1234:5678:9abc:def0:1234:5678:", false),
(b"1234:5678:9abc:def0:1234:5678:9abc:", false),
(b"1234:5678:9abc:def0:1234:5678:9abc:def0", false),
(b"1234:5678:9abc:def0:1234:5678:9abc:def0:", false),
(b":1234:5678:9abc:def0:1234:5678:9abc:def0", false),
(b"1234:5678:9abc:def0:1234:5678:9abc:def0:0000", false),
// Valid contractions
(b"::1", false),
(b"::1234", false),
(b"1234::", false),
(b"1234::5678", false),
(b"1234:5678::abcd", false),
(b"1234:5678:9abc:def0:1234:5678:9abc::", false),
// Contraction in full IPv6 addresses not allowed
(b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false), // start
(b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false), // end
(b"1234:5678::9abc:def0:1234:5678:9abc:def0", false), // interior
// Multiple contractions not allowed
(b"::1::", false),
(b"::1::2", false),
(b"1::2::", false),
// Colon madness!
(b":", false),
(b"::", false),
(b":::", false),
(b"::::", false),
(b":::1", false),
(b"::::1", false),
(b"1:::2", false),
(b"1::::2", false),
(b"1:2:::", false),
(b"1:2::::", false),
(b"::1234:", false),
(b":1234::", false),
(b"01234::", false), // too many digits, even if zero
(b"12345678::", false), // too many digits or missing colon
// uppercase
(b"ABCD:EFAB::", false),
// miXeD CAse
(b"aBcd:eFAb::", false),
// IPv4-style
(b"::2.3.4.5", false),
(b"1234::2.3.4.5", false),
(b"::abcd:2.3.4.5", false),
(b"1234:5678:9abc:def0:1234:5678:252.253.254.255", false),
(b"1234:5678:9abc:def0:1234::252.253.254.255", false),
(b"1234::252.253.254", false),
(b"::252.253.254", false),
(b"::252.253.254.300", false),
(b"1234::252.253.254.255:", false),
(b"1234::252.253.254.255:5678", false),
// Contractions that don't contract
(b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false),
(b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false),
(b"1234:5678:9abc:def0::1234:5678:9abc:def0", false),
(b"1234:5678:9abc:def0:1234:5678::252.253.254.255", false),
// With and without leading zeros
(b"::123", false),
(b"::0123", false),
(b"::012", false),
(b"::0012", false),
(b"::01", false),
(b"::001", false),
(b"::0001", false),
(b"::0", false),
(b"::00", false),
(b"::000", false),
(b"::0000", false),
(b"::01234", false),
(b"::00123", false),
(b"::000123", false),
// Trailing zero
(b"::12340", false),
// Whitespace
(b" 1234:5678:9abc:def0:1234:5678:9abc:def0", false),
(b"\t1234:5678:9abc:def0:1234:5678:9abc:def0", false),
(b"\t1234:5678:9abc:def0:1234:5678:9abc:def0\n", false),
(b"1234 :5678:9abc:def0:1234:5678:9abc:def0", false),
(b"1234: 5678:9abc:def0:1234:5678:9abc:def0", false),
(b":: 2.3.4.5", false),
(b"1234::252.253.254.255 ", false),
(b"1234::252.253.254.255\n", false),
(b"1234::252.253. 254.255", false),
// Nulls
(b"\0", false),
(b"::1\0:2", false),
(b"::1\0", false),
(b"::1.2.3.4\0", false),
(b"::1.2\02.3.4", false),
];
#[test]
fn dns_name_ref_try_from_ascii_test() {
for &(s, is_valid) in DNS_NAME_VALIDITY
.iter()
.chain(IP_ADDRESS_DNS_VALIDITY.iter())
{
assert_eq!(
webpki::DnsNameRef::try_from_ascii(s).is_ok(),
is_valid,
"DnsNameRef::try_from_ascii_str failed for \"{:?}\"",
s
);
}
}