diff --git a/src/js/configs.js b/src/js/configs.js index fed1a6d5..fdbcbd6e 100644 --- a/src/js/configs.js +++ b/src/js/configs.js @@ -31,7 +31,7 @@ module.exports = { usesOpenssl: false, }, caddy: { - cipherFormat: 'caddy', + cipherFormat: 'go', latestVersion: '2.8.4', eolBefore: '2.0.0', name: 'Caddy', @@ -68,6 +68,7 @@ module.exports = { name: 'Go', tls13: '1.13.0', usesOpenssl: false, + supportedCiphers: [ 'TLS_RSA_WITH_RC4_128_SHA', 'TLS_RSA_WITH_3DES_EDE_CBC_SHA', 'TLS_RSA_WITH_AES_128_CBC_SHA', 'TLS_RSA_WITH_AES_256_CBC_SHA', 'TLS_RSA_WITH_AES_128_CBC_SHA256', 'TLS_RSA_WITH_AES_128_GCM_SHA256', 'TLS_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_ECDSA_WITH_RC4_128_SHA', 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA', 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA', 'TLS_ECDHE_RSA_WITH_RC4_128_SHA', 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA', 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA', 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256', 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256' ], }, haproxy: { latestVersion: '3.0', diff --git a/src/js/index.js b/src/js/index.js index cb240e0b..4ea70421 100755 --- a/src/js/index.js +++ b/src/js/index.js @@ -128,6 +128,23 @@ function form_config_init() { e_version.value = configs[params.get('server')].latestVersion; } + // compat behavior with rendering of guidelines <= 5.7 + // (guideline ver is used to separate past rendering behavior from current) + const guideline = params.get('guideline'); + if (guideline !== undefined && !isNaN(guideline)) { + const guideln = parseFloat(guideline); + if (!isNaN(guideln) && guideln <= 5.7) { + // OCSP and HSTS logic inverted; absense indicates checked (enabled) + if (params.get('hsts') === undefined) { + document.getElementById('hsts').checked = true; + } + if (params.get('ocsp') === undefined) { + document.getElementById('ocsp').checked = true; + } + } + document.getElementById('config-old-compat').classList.toggle('d-none', (!isNaN(guideln) && guideln >= 6.0)); + } + for (let entry of params.entries()) { if (validHashKeys.includes(entry[0])) { // find the element @@ -140,8 +157,7 @@ function form_config_init() { switch (e.type) { case 'radio': case 'checkbox': - // if it's in the mappings, we should do a find/replace - e.checked = mappings[entry[1]] === undefined ? !!entry[1] : mappings[entry[1]]; + e.checked = entry[1] === undefined ? true : mappings[entry[1]] === undefined ? !!entry[1] : mappings[entry[1]]; break; case 'text': case 'hidden': diff --git a/src/js/state.js b/src/js/state.js index 1f95df6e..73417db3 100644 --- a/src/js/state.js +++ b/src/js/state.js @@ -2,9 +2,10 @@ import configs from './configs.js'; import minver from './helpers/minver.js'; import { xmlEntities } from './utils.js'; +// note: guideln_latest for '6.0' is rendered as number 6 in guidelines[], not string '6.0' +const guideln_latest = '6.0'; // update when guideline changes const guidelines = {}; -guidelines['5.7'] = require(`../static/guidelines/5.7.json`); -const guideln_latest = '5.7'; // update these two lines when guideline changes +guidelines[guideln_latest] = require(`../static/guidelines/${guideln_latest}.json`); export default async function () { @@ -66,8 +67,8 @@ export default async function () { // generate the fragment let fragment = `server=${server}&version=${form['version'].value}&config=${config}`; fragment += configs[server].usesOpenssl !== false ? `&openssl=${form['openssl'].value}` : ''; - fragment += configs[server].supportsHsts !== false && !form['hsts'].checked ? `&hsts=false` : ''; - fragment += supportsOcspStapling && !form['ocsp'].checked ? `&ocsp=false` : ''; + fragment += configs[server].supportsHsts !== false && form['hsts'].checked ? '&hsts' : ''; + fragment += supportsOcspStapling && form['ocsp'].checked ? '&ocsp' : ''; fragment += `&guideline=${guideln}`; // generate the version tags @@ -91,8 +92,8 @@ export default async function () { // generate the header const date = new Date().toISOString().substr(0, 10); let header = `generated ${date}, Mozilla Guideline v${guideln}, ${version_tags}`; - header += configs[server].supportsHsts !== false && !form['hsts'].checked ? `, no HSTS` : ''; - header += supportsOcspStapling && !form['ocsp'].checked ? `, no OCSP` : ''; + header += configs[server].supportsHsts !== false && form['hsts'].checked ? ', HSTS' : ''; + header += supportsOcspStapling && form['ocsp'].checked ? ', OCSP' : ''; const link = `${url.origin}${url.pathname}#${fragment}`; @@ -104,9 +105,13 @@ export default async function () { protocols = protocols.filter(ciphers => ciphers !== 'TLSv1.3'); } - let ciphers = configs[server].cipherFormat ? ssc.ciphers[configs[server].cipherFormat] : ssc.ciphers.openssl; - if (configs[server].supportedCiphers) { - ciphers = ciphers.filter(suite => configs[server].supportedCiphers.indexOf(suite) !== -1); + const cipherFormat = configs[server].cipherFormat ? configs[server].cipherFormat : 'openssl'; + let ciphers = cipherFormat === 'go' ? ssc.ciphers['iana'] : ssc.ciphers[cipherFormat]; + const supportedCiphers = configs[server].supportedCiphers + ? configs[server].supportedCiphers + : cipherFormat === 'go' ? configs['go'].supportedCiphers : null; + if (supportedCiphers) { + ciphers = ciphers.filter(suite => supportedCiphers.indexOf(suite) !== -1); } else { ciphers = ciphers; } @@ -131,13 +136,14 @@ export default async function () { ciphers, cipherSuites: ssc.ciphersuites, date, - dhCommand: ssc.dh_param_size >= 2048 ? `curl ${url.origin}/ffdhe${ssc.dh_param_size}.txt` : `openssl dhparam ${ssc.dh_param_size}`, + dhCommand: `curl ${url.origin}/ffdhe${ssc.dh_param_size}.txt`, dhParamSize: ssc.dh_param_size, fragment, hasVersions: configs[server].hasVersions !== false, header, hstsMaxAge: ssc.hsts_min_age, - hstsRedirectCode: 301, + //hstsRedirectCode: form['config'].value === 'old' ? 301 : 308, + hstsRedirectCode: 308, latestVersion: configs[server].latestVersion, link, oldestClients: ssc.oldest_clients, @@ -148,6 +154,8 @@ export default async function () { supportsHsts: configs[server].supportsHsts !== false, supportsOcspStapling: supportsOcspStapling, tlsCurves: ssc.tls_curves, + // XXX: If DHE ciphers removed from guidelines, then usesDhe, dhCommand, + // dhParamSize, and helpers/*.js code which uses them can be removed usesDhe: ciphers.join(":").includes(":DHE") || ciphers.join(":").includes("_DHE_"), usesOpenssl: configs[server].usesOpenssl !== false, }, diff --git a/src/static/guidelines/5.8.json b/src/static/guidelines/5.8.json new file mode 100644 index 00000000..2d18c51b --- /dev/null +++ b/src/static/guidelines/5.8.json @@ -0,0 +1,139 @@ +{ + "version": 5.8, + "href": "https://ssl-config.mozilla.org/guidelines/5.8.json", + "configurations": { + "modern": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa"], + "ciphers": { + "iana": [], + "openssl": [] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": null, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 90, + "ocsp_staple": true, + "oldest_clients": ["Firefox 63", "Android 10.0", "Chrome 70", "Edge 75", "Java 11", "OpenSSL 1.1.1", "Opera 57", "Safari 12.1"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": null, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.3"] + }, + "intermediate": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["sha256WithRSAEncryption", "ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa", "rsa"], + "ciphers": { + "iana": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + ], + "openssl": [ + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305" + ] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": 2048, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 366, + "ocsp_staple": true, + "oldest_clients": ["Firefox 31.3.0", "Android 4.4.2", "Chrome 49", "Edge 15 on Windows 10", "IE 11 on Windows 10", "Java 8u161", "OpenSSL 1.0.1l", "Opera 20", "Safari 9"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": 2048, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.2", "TLSv1.3"] + }, + "old": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["sha256WithRSAEncryption"], + "certificate_types": ["rsa"], + "ciphers": { + "iana": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + ], + "openssl": [ + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305", + "ECDHE-ECDSA-AES128-SHA256", + "ECDHE-RSA-AES128-SHA256", + "ECDHE-ECDSA-AES128-SHA", + "ECDHE-RSA-AES128-SHA", + "ECDHE-ECDSA-AES256-SHA384", + "ECDHE-RSA-AES256-SHA384", + "ECDHE-ECDSA-AES256-SHA", + "ECDHE-RSA-AES256-SHA", + "AES128-GCM-SHA256", + "AES256-GCM-SHA384", + "AES128-SHA256", + "AES256-SHA256", + "AES128-SHA", + "AES256-SHA", + "DES-CBC3-SHA" + ] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": 2048, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 366, + "ocsp_staple": true, + "oldest_clients": ["Firefox 1", "Android 2.3", "Chrome 1", "Edge 12", "IE8 on Windows XP", "Java 6", "OpenSSL 0.9.8", "Opera 5", "Safari 1"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": 2048, + "server_preferred_order": true, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"] + } + } +} diff --git a/src/static/guidelines/6.0.json b/src/static/guidelines/6.0.json new file mode 100644 index 00000000..d28853f2 --- /dev/null +++ b/src/static/guidelines/6.0.json @@ -0,0 +1,70 @@ +{ + "version": 6.0, + "href": "https://ssl-config.mozilla.org/guidelines/6.0.json", + "configurations": { + "modern": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa"], + "ciphers": { + "iana": [], + "openssl": [] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": null, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 90, + "ocsp_staple": true, + "oldest_clients": ["Firefox 63", "Android 10.0", "Chrome 70", "Edge 75", "Java 11", "OpenSSL 1.1.1", "Opera 57", "Safari 12.1"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": null, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.3"] + }, + "intermediate": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["sha256WithRSAEncryption", "ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa", "rsa"], + "ciphers": { + "iana": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + ], + "openssl": [ + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305" + ] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": 2048, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 366, + "ocsp_staple": true, + "oldest_clients": ["Firefox 27", "Android 4.4.2", "Chrome 31", "Edge", "IE 11 on Windows 7", "Java 8u31", "OpenSSL 1.0.1", "Opera 20", "Safari 9"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": 2048, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.2", "TLSv1.3"] + } + } +} diff --git a/src/static/guidelines/latest.json b/src/static/guidelines/latest.json index de06a35a..4cb7e59f 120000 --- a/src/static/guidelines/latest.json +++ b/src/static/guidelines/latest.json @@ -1 +1 @@ -5.7.json \ No newline at end of file +6.0.json \ No newline at end of file diff --git a/src/templates/index.ejs b/src/templates/index.ejs index dcac8c3d..79957ec0 100755 --- a/src/templates/index.ejs +++ b/src/templates/index.ejs @@ -69,6 +69,7 @@ General-purpose servers with a variety of clients, recommended for almost all systems +