• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24
25if (!common.hasCrypto)
26  common.skip('missing crypto');
27
28const assert = require('assert');
29const util = require('util');
30
31const tls = require('tls');
32
33common.expectWarning('DeprecationWarning', [
34  ['The URI http://[a.b.a.com]/ found in cert.subjectaltname ' +
35  'is not a valid URI, and is supported in the tls module ' +
36  'solely for compatibility.',
37   'DEP0109'],
38]);
39
40const tests = [
41  // False-y values.
42  {
43    host: false,
44    cert: { subject: { CN: 'a.com' } },
45    error: 'Host: false. is not cert\'s CN: a.com'
46  },
47  {
48    host: null,
49    cert: { subject: { CN: 'a.com' } },
50    error: 'Host: null. is not cert\'s CN: a.com'
51  },
52  {
53    host: undefined,
54    cert: { subject: { CN: 'a.com' } },
55    error: 'Host: undefined. is not cert\'s CN: a.com'
56  },
57
58  // Basic CN handling
59  { host: 'a.com', cert: { subject: { CN: 'a.com' } } },
60  { host: 'a.com', cert: { subject: { CN: 'A.COM' } } },
61  {
62    host: 'a.com',
63    cert: { subject: { CN: 'b.com' } },
64    error: 'Host: a.com. is not cert\'s CN: b.com'
65  },
66  { host: 'a.com', cert: { subject: { CN: 'a.com.' } } },
67  {
68    host: 'a.com',
69    cert: { subject: { CN: '.a.com' } },
70    error: 'Host: a.com. is not cert\'s CN: .a.com'
71  },
72
73  // IP address in CN. Technically allowed but so rare that we reject
74  // it anyway. If we ever do start allowing them, we should take care
75  // to only allow public (non-internal, non-reserved) IP addresses,
76  // because that's what the spec mandates.
77  {
78    host: '8.8.8.8',
79    cert: { subject: { CN: '8.8.8.8' } },
80    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
81  },
82
83  // The spec suggests that a "DNS:" Subject Alternative Name containing an
84  // IP address is valid but it seems so suspect that we currently reject it.
85  {
86    host: '8.8.8.8',
87    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'DNS:8.8.8.8' },
88    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
89  },
90
91  // Likewise for "URI:" Subject Alternative Names.
92  // See also https://github.com/nodejs/node/issues/8108.
93  {
94    host: '8.8.8.8',
95    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'URI:http://8.8.8.8/' },
96    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
97  },
98
99  // An "IP Address:" Subject Alternative Name however is acceptable.
100  {
101    host: '8.8.8.8',
102    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'IP Address:8.8.8.8' }
103  },
104
105  // But not when it's a CIDR.
106  {
107    host: '8.8.8.8',
108    cert: {
109      subject: { CN: '8.8.8.8' },
110      subjectaltname: 'IP Address:8.8.8.0/24'
111    },
112    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
113  },
114
115  // Wildcards in CN
116  { host: 'b.a.com', cert: { subject: { CN: '*.a.com' } } },
117  {
118    host: 'ba.com',
119    cert: { subject: { CN: '*.a.com' } },
120    error: 'Host: ba.com. is not cert\'s CN: *.a.com'
121  },
122  {
123    host: '\n.b.com',
124    cert: { subject: { CN: '*n.b.com' } },
125    error: 'Host: \n.b.com. is not cert\'s CN: *n.b.com'
126  },
127  { host: 'b.a.com', cert: {
128    subjectaltname: 'DNS:omg.com',
129    subject: { CN: '*.a.com' } },
130    error: 'Host: b.a.com. is not in the cert\'s altnames: ' +
131           'DNS:omg.com'
132  },
133  {
134    host: 'b.a.com',
135    cert: { subject: { CN: 'b*b.a.com' } },
136    error: 'Host: b.a.com. is not cert\'s CN: b*b.a.com'
137  },
138
139  // Empty Cert
140  {
141    host: 'a.com',
142    cert: { },
143    error: 'Cert is empty'
144  },
145
146  // Empty Subject w/DNS name
147  {
148    host: 'a.com', cert: {
149      subjectaltname: 'DNS:a.com',
150    }
151  },
152
153  // Empty Subject w/URI name
154  {
155    host: 'a.b.a.com', cert: {
156      subjectaltname: 'URI:http://a.b.a.com/',
157    }
158  },
159
160  // Multiple CN fields
161  {
162    host: 'foo.com', cert: {
163      subject: { CN: ['foo.com', 'bar.com'] } // CN=foo.com; CN=bar.com;
164    }
165  },
166
167  // DNS names and CN
168  {
169    host: 'a.com', cert: {
170      subjectaltname: 'DNS:*',
171      subject: { CN: 'b.com' }
172    },
173    error: 'Host: a.com. is not in the cert\'s altnames: ' +
174           'DNS:*'
175  },
176  {
177    host: 'a.com', cert: {
178      subjectaltname: 'DNS:*.com',
179      subject: { CN: 'b.com' }
180    },
181    error: 'Host: a.com. is not in the cert\'s altnames: ' +
182           'DNS:*.com'
183  },
184  {
185    host: 'a.co.uk', cert: {
186      subjectaltname: 'DNS:*.co.uk',
187      subject: { CN: 'b.com' }
188    }
189  },
190  {
191    host: 'a.com', cert: {
192      subjectaltname: 'DNS:*.a.com',
193      subject: { CN: 'a.com' }
194    },
195    error: 'Host: a.com. is not in the cert\'s altnames: ' +
196           'DNS:*.a.com'
197  },
198  {
199    host: 'a.com', cert: {
200      subjectaltname: 'DNS:*.a.com',
201      subject: { CN: 'b.com' }
202    },
203    error: 'Host: a.com. is not in the cert\'s altnames: ' +
204           'DNS:*.a.com'
205  },
206  {
207    host: 'a.com', cert: {
208      subjectaltname: 'DNS:a.com',
209      subject: { CN: 'b.com' }
210    }
211  },
212  {
213    host: 'a.com', cert: {
214      subjectaltname: 'DNS:A.COM',
215      subject: { CN: 'b.com' }
216    }
217  },
218
219  // DNS names
220  {
221    host: 'a.com', cert: {
222      subjectaltname: 'DNS:*.a.com',
223      subject: {}
224    },
225    error: 'Host: a.com. is not in the cert\'s altnames: ' +
226           'DNS:*.a.com'
227  },
228  {
229    host: 'b.a.com', cert: {
230      subjectaltname: 'DNS:*.a.com',
231      subject: {}
232    }
233  },
234  {
235    host: 'c.b.a.com', cert: {
236      subjectaltname: 'DNS:*.a.com',
237      subject: {}
238    },
239    error: 'Host: c.b.a.com. is not in the cert\'s altnames: ' +
240           'DNS:*.a.com'
241  },
242  {
243    host: 'b.a.com', cert: {
244      subjectaltname: 'DNS:*b.a.com',
245      subject: {}
246    }
247  },
248  {
249    host: 'a-cb.a.com', cert: {
250      subjectaltname: 'DNS:*b.a.com',
251      subject: {}
252    }
253  },
254  {
255    host: 'a.b.a.com', cert: {
256      subjectaltname: 'DNS:*b.a.com',
257      subject: {}
258    },
259    error: 'Host: a.b.a.com. is not in the cert\'s altnames: ' +
260           'DNS:*b.a.com'
261  },
262  // Multiple DNS names
263  {
264    host: 'a.b.a.com', cert: {
265      subjectaltname: 'DNS:*b.a.com, DNS:a.b.a.com',
266      subject: {}
267    }
268  },
269  // URI names
270  {
271    host: 'a.b.a.com', cert: {
272      subjectaltname: 'URI:http://a.b.a.com/',
273      subject: {}
274    }
275  },
276  {
277    host: 'a.b.a.com', cert: {
278      subjectaltname: 'URI:http://*.b.a.com/',
279      subject: {}
280    },
281    error: 'Host: a.b.a.com. is not in the cert\'s altnames: ' +
282           'URI:http://*.b.a.com/'
283  },
284  // Invalid URI
285  {
286    host: 'a.b.a.com', cert: {
287      subjectaltname: 'URI:http://[a.b.a.com]/',
288      subject: {}
289    }
290  },
291  // IP addresses
292  {
293    host: 'a.b.a.com', cert: {
294      subjectaltname: 'IP Address:127.0.0.1',
295      subject: {}
296    },
297    error: 'Host: a.b.a.com. is not in the cert\'s altnames: ' +
298           'IP Address:127.0.0.1'
299  },
300  {
301    host: '127.0.0.1', cert: {
302      subjectaltname: 'IP Address:127.0.0.1',
303      subject: {}
304    }
305  },
306  {
307    host: '127.0.0.2', cert: {
308      subjectaltname: 'IP Address:127.0.0.1',
309      subject: {}
310    },
311    error: 'IP: 127.0.0.2 is not in the cert\'s list: ' +
312           '127.0.0.1'
313  },
314  {
315    host: '127.0.0.1', cert: {
316      subjectaltname: 'DNS:a.com',
317      subject: {}
318    },
319    error: 'IP: 127.0.0.1 is not in the cert\'s list: '
320  },
321  {
322    host: 'localhost', cert: {
323      subjectaltname: 'DNS:a.com',
324      subject: { CN: 'localhost' }
325    },
326    error: 'Host: localhost. is not in the cert\'s altnames: ' +
327           'DNS:a.com'
328  },
329  // IDNA
330  {
331    host: 'xn--bcher-kva.example.com',
332    cert: { subject: { CN: '*.example.com' } },
333  },
334  // RFC 6125, section 6.4.3: "[...] the client SHOULD NOT attempt to match
335  // a presented identifier where the wildcard character is embedded within
336  // an A-label [...]"
337  {
338    host: 'xn--bcher-kva.example.com',
339    cert: { subject: { CN: 'xn--*.example.com' } },
340    error: 'Host: xn--bcher-kva.example.com. is not cert\'s CN: ' +
341            'xn--*.example.com',
342  },
343];
344
345tests.forEach(function(test, i) {
346  const err = tls.checkServerIdentity(test.host, test.cert);
347  assert.strictEqual(err && err.reason,
348                     test.error,
349                     `Test# ${i} failed: ${util.inspect(test)} \n` +
350                     `${test.error} != ${(err && err.reason)}`);
351});
352