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