1 // Copyright 2014-2017 Brian Smith.
2 
3 // (name, is_valid)
4 static DNS_NAME_VALIDITY: &[(&[u8], bool)] = &[
5     (b"a", true),
6     (b"a.b", true),
7     (b"a.b.c", true),
8     (b"a.b.c.d", true),
9 
10     // Hyphens, one component.
11     (b"-", false),
12     (b"-a", false),
13     (b"a-", false),
14     (b"a-b", true),
15 
16     // Hyphens, last component.
17     (b"a.-", false),
18     (b"a.-a", false),
19     (b"a.a-", false),
20     (b"a.a-b", true),
21 
22     // Hyphens, not last component.
23     (b"-.a", false),
24     (b"-a.a", false),
25     (b"a-.a", false),
26     (b"a-b.a", true),
27 
28     // Underscores, one component.
29     (b"_", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
30     (b"_a", true), // TODO: Perhaps this should be rejected for '_' being 1st?
31     (b"a_", true),
32     (b"a_b", true),
33 
34     // Underscores, last component.
35     (b"a._", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
36     (b"a._a", true), // TODO: Perhaps this should be rejected for '_' being 1st?
37     (b"a.a_", true),
38     (b"a.a_b", true),
39 
40     // Underscores, not last component.
41     (b"_.a", true), // TODO: Perhaps this should be rejected for '_' being sole character?.
42     (b"_a.a", true),
43     (b"a_.a", true),
44     (b"a_b.a", true),
45 
46     // empty labels
47     (b"", false),
48     (b".", false),
49     (b"a", true),
50     (b".a", false),
51     (b".a.b", false),
52     (b"..a", false),
53     (b"a..b", false),
54     (b"a...b", false),
55     (b"a..b.c", false),
56     (b"a.b..c", false),
57     (b".a.b.c.", false),
58 
59     // absolute names
60     (b"a.", true),
61     (b"a.b.", true),
62     (b"a.b.c.", true),
63 
64     // absolute names with empty label at end
65     (b"a..", false),
66     (b"a.b..", false),
67     (b"a.b.c..", false),
68     (b"a...", false),
69 
70     // Punycode
71     (b"xn--", false),
72     (b"xn--.", false),
73     (b"xn--.a", false),
74     (b"a.xn--", false),
75     (b"a.xn--.", false),
76     (b"a.xn--.b", false),
77     (b"a.xn--.b", false),
78     (b"a.xn--\0.b", false),
79     (b"a.xn--a.b", true),
80     (b"xn--a", true),
81     (b"a.xn--a", true),
82     (b"a.xn--a.a", true),
83     (b"\xc4\x95.com", false), // UTF-8 ĕ
84     (b"xn--jea.com", true), // punycode ĕ
85     (b"xn--\xc4\x95.com", false), // UTF-8 ĕ, malformed punycode + UTF-8 mashup
86 
87     // Surprising punycode
88     (b"xn--google.com", true), // 䕮䕵䕶䕱.com
89     (b"xn--citibank.com", true), // 岍岊岊岅岉岎.com
90     (b"xn--cnn.com", true), // 䁾.com
91     (b"a.xn--cnn", true), // a.䁾
92     (b"a.xn--cnn.com", true), // a.䁾.com
93 
94     (b"1.2.3.4", false), // IPv4 address
95     (b"1::2", false), // IPV6 address
96 
97     // whitespace not allowed anywhere.
98     (b" ", false),
99     (b" a", false),
100     (b"a ", false),
101     (b"a b", false),
102     (b"a.b 1", false),
103     (b"a\t", false),
104 
105     // Nulls not allowed
106     (b"\0", false),
107     (b"a\0", false),
108     (b"example.org\0.example.com", false), // Hi Moxie!
109     (b"\0a", false),
110     (b"xn--\0", false),
111 
112     // Allowed character set
113     (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),
114     (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),
115     (b"0.1.2.3.4.5.6.7.8.9.a", true), // "a" needed to avoid numeric last label
116     (b"a-b", true), // hyphen (a label cannot start or end with a hyphen)
117 
118     // An invalid character in various positions
119     (b"!", false),
120     (b"!a", false),
121     (b"a!", false),
122     (b"a!b", false),
123     (b"a.!", false),
124     (b"a.a!", false),
125     (b"a.!a", false),
126     (b"a.a!a", false),
127     (b"a.!a.a", false),
128     (b"a.a!.a", false),
129     (b"a.a!a.a", false),
130 
131     // Various other invalid characters
132     (b"a!", false),
133     (b"a@", false),
134     (b"a#", false),
135     (b"a$", false),
136     (b"a%", false),
137     (b"a^", false),
138     (b"a&", false),
139     (b"a*", false),
140     (b"a(", false),
141     (b"a)", false),
142 
143     // last label can't be fully numeric
144     (b"1", false),
145     (b"a.1", false),
146 
147     // other labels can be fully numeric
148     (b"1.a", true),
149     (b"1.2.a", true),
150     (b"1.2.3.a", true),
151 
152     // last label can be *partly* numeric
153     (b"1a", true),
154     (b"1.1a", true),
155     (b"1-1", true),
156     (b"a.1-1", true),
157     (b"a.1-a", true),
158 
159     // labels cannot start with a hyphen
160     (b"-", false),
161     (b"-1", false),
162 
163     // labels cannot end with a hyphen
164     (b"1-", false),
165     (b"1-.a", false),
166     (b"a-", false),
167     (b"a-.a", false),
168     (b"a.1-.a", false),
169     (b"a.a-.a", false),
170 
171     // labels can contain a hyphen in the middle
172     (b"a-b", true),
173     (b"1-2", true),
174     (b"a.a-1", true),
175 
176     // multiple consecutive hyphens allowed
177     (b"a--1", true),
178     (b"1---a", true),
179     (b"a-----------------b", true),
180 
181     // Wildcard specifications are not valid reference names.
182     (b"*.a", false),
183     (b"a*", false),
184     (b"a*.", false),
185     (b"a*.a", false),
186     (b"a*.a.", false),
187     (b"*.a.b", false),
188     (b"*.a.b.", false),
189     (b"a*.b.c", false),
190     (b"*.a.b.c", false),
191     (b"a*.b.c.d", false),
192 
193     // Multiple wildcards.
194     (b"a**.b.c", false),
195     (b"a*b*.c.d", false),
196     (b"a*.b*.c", false),
197 
198     // Wildcards not in the first label.
199     (b"a.*", false),
200     (b"a.*.b", false),
201     (b"a.b.*", false),
202     (b"a.b*.c", false),
203     (b"*.b*.c", false),
204     (b".*.a.b", false),
205     (b".a*.b.c", false),
206 
207     // Wildcards not at the end of the first label.
208     (b"*a.b.c", false),
209     (b"a*b.c.d", false),
210 
211     // Wildcards and IDNA prefix.
212     (b"x*.a.b", false),
213     (b"xn*.a.b", false),
214     (b"xn-*.a.b", false),
215     (b"xn--*.a.b", false),
216     (b"xn--w*.a.b", false),
217 
218     // Redacted labels from RFC6962bis draft 4
219     // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-04#section-3.2.2
220     (b"(PRIVATE).foo", false),
221 
222     // maximum label length is 63 characters
223     (b"123456789012345678901234567890123456789012345678901234567890abc", true),
224     (b"123456789012345678901234567890123456789012345678901234567890abcd", false),
225 
226     // maximum total length is 253 characters
227     (b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678a",
228      true),
229     (b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.1234567890123456789012345678901234567890123456789a",
230      false),
231 ];
232 
233 // (IP address, is valid DNS name). The comments here refer to the validity of
234 // the string as an IP address, not as a DNS name validity.
235 static IP_ADDRESS_DNS_VALIDITY: &[(&[u8], bool)] = &[
236     (b"", false),
237     (b"1", false),
238     (b"1.2", false),
239     (b"1.2.3", false),
240     (b"1.2.3.4", false),
241     (b"1.2.3.4.5", false),
242     (b"1.2.3.4a", true), // a DNS name!
243     (b"a.2.3.4", false), // not even a DNS name!
244     (b"1::2", false),    // IPv6 address
245     // Whitespace not allowed
246     (b" 1.2.3.4", false),
247     (b"1.2.3.4 ", false),
248     (b"1 .2.3.4", false),
249     (b"\n1.2.3.4", false),
250     (b"1.2.3.4\n", false),
251     // Nulls not allowed
252     (b"\0", false),
253     (b"\x001.2.3.4", false),
254     (b"1.2.3.4\0", false),
255     (b"1.2.3.4\0.5", false),
256     // Range
257     (b"0.0.0.0", false),
258     (b"255.255.255.255", false),
259     (b"256.0.0.0", false),
260     (b"0.256.0.0", false),
261     (b"0.0.256.0", false),
262     (b"0.0.0.256", false),
263     (b"999.0.0.0", false),
264     (b"9999999999999999999.0.0.0", false),
265     // All digits allowed
266     (b"0.1.2.3", false),
267     (b"4.5.6.7", false),
268     (b"8.9.0.1", false),
269     // Leading zeros not allowed
270     (b"01.2.3.4", false),
271     (b"001.2.3.4", false),
272     (b"00000000001.2.3.4", false),
273     (b"010.2.3.4", false),
274     (b"1.02.3.4", false),
275     (b"1.2.03.4", false),
276     (b"1.2.3.04", false),
277     // Empty components
278     (b".2.3.4", false),
279     (b"1..3.4", false),
280     (b"1.2..4", false),
281     (b"1.2.3.", false),
282     // Too many components
283     (b"1.2.3.4.5", false),
284     (b"1.2.3.4.5.6", false),
285     (b"0.1.2.3.4", false),
286     (b"1.2.3.4.0", false),
287     // Leading/trailing dot
288     (b".1.2.3.4", false),
289     (b"1.2.3.4.", false),
290     // Other common forms of IPv4 address
291     // http://en.wikipedia.org/wiki/IPv4#Address_representations
292     (b"192.0.2.235", false),         // dotted decimal (control value)
293     (b"0xC0.0x00.0x02.0xEB", true),  // dotted hex - actually a DNS name!
294     (b"0301.0000.0002.0353", false), // dotted octal
295     (b"0xC00002EB", true),           // non-dotted hex, actually a DNS name!
296     (b"3221226219", false),          // non-dotted decimal
297     (b"030000001353", false),        // non-dotted octal
298     (b"192.0.0002.0xEB", true),      // mixed, actually a DNS name!
299     (b"1234", false),
300     (b"1234:5678", false),
301     (b"1234:5678:9abc", false),
302     (b"1234:5678:9abc:def0", false),
303     (b"1234:5678:9abc:def0:1234:", false),
304     (b"1234:5678:9abc:def0:1234:5678:", false),
305     (b"1234:5678:9abc:def0:1234:5678:9abc:", false),
306     (b"1234:5678:9abc:def0:1234:5678:9abc:def0", false),
307     (b"1234:5678:9abc:def0:1234:5678:9abc:def0:", false),
308     (b":1234:5678:9abc:def0:1234:5678:9abc:def0", false),
309     (b"1234:5678:9abc:def0:1234:5678:9abc:def0:0000", false),
310     // Valid contractions
311     (b"::1", false),
312     (b"::1234", false),
313     (b"1234::", false),
314     (b"1234::5678", false),
315     (b"1234:5678::abcd", false),
316     (b"1234:5678:9abc:def0:1234:5678:9abc::", false),
317     // Contraction in full IPv6 addresses not allowed
318     (b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false), // start
319     (b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false), // end
320     (b"1234:5678::9abc:def0:1234:5678:9abc:def0", false),  // interior
321     // Multiple contractions not allowed
322     (b"::1::", false),
323     (b"::1::2", false),
324     (b"1::2::", false),
325     // Colon madness!
326     (b":", false),
327     (b"::", false),
328     (b":::", false),
329     (b"::::", false),
330     (b":::1", false),
331     (b"::::1", false),
332     (b"1:::2", false),
333     (b"1::::2", false),
334     (b"1:2:::", false),
335     (b"1:2::::", false),
336     (b"::1234:", false),
337     (b":1234::", false),
338     (b"01234::", false),    // too many digits, even if zero
339     (b"12345678::", false), // too many digits or missing colon
340     // uppercase
341     (b"ABCD:EFAB::", false),
342     // miXeD CAse
343     (b"aBcd:eFAb::", false),
344     // IPv4-style
345     (b"::2.3.4.5", false),
346     (b"1234::2.3.4.5", false),
347     (b"::abcd:2.3.4.5", false),
348     (b"1234:5678:9abc:def0:1234:5678:252.253.254.255", false),
349     (b"1234:5678:9abc:def0:1234::252.253.254.255", false),
350     (b"1234::252.253.254", false),
351     (b"::252.253.254", false),
352     (b"::252.253.254.300", false),
353     (b"1234::252.253.254.255:", false),
354     (b"1234::252.253.254.255:5678", false),
355     // Contractions that don't contract
356     (b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false),
357     (b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false),
358     (b"1234:5678:9abc:def0::1234:5678:9abc:def0", false),
359     (b"1234:5678:9abc:def0:1234:5678::252.253.254.255", false),
360     // With and without leading zeros
361     (b"::123", false),
362     (b"::0123", false),
363     (b"::012", false),
364     (b"::0012", false),
365     (b"::01", false),
366     (b"::001", false),
367     (b"::0001", false),
368     (b"::0", false),
369     (b"::00", false),
370     (b"::000", false),
371     (b"::0000", false),
372     (b"::01234", false),
373     (b"::00123", false),
374     (b"::000123", false),
375     // Trailing zero
376     (b"::12340", false),
377     // Whitespace
378     (b" 1234:5678:9abc:def0:1234:5678:9abc:def0", false),
379     (b"\t1234:5678:9abc:def0:1234:5678:9abc:def0", false),
380     (b"\t1234:5678:9abc:def0:1234:5678:9abc:def0\n", false),
381     (b"1234 :5678:9abc:def0:1234:5678:9abc:def0", false),
382     (b"1234: 5678:9abc:def0:1234:5678:9abc:def0", false),
383     (b":: 2.3.4.5", false),
384     (b"1234::252.253.254.255 ", false),
385     (b"1234::252.253.254.255\n", false),
386     (b"1234::252.253. 254.255", false),
387     // Nulls
388     (b"\0", false),
389     (b"::1\0:2", false),
390     (b"::1\0", false),
391     (b"::1.2.3.4\0", false),
392     (b"::1.2\x002.3.4", false),
393 ];
394 
395 #[test]
dns_name_ref_try_from_ascii_test()396 fn dns_name_ref_try_from_ascii_test() {
397     for &(s, is_valid) in DNS_NAME_VALIDITY
398         .iter()
399         .chain(IP_ADDRESS_DNS_VALIDITY.iter())
400     {
401         assert_eq!(
402             webpki::DnsNameRef::try_from_ascii(s).is_ok(),
403             is_valid,
404             "DnsNameRef::try_from_ascii_str failed for \"{:?}\"",
405             s
406         );
407     }
408 }
409