nodejs/test/parallel/test-tls-client-auth.js

361 lines
7.9 KiB
JavaScript

'use strict';
const common = require('../common');
const fixtures = require('../common/fixtures');
const {
assert, connect, keys, tls
} = require(fixtures.path('tls-connect'));
// Use ec10 and agent10, they are the only identities with intermediate CAs.
const client = keys.ec10;
const server = keys.agent10;
// The certificates aren't for "localhost", so override the identity check.
function checkServerIdentity(hostname, cert) {
assert.strictEqual(hostname, 'localhost');
assert.strictEqual(cert.subject.CN, 'agent10.example.com');
}
// Split out the single end-entity cert and the subordinate CA for later use.
split(client.cert, client);
split(server.cert, server);
function split(file, into) {
const certs = /([^]*END CERTIFICATE-----\r?\n)(-----BEGIN[^]*)/.exec(file);
assert.strictEqual(certs.length, 3);
into.single = certs[1];
into.subca = certs[2];
}
// Typical setup, nothing special, complete cert chains sent to peer.
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// As above, but without requesting client's cert.
connect({
client: {
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Request cert from TLS1.2 client that doesn't have one.
connect({
client: {
maxVersion: 'TLSv1.2',
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.strictEqual(pair.server.err.code,
'ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE');
assert.strictEqual(pair.client.err.code, 'ECONNRESET');
return cleanup();
});
// Request cert from TLS1.3 client that doesn't have one.
if (tls.DEFAULT_MAX_VERSION === 'TLSv1.3') connect({
client: {
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.strictEqual(pair.server.err.code,
'ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE');
// TLS1.3 client completes handshake before server, and its only after the
// server handshakes, requests certs, gets back a zero-length list of certs,
// and sends a fatal Alert to the client that the client discovers there has
// been a fatal error.
pair.client.conn.once('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED');
cleanup();
}));
});
// Typical configuration error, incomplete cert chains sent, we have to know the
// peer's subordinate CAs in order to verify the peer.
connect({
client: {
key: client.key,
cert: client.single,
ca: [server.ca, server.subca],
checkServerIdentity,
},
server: {
key: server.key,
cert: server.single,
ca: [client.ca, client.subca],
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Like above, but provide root CA and subordinate CA as multi-PEM.
connect({
client: {
key: client.key,
cert: client.single,
ca: server.ca + '\n' + server.subca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.single,
ca: client.ca + '\n' + client.subca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Like above, but provide multi-PEM in an array.
connect({
client: {
key: client.key,
cert: client.single,
ca: [server.ca + '\n' + server.subca],
checkServerIdentity,
},
server: {
key: server.key,
cert: server.single,
ca: [client.ca + '\n' + client.subca],
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Fail to complete server's chain
connect({
client: {
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.single,
},
}, function(err, pair, cleanup) {
assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE');
return cleanup();
});
// Fail to complete client's chain.
connect({
client: {
key: client.key,
cert: client.single,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(pair.client.error);
assert.ifError(pair.server.error);
assert.strictEqual(err.code, 'ECONNRESET');
return cleanup();
});
// Fail to find CA for server.
connect({
client: {
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
},
}, function(err, pair, cleanup) {
assert.strictEqual(err.code, 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY');
return cleanup();
});
// Server sent their CA, but CA cannot be trusted if it is not locally known.
connect({
client: {
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert + '\n' + server.ca,
},
}, function(err, pair, cleanup) {
assert.strictEqual(err.code, 'SELF_SIGNED_CERT_IN_CHAIN');
return cleanup();
});
// Server sent their CA, wrongly, but its OK since we know the CA locally.
connect({
client: {
checkServerIdentity,
ca: server.ca,
},
server: {
key: server.key,
cert: server.cert + '\n' + server.ca,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Fail to complete client's chain.
connect({
client: {
key: client.key,
cert: client.single,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.strictEqual(err.code, 'ECONNRESET');
return cleanup();
});
// Fail to find CA for client.
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.strictEqual(err.code, 'ECONNRESET');
return cleanup();
});
// Confirm support for "BEGIN TRUSTED CERTIFICATE".
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca.replace(/CERTIFICATE/g, 'TRUSTED CERTIFICATE'),
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Confirm support for "BEGIN TRUSTED CERTIFICATE".
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca.replace(/CERTIFICATE/g, 'TRUSTED CERTIFICATE'),
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Confirm support for "BEGIN X509 CERTIFICATE".
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca.replace(/CERTIFICATE/g, 'X509 CERTIFICATE'),
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca,
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
// Confirm support for "BEGIN X509 CERTIFICATE".
connect({
client: {
key: client.key,
cert: client.cert,
ca: server.ca,
checkServerIdentity,
},
server: {
key: server.key,
cert: server.cert,
ca: client.ca.replace(/CERTIFICATE/g, 'X509 CERTIFICATE'),
requestCert: true,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});