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