1'use strict'; 2 3const common = require('../common'); 4const fixtures = require('../common/fixtures'); 5 6const { 7 assert, connect, keys, tls 8} = require(fixtures.path('tls-connect')); 9 10// Use ec10 and agent10, they are the only identities with intermediate CAs. 11const client = keys.ec10; 12const server = keys.agent10; 13 14// The certificates aren't for "localhost", so override the identity check. 15function checkServerIdentity(hostname, cert) { 16 assert.strictEqual(hostname, 'localhost'); 17 assert.strictEqual(cert.subject.CN, 'agent10.example.com'); 18} 19 20// Split out the single end-entity cert and the subordinate CA for later use. 21split(client.cert, client); 22split(server.cert, server); 23 24function split(file, into) { 25 const certs = /([^]*END CERTIFICATE-----\r?\n)(-----BEGIN[^]*)/.exec(file); 26 assert.strictEqual(certs.length, 3); 27 into.single = certs[1]; 28 into.subca = certs[2]; 29} 30 31// Typical setup, nothing special, complete cert chains sent to peer. 32connect({ 33 client: { 34 key: client.key, 35 cert: client.cert, 36 ca: server.ca, 37 checkServerIdentity, 38 }, 39 server: { 40 key: server.key, 41 cert: server.cert, 42 ca: client.ca, 43 requestCert: true, 44 }, 45}, function(err, pair, cleanup) { 46 assert.ifError(err); 47 return cleanup(); 48}); 49 50// As above, but without requesting client's cert. 51connect({ 52 client: { 53 ca: server.ca, 54 checkServerIdentity, 55 }, 56 server: { 57 key: server.key, 58 cert: server.cert, 59 ca: client.ca, 60 }, 61}, function(err, pair, cleanup) { 62 assert.ifError(err); 63 return cleanup(); 64}); 65 66// Request cert from TLS1.2 client that doesn't have one. 67connect({ 68 client: { 69 maxVersion: 'TLSv1.2', 70 ca: server.ca, 71 checkServerIdentity, 72 }, 73 server: { 74 key: server.key, 75 cert: server.cert, 76 ca: client.ca, 77 requestCert: true, 78 }, 79}, function(err, pair, cleanup) { 80 assert.strictEqual(pair.server.err.code, 81 'ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE'); 82 assert.strictEqual(pair.client.err.code, 83 'ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE'); 84 return cleanup(); 85}); 86 87// Request cert from TLS1.3 client that doesn't have one. 88if (tls.DEFAULT_MAX_VERSION === 'TLSv1.3') connect({ 89 client: { 90 ca: server.ca, 91 checkServerIdentity, 92 }, 93 server: { 94 key: server.key, 95 cert: server.cert, 96 ca: client.ca, 97 requestCert: true, 98 }, 99}, function(err, pair, cleanup) { 100 assert.strictEqual(pair.server.err.code, 101 'ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE'); 102 103 // TLS1.3 client completes handshake before server, and its only after the 104 // server handshakes, requests certs, gets back a zero-length list of certs, 105 // and sends a fatal Alert to the client that the client discovers there has 106 // been a fatal error. 107 pair.client.conn.once('error', common.mustCall((err) => { 108 assert.strictEqual(err.code, 'ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED'); 109 cleanup(); 110 })); 111}); 112 113// Typical configuration error, incomplete cert chains sent, we have to know the 114// peer's subordinate CAs in order to verify the peer. 115connect({ 116 client: { 117 key: client.key, 118 cert: client.single, 119 ca: [server.ca, server.subca], 120 checkServerIdentity, 121 }, 122 server: { 123 key: server.key, 124 cert: server.single, 125 ca: [client.ca, client.subca], 126 requestCert: true, 127 }, 128}, function(err, pair, cleanup) { 129 assert.ifError(err); 130 return cleanup(); 131}); 132 133// Like above, but provide root CA and subordinate CA as multi-PEM. 134connect({ 135 client: { 136 key: client.key, 137 cert: client.single, 138 ca: server.ca + '\n' + server.subca, 139 checkServerIdentity, 140 }, 141 server: { 142 key: server.key, 143 cert: server.single, 144 ca: client.ca + '\n' + client.subca, 145 requestCert: true, 146 }, 147}, function(err, pair, cleanup) { 148 assert.ifError(err); 149 return cleanup(); 150}); 151 152// Like above, but provide multi-PEM in an array. 153connect({ 154 client: { 155 key: client.key, 156 cert: client.single, 157 ca: [server.ca + '\n' + server.subca], 158 checkServerIdentity, 159 }, 160 server: { 161 key: server.key, 162 cert: server.single, 163 ca: [client.ca + '\n' + client.subca], 164 requestCert: true, 165 }, 166}, function(err, pair, cleanup) { 167 assert.ifError(err); 168 return cleanup(); 169}); 170 171// Fail to complete server's chain 172connect({ 173 client: { 174 ca: server.ca, 175 checkServerIdentity, 176 }, 177 server: { 178 key: server.key, 179 cert: server.single, 180 }, 181}, function(err, pair, cleanup) { 182 assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); 183 return cleanup(); 184}); 185 186// Fail to complete client's chain. 187connect({ 188 client: { 189 key: client.key, 190 cert: client.single, 191 ca: server.ca, 192 checkServerIdentity, 193 }, 194 server: { 195 key: server.key, 196 cert: server.cert, 197 ca: client.ca, 198 requestCert: true, 199 }, 200}, function(err, pair, cleanup) { 201 assert.ifError(pair.client.error); 202 assert.ifError(pair.server.error); 203 assert.strictEqual(err.code, 'ECONNRESET'); 204 return cleanup(); 205}); 206 207// Fail to find CA for server. 208connect({ 209 client: { 210 checkServerIdentity, 211 }, 212 server: { 213 key: server.key, 214 cert: server.cert, 215 }, 216}, function(err, pair, cleanup) { 217 assert.strictEqual(err.code, 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'); 218 return cleanup(); 219}); 220 221// Server sent their CA, but CA cannot be trusted if it is not locally known. 222connect({ 223 client: { 224 checkServerIdentity, 225 }, 226 server: { 227 key: server.key, 228 cert: server.cert + '\n' + server.ca, 229 }, 230}, function(err, pair, cleanup) { 231 assert.strictEqual(err.code, 'SELF_SIGNED_CERT_IN_CHAIN'); 232 return cleanup(); 233}); 234 235// Server sent their CA, wrongly, but its OK since we know the CA locally. 236connect({ 237 client: { 238 checkServerIdentity, 239 ca: server.ca, 240 }, 241 server: { 242 key: server.key, 243 cert: server.cert + '\n' + server.ca, 244 }, 245}, function(err, pair, cleanup) { 246 assert.ifError(err); 247 return cleanup(); 248}); 249 250// Fail to complete client's chain. 251connect({ 252 client: { 253 key: client.key, 254 cert: client.single, 255 ca: server.ca, 256 checkServerIdentity, 257 }, 258 server: { 259 key: server.key, 260 cert: server.cert, 261 ca: client.ca, 262 requestCert: true, 263 }, 264}, function(err, pair, cleanup) { 265 assert.strictEqual(err.code, 'ECONNRESET'); 266 return cleanup(); 267}); 268 269// Fail to find CA for client. 270connect({ 271 client: { 272 key: client.key, 273 cert: client.cert, 274 ca: server.ca, 275 checkServerIdentity, 276 }, 277 server: { 278 key: server.key, 279 cert: server.cert, 280 requestCert: true, 281 }, 282}, function(err, pair, cleanup) { 283 assert.strictEqual(err.code, 'ECONNRESET'); 284 return cleanup(); 285}); 286 287// Confirm support for "BEGIN TRUSTED CERTIFICATE". 288connect({ 289 client: { 290 key: client.key, 291 cert: client.cert, 292 ca: server.ca.replace(/CERTIFICATE/g, 'TRUSTED CERTIFICATE'), 293 checkServerIdentity, 294 }, 295 server: { 296 key: server.key, 297 cert: server.cert, 298 ca: client.ca, 299 requestCert: true, 300 }, 301}, function(err, pair, cleanup) { 302 assert.ifError(err); 303 return cleanup(); 304}); 305 306// Confirm support for "BEGIN TRUSTED CERTIFICATE". 307connect({ 308 client: { 309 key: client.key, 310 cert: client.cert, 311 ca: server.ca, 312 checkServerIdentity, 313 }, 314 server: { 315 key: server.key, 316 cert: server.cert, 317 ca: client.ca.replace(/CERTIFICATE/g, 'TRUSTED CERTIFICATE'), 318 requestCert: true, 319 }, 320}, function(err, pair, cleanup) { 321 assert.ifError(err); 322 return cleanup(); 323}); 324 325// Confirm support for "BEGIN X509 CERTIFICATE". 326connect({ 327 client: { 328 key: client.key, 329 cert: client.cert, 330 ca: server.ca.replace(/CERTIFICATE/g, 'X509 CERTIFICATE'), 331 checkServerIdentity, 332 }, 333 server: { 334 key: server.key, 335 cert: server.cert, 336 ca: client.ca, 337 requestCert: true, 338 }, 339}, function(err, pair, cleanup) { 340 assert.ifError(err); 341 return cleanup(); 342}); 343 344// Confirm support for "BEGIN X509 CERTIFICATE". 345connect({ 346 client: { 347 key: client.key, 348 cert: client.cert, 349 ca: server.ca, 350 checkServerIdentity, 351 }, 352 server: { 353 key: server.key, 354 cert: server.cert, 355 ca: client.ca.replace(/CERTIFICATE/g, 'X509 CERTIFICATE'), 356 requestCert: true, 357 }, 358}, function(err, pair, cleanup) { 359 assert.ifError(err); 360 return cleanup(); 361}); 362