GeezerVison is showing github.com — src: suggest --use-system-ca when a certificate error occurs · nodejs/node@3cff7f8
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/tls.md +6Lines changed: 6 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -547,6 +547,12 @@ description are taken from deps/openssl/openssl/crypto/x509/x509_txt.c | 547 | 547 | * `'CERT_REJECTED'`: Certificate rejected. | 548 | 548 | * `'HOSTNAME_MISMATCH'`: Hostname mismatch. | 549 | 549 |
| | 550 | +When certificate errors like `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, | | 551 | +`DEPTH_ZERO_SELF_SIGNED_CERT`, or `UNABLE_TO_GET_ISSUER_CERT` occur, Node.js | | 552 | +appends a hint suggesting that if the root CA is installed locally, | | 553 | +try running with the `--use-system-ca` flag to direct developers towards a | | 554 | +secure solution, to prevent unsafe workarounds. | | 555 | + | 550 | 556 | ## Class: `tls.CryptoStream` | 551 | 557 |
| 552 | 558 | <!-- YAML | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_common.cc +13-1Lines changed: 13 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -53,8 +53,20 @@ SSLSessionPointer GetTLSSession(const unsigned char* buf, size_t length) { | 53 | 53 | } | 54 | 54 |
| 55 | 55 | MaybeLocal<Value> GetValidationErrorReason(Environment* env, int err) { | 56 | | - auto reason = X509Pointer::ErrorReason(err).value_or(""); | | 56 | + auto reason = std::string(X509Pointer::ErrorReason(err).value_or("")); | 57 | 57 | if (reason == "") return Undefined(env->isolate()); | | 58 | + | | 59 | + // Suggest --use-system-ca if the error indicates a certificate issue | | 60 | + bool suggest_system_ca = | | 61 | + (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) || | | 62 | + (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || | | 63 | + ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) && | | 64 | + !per_process::cli_options->use_system_ca); | | 65 | + | | 66 | + if (suggest_system_ca) { | | 67 | + reason.append("; if the root CA is installed locally, " | | 68 | + "try running Node.js with --use-system-ca"); | | 69 | + } | 58 | 70 | return OneByteString(env->isolate(), reason); | 59 | 71 | } | 60 | 72 |
| |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-https-agent-create-connection.js +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -17,7 +17,7 @@ const options = { | 17 | 17 |
| 18 | 18 | const expectedHeader = /^HTTP\/1\.1 200 OK/; | 19 | 19 | const expectedBody = /hello world\n/; | 20 | | -const expectCertError = /^Error: unable to verify the first certificate$/; | | 20 | +const expectCertError = /^UNABLE_TO_VERIFY_LEAF_SIGNATURE$/; | 21 | 21 |
| 22 | 22 | const checkRequest = (socket, server) => { | 23 | 23 | let result = ''; | @@ -112,7 +112,7 @@ function createServer() { | 112 | 112 | const options = null; | 113 | 113 | const socket = agent.createConnection(port, host, options); | 114 | 114 | socket.on('error', common.mustCall((e) => { | 115 | | - assert.match(e.toString(), expectCertError); | | 115 | + assert.match(e.code, expectCertError); | 116 | 116 | server.close(); | 117 | 117 | })); | 118 | 118 | })); | @@ -127,7 +127,7 @@ function createServer() { | 127 | 127 | const options = undefined; | 128 | 128 | const socket = agent.createConnection(port, host, options); | 129 | 129 | socket.on('error', common.mustCall((e) => { | 130 | | - assert.match(e.toString(), expectCertError); | | 130 | + assert.match(e.code, expectCertError); | 131 | 131 | server.close(); | 132 | 132 | })); | 133 | 133 | })); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-tls-addca.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -34,7 +34,7 @@ connect({ | 34 | 34 | server: serverOptions, | 35 | 35 | }, common.mustCall((err, pair, cleanup) => { | 36 | 36 | assert(err); | 37 | | - assert.strictEqual(err.message, 'unable to verify the first certificate'); | | 37 | + assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 38 | 38 | cleanup(); | 39 | 39 |
| 40 | 40 | // This time it should connect because contextWithCert includes the needed CA | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-tls-friendly-error-message.js -1Lines changed: 0 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -40,6 +40,5 @@ tls.createServer({ key, cert }).on('connection', common.mustCall(function() { | 40 | 40 | const options = { port: this.address().port, rejectUnauthorized: true }; | 41 | 41 | tls.connect(options).on('error', common.mustCall(function(err) { | 42 | 42 | assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 43 | | - assert.strictEqual(err.message, 'unable to verify the first certificate'); | 44 | 43 | })); | 45 | 44 | })); |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-tls-set-secure-context.js +6-6Lines changed: 6 additions & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,7 +13,6 @@ const assert = require('assert'); | 13 | 13 | const events = require('events'); | 14 | 14 | const https = require('https'); | 15 | 15 | const timers = require('timers/promises'); | 16 | | -const { hasOpenSSL3 } = require('../common/crypto'); | 17 | 16 | const fixtures = require('../common/fixtures'); | 18 | 17 | const credentialOptions = [ | 19 | 18 | { | @@ -57,17 +56,18 @@ server.listen(0, common.mustCall(() => { | 57 | 56 |
| 58 | 57 | server.setSecureContext(credentialOptions[1]); | 59 | 58 | firstResponse.write('request-'); | 60 | | - const errorMessageRegex = hasOpenSSL3 ? | 61 | | - /^Error: self-signed certificate$/ : | 62 | | - /^Error: self signed certificate$/; | 63 | | - await assert.rejects(makeRequest(port, 3), errorMessageRegex); | | 59 | + await assert.rejects(makeRequest(port, 3), { | | 60 | + code: 'DEPTH_ZERO_SELF_SIGNED_CERT', | | 61 | + }); | 64 | 62 |
| 65 | 63 | server.setSecureContext(credentialOptions[0]); | 66 | 64 | assert.strictEqual(await makeRequest(port, 4), 'success'); | 67 | 65 |
| 68 | 66 | server.setSecureContext(credentialOptions[1]); | 69 | 67 | firstResponse.end('fun!'); | 70 | | - await assert.rejects(makeRequest(port, 5), errorMessageRegex); | | 68 | + await assert.rejects(makeRequest(port, 5), { | | 69 | + code: 'DEPTH_ZERO_SELF_SIGNED_CERT', | | 70 | + }); | 71 | 71 |
| 72 | 72 | assert.strictEqual(await firstRequest, 'multi-request-success-fun!'); | 73 | 73 | server.close(); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-tls-socket-default-options.js +5-5Lines changed: 5 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -10,11 +10,11 @@ const { | 10 | 10 | } = require(fixtures.path('tls-connect')); | 11 | 11 |
| 12 | 12 | test(undefined, (err) => { | 13 | | - assert.strictEqual(err.message, 'unable to verify the first certificate'); | | 13 | + assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 14 | 14 | }); | 15 | 15 |
| 16 | 16 | test({}, (err) => { | 17 | | - assert.strictEqual(err.message, 'unable to verify the first certificate'); | | 17 | + assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 18 | 18 | }); | 19 | 19 |
| 20 | 20 | test( | | 30 | 30 | test( | 31 | 31 | { secureContext: tls.createSecureContext(), ca: keys.agent1.ca }, | 32 | 32 | (err) => { | 33 | | - assert.strictEqual(err.message, | 34 | | - 'unable to verify the first certificate'); | | 33 | + assert.strictEqual(err.code, | | 34 | + 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 35 | 35 | }); | 36 | 36 |
| 37 | 37 | function test(client, callback) { | @@ -42,7 +42,7 @@ function test(client, callback) { | 42 | 42 | cert: keys.agent1.cert, | 43 | 43 | }, | 44 | 44 | }, function(err, pair, cleanup) { | 45 | | - assert.strictEqual(err.message, 'unable to verify the first certificate'); | | 45 | + assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); | 46 | 46 | let recv = ''; | 47 | 47 | pair.server.server.once('secureConnection', common.mustCall((conn) => { | 48 | 48 | conn.on('data', (data) => recv += data); | |
|