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