| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 51253ba commit 32c527d
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -123,23 +123,17 @@ all sessions). Methods implementing this technique are called "ephemeral". | |||
| 123 | 123 | Currently two methods are commonly used to achieve perfect forward secrecy (note | |
| 124 | 124 | the character "E" appended to the traditional abbreviations): | |
| 125 | 125 | ||
| 126 | - * [DHE][]: An ephemeral version of the Diffie-Hellman key-agreement protocol. | ||
| 127 | 126 | * [ECDHE][]: An ephemeral version of the Elliptic Curve Diffie-Hellman | |
| 128 | 127 | key-agreement protocol. | |
| 128 | + * [DHE][]: An ephemeral version of the Diffie-Hellman key-agreement protocol. | ||
| 129 | 129 | ||
| 130 | - To use perfect forward secrecy using `DHE` with the `node:tls` module, it is | ||
| 131 | - required to generate Diffie-Hellman parameters and specify them with the | ||
| 132 | - `dhparam` option to [`tls.createSecureContext()`][]. The following illustrates | ||
| 133 | - the use of the OpenSSL command-line interface to generate such parameters: | ||
| 134 | - | ||
| 135 | - ```bash | ||
| 136 | - openssl dhparam -outform PEM -out dhparam.pem 2048 | ||
| 137 | - ``` | ||
| 130 | + Perfect forward secrecy using ECDHE is enabled by default. The `ecdhCurve` | ||
| 131 | + option can be used when creating a TLS server to customize the list of supported | ||
| 132 | + ECDH curves to use. See [`tls.createServer()`][] for more info. | ||
| 138 | 133 | ||
| 139 | - If using perfect forward secrecy using `ECDHE`, Diffie-Hellman parameters are | ||
| 140 | - not required and a default ECDHE curve will be used. The `ecdhCurve` property | ||
| 141 | - can be used when creating a TLS Server to specify the list of names of supported | ||
| 142 | - curves to use, see [`tls.createServer()`][] for more info. | ||
| 134 | + DHE is disabled by default but can be enabled alongside ECDHE by setting the | ||
| 135 | + `dhparam` option to `'auto'`. Custom DHE parameters are also supported but | ||
| 136 | + discouraged in favor of automatically selected, well-known parameters. | ||
| 143 | 137 | ||
| 144 | 138 | Perfect forward secrecy was optional up to TLSv1.2. As of TLSv1.3, (EC)DHE is | |
| 145 | 139 | always used (with the exception of PSK-only connections). | |
@@ -1796,6 +1790,10 @@ argument. | |||
| 1796 | 1790 | <!-- YAML | |
| 1797 | 1791 | added: v0.11.13 | |
| 1798 | 1792 | changes: | |
| 1793 | + - version: REPLACEME | ||
| 1794 | + pr-url: https://github.com/nodejs/node/pull/46978 | ||
| 1795 | + description: The `dhparam` option can now be set to `'auto'` to | ||
| 1796 | + enable DHE with appropriate well-known parameters. | ||
| 1799 | 1797 | - version: v12.12.0 | |
| 1800 | 1798 | pr-url: https://github.com/nodejs/node/pull/28973 | |
| 1801 | 1799 | description: Added `privateKeyIdentifier` and `privateKeyEngine` options | |
@@ -1880,13 +1878,10 @@ changes: | |||
| 1880 | 1878 | client certificate. | |
| 1881 | 1879 | * `crl` {string|string\[]|Buffer|Buffer\[]} PEM formatted CRLs (Certificate | |
| 1882 | 1880 | Revocation Lists). | |
| 1883 | - * `dhparam` {string|Buffer} Diffie-Hellman parameters, required for non-ECDHE | ||
| 1884 | - [perfect forward secrecy][]. Use `openssl dhparam` to create the parameters. | ||
| 1885 | - The key length must be greater than or equal to 1024 bits or else an error | ||
| 1886 | - will be thrown. Although 1024 bits is permissible, use 2048 bits or larger | ||
| 1887 | - for stronger security. If omitted or invalid, the parameters are silently | ||
| 1888 | - discarded and DHE ciphers will not be available. [ECDHE][]-based [perfect | ||
| 1889 | - forward secrecy][] will still be available. | ||
| 1881 | + * `dhparam` {string|Buffer} `'auto'` or custom Diffie-Hellman parameters, | ||
| 1882 | + required for non-ECDHE [perfect forward secrecy][]. If omitted or invalid, | ||
| 1883 | + the parameters are silently discarded and DHE ciphers will not be available. | ||
| 1884 | + [ECDHE][]-based [perfect forward secrecy][] will still be available. | ||
| 1890 | 1885 | * `ecdhCurve` {string} A string describing a named curve or a colon separated | |
| 1891 | 1886 | list of curve NIDs or names, for example `P-521:P-384:P-256`, to use for | |
| 1892 | 1887 | ECDH key agreement. Set to `auto` to select the | |
@@ -1973,6 +1968,13 @@ A key is _required_ for ciphers that use certificates. Either `key` or | |||
| 1973 | 1968 | If the `ca` option is not given, then Node.js will default to using | |
| 1974 | 1969 | [Mozilla's publicly trusted list of CAs][]. | |
| 1975 | 1970 | ||
| 1971 | + Custom DHE parameters are discouraged in favor of the new `dhparam: 'auto'` | ||
| 1972 | + option. When set to `'auto'`, well-known DHE parameters of sufficient strength | ||
| 1973 | + will be selected automatically. Otherwise, if necessary, `openssl dhparam` can | ||
| 1974 | + be used to create custom parameters. The key length must be greater than or | ||
| 1975 | + equal to 1024 bits or else an error will be thrown. Although 1024 bits is | ||
| 1976 | + permissible, use 2048 bits or larger for stronger security. | ||
| 1977 | + | ||
| 1976 | 1978 | ## `tls.createSecurePair([context][, isServer][, requestCert][, rejectUnauthorized][, options])` | |
| 1977 | 1979 | ||
| 1978 | 1980 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -240,7 +240,7 @@ function configSecureContext(context, options = kEmptyObject, name = 'options') | |||
| 240 | 240 | ||
| 241 | 241 | if (dhparam !== undefined && dhparam !== null) { | |
| 242 | 242 | validateKeyOrCertOption(`${name}.dhparam`, dhparam); | |
| 243 | - const warning = context.setDHParam(dhparam); | ||
| 243 | + const warning = context.setDHParam(dhparam === 'auto' || dhparam); | ||
| 244 | 244 | if (warning) | |
| 245 | 245 | process.emitWarning(warning, 'SecurityWarning'); | |
| 246 | 246 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -854,6 +854,14 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { | |||
| 854 | 854 | ||
| 855 | 855 | CHECK_GE(args.Length(), 1); // DH argument is mandatory | |
| 856 | 856 | ||
| 857 | + // If the user specified "auto" for dhparams, the JavaScript layer will pass | ||
| 858 | + // true to this function instead of the original string. Any other string | ||
| 859 | + // value will be interpreted as custom DH parameters below. | ||
| 860 | + if (args[0]->IsTrue()) { | ||
| 861 | + CHECK(SSL_CTX_set_dh_auto(sc->ctx_.get(), true)); | ||
| 862 | + return; | ||
| 863 | + } | ||
| 864 | + | ||
| 857 | 865 | DHPointer dh; | |
| 858 | 866 | { | |
| 859 | 867 | BIOPointer bio(LoadBIO(env, args[0])); | |
@@ -864,6 +872,7 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { | |||
| 864 | 872 | } | |
| 865 | 873 | ||
| 866 | 874 | // Invalid dhparam is silently discarded and DHE is no longer used. | |
| 875 | + // TODO(tniessen): don't silently discard invalid dhparam. | ||
| 867 | 876 | if (!dh) | |
| 868 | 877 | return; | |
| 869 | 878 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ if (!common.hasCrypto) | |||
| 5 | 5 | const fixtures = require('../common/fixtures'); | |
| 6 | 6 | ||
| 7 | 7 | const assert = require('assert'); | |
| 8 | + const { X509Certificate } = require('crypto'); | ||
| 8 | 9 | const tls = require('tls'); | |
| 9 | 10 | ||
| 10 | 11 | const key = fixtures.readKey('agent2-key.pem'); | |
@@ -29,7 +30,20 @@ function test(size, type, name, cipher) { | |||
| 29 | 30 | ||
| 30 | 31 | if (name) options.ecdhCurve = name; | |
| 31 | 32 | ||
| 32 | - if (type === 'DH') options.dhparam = loadDHParam(size); | ||
| 33 | + if (type === 'DH') { | ||
| 34 | + if (size === 'auto') { | ||
| 35 | + options.dhparam = 'auto'; | ||
| 36 | + // The DHE parameters selected by OpenSSL depend on the strength of the | ||
| 37 | + // certificate's key. For this test, we can assume that the modulus length | ||
| 38 | + // of the certificate's key is equal to the size of the DHE parameter, but | ||
| 39 | + // that is really only true for a few modulus lengths. | ||
| 40 | + ({ | ||
| 41 | + publicKey: { asymmetricKeyDetails: { modulusLength: size } } | ||
| 42 | + } = new X509Certificate(cert)); | ||
| 43 | + } else { | ||
| 44 | + options.dhparam = loadDHParam(size); | ||
| 45 | + } | ||
| 46 | + } | ||
| 33 | 47 | ||
| 34 | 48 | const server = tls.createServer(options, common.mustCall((conn) => { | |
| 35 | 49 | assert.strictEqual(conn.getEphemeralKeyInfo(), null); | |
@@ -54,6 +68,7 @@ function test(size, type, name, cipher) { | |||
| 54 | 68 | } | |
| 55 | 69 | ||
| 56 | 70 | test(undefined, undefined, undefined, 'AES128-SHA256'); | |
| 71 | + test('auto', 'DH', undefined, 'DHE-RSA-AES128-GCM-SHA256'); | ||
| 57 | 72 | test(1024, 'DH', undefined, 'DHE-RSA-AES128-GCM-SHA256'); | |
| 58 | 73 | test(2048, 'DH', undefined, 'DHE-RSA-AES128-GCM-SHA256'); | |
| 59 | 74 | test(256, 'ECDH', 'prime256v1', 'ECDHE-RSA-AES128-GCM-SHA256'); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,14 +29,19 @@ if (!common.opensslCli) | |||
| 29 | 29 | common.skip('missing openssl-cli'); | |
| 30 | 30 | ||
| 31 | 31 | const assert = require('assert'); | |
| 32 | + const { X509Certificate } = require('crypto'); | ||
| 32 | 33 | const { once } = require('events'); | |
| 33 | 34 | const tls = require('tls'); | |
| 34 | 35 | const { execFile } = require('child_process'); | |
| 35 | 36 | const fixtures = require('../common/fixtures'); | |
| 36 | 37 | ||
| 37 | 38 | const key = fixtures.readKey('agent2-key.pem'); | |
| 38 | 39 | const cert = fixtures.readKey('agent2-cert.pem'); | |
| 39 | - const ciphers = 'DHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; | ||
| 40 | + | ||
| 41 | + // Prefer DHE over ECDHE when possible. | ||
| 42 | + const dheCipher = 'DHE-RSA-AES128-SHA256'; | ||
| 43 | + const ecdheCipher = 'ECDHE-RSA-AES128-SHA256'; | ||
| 44 | + const ciphers = `${dheCipher}:${ecdheCipher}`; | ||
| 40 | 45 | ||
| 41 | 46 | // Test will emit a warning because the DH parameter size is < 2048 bits | |
| 42 | 47 | common.expectWarning('SecurityWarning', | |
@@ -47,12 +52,12 @@ function loadDHParam(n) { | |||
| 47 | 52 | return fixtures.readKey(keyname); | |
| 48 | 53 | } | |
| 49 | 54 | ||
| 50 | - function test(keylen, expectedCipher) { | ||
| 55 | + function test(dhparam, keylen, expectedCipher) { | ||
| 51 | 56 | const options = { | |
| 52 | - key: key, | ||
| 53 | - cert: cert, | ||
| 54 | - ciphers: ciphers, | ||
| 55 | - dhparam: loadDHParam(keylen), | ||
| 57 | + key, | ||
| 58 | + cert, | ||
| 59 | + ciphers, | ||
| 60 | + dhparam, | ||
| 56 | 61 | maxVersion: 'TLSv1.2', | |
| 57 | 62 | }; | |
| 58 | 63 | ||
@@ -63,7 +68,7 @@ function test(keylen, expectedCipher) { | |||
| 63 | 68 | '-cipher', ciphers]; | |
| 64 | 69 | ||
| 65 | 70 | execFile(common.opensslCli, args, common.mustSucceed((stdout) => { | |
| 66 | - assert(keylen === 'error' || | ||
| 71 | + assert(keylen === null || | ||
| 67 | 72 | stdout.includes(`Server Temp Key: DH, ${keylen} bits`)); | |
| 68 | 73 | assert(stdout.includes(`Cipher : ${expectedCipher}`)); | |
| 69 | 74 | server.close(); | |
@@ -73,12 +78,35 @@ function test(keylen, expectedCipher) { | |||
| 73 | 78 | return once(server, 'close'); | |
| 74 | 79 | } | |
| 75 | 80 | ||
| 81 | + function testCustomParam(keylen, expectedCipher) { | ||
| 82 | + const dhparam = loadDHParam(keylen); | ||
| 83 | + if (keylen === 'error') keylen = null; | ||
| 84 | + return test(dhparam, keylen, expectedCipher); | ||
| 85 | + } | ||
| 86 | + | ||
| 76 | 87 | (async () => { | |
| 88 | + // By default, DHE is disabled while ECDHE is enabled. | ||
| 89 | + for (const dhparam of [undefined, null]) { | ||
| 90 | + await test(dhparam, null, ecdheCipher); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + // The DHE parameters selected by OpenSSL depend on the strength of the | ||
| 94 | + // certificate's key. For this test, we can assume that the modulus length | ||
| 95 | + // of the certificate's key is equal to the size of the DHE parameter, but | ||
| 96 | + // that is really only true for a few modulus lengths. | ||
| 97 | + const { | ||
| 98 | + publicKey: { asymmetricKeyDetails: { modulusLength } } | ||
| 99 | + } = new X509Certificate(cert); | ||
| 100 | + await test('auto', modulusLength, dheCipher); | ||
| 101 | + | ||
| 77 | 102 | assert.throws(() => { | |
| 78 | - test(512, 'DHE-RSA-AES128-SHA256'); | ||
| 103 | + testCustomParam(512); | ||
| 79 | 104 | }, /DH parameter is less than 1024 bits/); | |
| 80 | 105 | ||
| 81 | - await test(1024, 'DHE-RSA-AES128-SHA256'); | ||
| 82 | - await test(2048, 'DHE-RSA-AES128-SHA256'); | ||
| 83 | - await test('error', 'ECDHE-RSA-AES128-SHA256'); | ||
| 106 | + // Custom DHE parameters are supported (but discouraged). | ||
| 107 | + await testCustomParam(1024, dheCipher); | ||
| 108 | + await testCustomParam(2048, dheCipher); | ||
| 109 | + | ||
| 110 | + // Invalid DHE parameters are discarded. ECDHE remains enabled. | ||
| 111 | + await testCustomParam('error', ecdheCipher); | ||
| 84 | 112 | })().then(common.mustCall()); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments