• 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
33const tests = [
34  // False-y values.
35  {
36    host: false,
37    cert: { subject: { CN: 'a.com' } },
38    error: 'Host: false. is not cert\'s CN: a.com'
39  },
40  {
41    host: null,
42    cert: { subject: { CN: 'a.com' } },
43    error: 'Host: null. is not cert\'s CN: a.com'
44  },
45  {
46    host: undefined,
47    cert: { subject: { CN: 'a.com' } },
48    error: 'Host: undefined. is not cert\'s CN: a.com'
49  },
50
51  // Basic CN handling
52  { host: 'a.com', cert: { subject: { CN: 'a.com' } } },
53  { host: 'a.com', cert: { subject: { CN: 'A.COM' } } },
54  {
55    host: 'a.com',
56    cert: { subject: { CN: 'b.com' } },
57    error: 'Host: a.com. is not cert\'s CN: b.com'
58  },
59  { host: 'a.com', cert: { subject: { CN: 'a.com.' } } },
60  {
61    host: 'a.com',
62    cert: { subject: { CN: '.a.com' } },
63    error: 'Host: a.com. is not cert\'s CN: .a.com'
64  },
65
66  // IP address in CN. Technically allowed but so rare that we reject
67  // it anyway. If we ever do start allowing them, we should take care
68  // to only allow public (non-internal, non-reserved) IP addresses,
69  // because that's what the spec mandates.
70  {
71    host: '8.8.8.8',
72    cert: { subject: { CN: '8.8.8.8' } },
73    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
74  },
75
76  // The spec suggests that a "DNS:" Subject Alternative Name containing an
77  // IP address is valid but it seems so suspect that we currently reject it.
78  {
79    host: '8.8.8.8',
80    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'DNS:8.8.8.8' },
81    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
82  },
83
84  // Likewise for "URI:" Subject Alternative Names.
85  // See also https://github.com/nodejs/node/issues/8108.
86  {
87    host: '8.8.8.8',
88    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'URI:http://8.8.8.8/' },
89    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
90  },
91
92  // An "IP Address:" Subject Alternative Name however is acceptable.
93  {
94    host: '8.8.8.8',
95    cert: { subject: { CN: '8.8.8.8' }, subjectaltname: 'IP Address:8.8.8.8' }
96  },
97
98  // But not when it's a CIDR.
99  {
100    host: '8.8.8.8',
101    cert: {
102      subject: { CN: '8.8.8.8' },
103      subjectaltname: 'IP Address:8.8.8.0/24'
104    },
105    error: 'IP: 8.8.8.8 is not in the cert\'s list: '
106  },
107
108  // Wildcards in CN
109  { host: 'b.a.com', cert: { subject: { CN: '*.a.com' } } },
110  {
111    host: 'ba.com',
112    cert: { subject: { CN: '*.a.com' } },
113    error: 'Host: ba.com. is not cert\'s CN: *.a.com'
114  },
115  {
116    host: '\n.b.com',
117    cert: { subject: { CN: '*n.b.com' } },
118    error: 'Host: \n.b.com. is not cert\'s CN: *n.b.com'
119  },
120  { host: 'b.a.com',
121    cert: {
122      subjectaltname: 'DNS:omg.com',
123      subject: { CN: '*.a.com' },
124    },
125    error: 'Host: b.a.com. is not in the cert\'s altnames: ' +
126           'DNS:omg.com' },
127  {
128    host: 'b.a.com',
129    cert: { subject: { CN: 'b*b.a.com' } },
130    error: 'Host: b.a.com. is not cert\'s CN: b*b.a.com'
131  },
132
133  // Empty Cert
134  {
135    host: 'a.com',
136    cert: { },
137    error: 'Cert does not contain a DNS name'
138  },
139
140  // Empty Subject w/DNS name
141  {
142    host: 'a.com', cert: {
143      subjectaltname: 'DNS:a.com',
144    }
145  },
146
147  // Empty Subject w/URI name
148  {
149    host: 'a.b.a.com', cert: {
150      subjectaltname: 'URI:http://a.b.a.com/',
151    },
152    error: 'Cert does not contain a DNS name'
153  },
154
155  // Multiple CN fields
156  {
157    host: 'foo.com', cert: {
158      subject: { CN: ['foo.com', 'bar.com'] } // CN=foo.com; CN=bar.com;
159    }
160  },
161
162  // DNS names and CN
163  {
164    host: 'a.com', cert: {
165      subjectaltname: 'DNS:*',
166      subject: { CN: 'b.com' }
167    },
168    error: 'Host: a.com. is not in the cert\'s altnames: ' +
169           'DNS:*'
170  },
171  {
172    host: 'a.com', cert: {
173      subjectaltname: 'DNS:*.com',
174      subject: { CN: 'b.com' }
175    },
176    error: 'Host: a.com. is not in the cert\'s altnames: ' +
177           'DNS:*.com'
178  },
179  {
180    host: 'a.co.uk', cert: {
181      subjectaltname: 'DNS:*.co.uk',
182      subject: { CN: 'b.com' }
183    }
184  },
185  {
186    host: 'a.com', cert: {
187      subjectaltname: 'DNS:*.a.com',
188      subject: { CN: 'a.com' }
189    },
190    error: 'Host: a.com. is not in the cert\'s altnames: ' +
191           'DNS:*.a.com'
192  },
193  {
194    host: 'a.com', cert: {
195      subjectaltname: 'DNS:*.a.com',
196      subject: { CN: 'b.com' }
197    },
198    error: 'Host: a.com. is not in the cert\'s altnames: ' +
199           'DNS:*.a.com'
200  },
201  {
202    host: 'a.com', cert: {
203      subjectaltname: 'DNS:a.com',
204      subject: { CN: 'b.com' }
205    }
206  },
207  {
208    host: 'a.com', cert: {
209      subjectaltname: 'DNS:A.COM',
210      subject: { CN: 'b.com' }
211    }
212  },
213
214  // DNS names
215  {
216    host: 'a.com', cert: {
217      subjectaltname: 'DNS:*.a.com',
218      subject: {}
219    },
220    error: 'Host: a.com. is not in the cert\'s altnames: ' +
221           'DNS:*.a.com'
222  },
223  {
224    host: 'b.a.com', cert: {
225      subjectaltname: 'DNS:*.a.com',
226      subject: {}
227    }
228  },
229  {
230    host: 'c.b.a.com', cert: {
231      subjectaltname: 'DNS:*.a.com',
232      subject: {}
233    },
234    error: 'Host: c.b.a.com. is not in the cert\'s altnames: ' +
235           'DNS:*.a.com'
236  },
237  {
238    host: 'b.a.com', cert: {
239      subjectaltname: 'DNS:*b.a.com',
240      subject: {}
241    }
242  },
243  {
244    host: 'a-cb.a.com', cert: {
245      subjectaltname: 'DNS:*b.a.com',
246      subject: {}
247    }
248  },
249  {
250    host: 'a.b.a.com', cert: {
251      subjectaltname: 'DNS:*b.a.com',
252      subject: {}
253    },
254    error: 'Host: a.b.a.com. is not in the cert\'s altnames: ' +
255           'DNS:*b.a.com'
256  },
257  // Multiple DNS names
258  {
259    host: 'a.b.a.com', cert: {
260      subjectaltname: 'DNS:*b.a.com, DNS:a.b.a.com',
261      subject: {}
262    }
263  },
264  // URI names
265  {
266    host: 'a.b.a.com', cert: {
267      subjectaltname: 'URI:http://a.b.a.com/',
268      subject: {}
269    },
270    error: 'Cert does not contain a DNS name'
271  },
272  {
273    host: 'a.b.a.com', cert: {
274      subjectaltname: 'URI:http://*.b.a.com/',
275      subject: {}
276    },
277    error: 'Cert does not contain a DNS name'
278  },
279  // IP addresses
280  {
281    host: 'a.b.a.com', cert: {
282      subjectaltname: 'IP Address:127.0.0.1',
283      subject: {}
284    },
285    error: 'Cert does not contain a DNS name'
286  },
287  {
288    host: '127.0.0.1', cert: {
289      subjectaltname: 'IP Address:127.0.0.1',
290      subject: {}
291    }
292  },
293  {
294    host: '127.0.0.2', cert: {
295      subjectaltname: 'IP Address:127.0.0.1',
296      subject: {}
297    },
298    error: 'IP: 127.0.0.2 is not in the cert\'s list: ' +
299           '127.0.0.1'
300  },
301  {
302    host: '127.0.0.1', cert: {
303      subjectaltname: 'DNS:a.com',
304      subject: {}
305    },
306    error: 'IP: 127.0.0.1 is not in the cert\'s list: '
307  },
308  {
309    host: 'localhost', cert: {
310      subjectaltname: 'DNS:a.com',
311      subject: { CN: 'localhost' }
312    },
313    error: 'Host: localhost. is not in the cert\'s altnames: ' +
314           'DNS:a.com'
315  },
316  // IDNA
317  {
318    host: 'xn--bcher-kva.example.com',
319    cert: { subject: { CN: '*.example.com' } },
320  },
321  // RFC 6125, section 6.4.3: "[...] the client SHOULD NOT attempt to match
322  // a presented identifier where the wildcard character is embedded within
323  // an A-label [...]"
324  {
325    host: 'xn--bcher-kva.example.com',
326    cert: { subject: { CN: 'xn--*.example.com' } },
327    error: 'Host: xn--bcher-kva.example.com. is not cert\'s CN: ' +
328            'xn--*.example.com',
329  },
330];
331
332tests.forEach(function(test, i) {
333  const err = tls.checkServerIdentity(test.host, test.cert);
334  assert.strictEqual(err && err.reason,
335                     test.error,
336                     `Test# ${i} failed: ${util.inspect(test)} \n` +
337                     `${test.error} != ${(err && err.reason)}`);
338});
339