comparison core/certmanager.lua @ 14219:7f4fcbb1bbe4 13.0

certmanager: Drop embedded Mozilla TLSRef data in favour of util.tlsref This adds a 'tls_profile_version' configuration option. If unspecified, it will use the default profile version from util.tlsref. If specified, it must be either a valid version (known to util.tlsref) or the value "latest". This allows admins to pin to specific versions, go with the default (for the best balance between security/stability) or always use the latest available profiles.
author Matthew Wild <mwild1@gmail.com>
date Fri, 12 Jun 2026 13:04:23 +0100
parents 4aed38a1c971
children 565debd9c37a
comparison
equal deleted inserted replaced
14218:926f25af2ffe 14219:7f4fcbb1bbe4
9 local configmanager = require "prosody.core.configmanager"; 9 local configmanager = require "prosody.core.configmanager";
10 local log = require "prosody.util.logger".init("certmanager"); 10 local log = require "prosody.util.logger".init("certmanager");
11 local new_config = require"prosody.net.server".tls_builder; 11 local new_config = require"prosody.net.server".tls_builder;
12 local tls = require "prosody.net.tls_luasec"; 12 local tls = require "prosody.net.tls_luasec";
13 local stat = require "lfs".attributes; 13 local stat = require "lfs".attributes;
14
15 local tlsref = require "prosody.util.tlsref";
14 16
15 local x509 = require "prosody.util.x509"; 17 local x509 = require "prosody.util.x509";
16 local lfs = require "lfs"; 18 local lfs = require "lfs";
17 19
18 local tonumber, tostring = tonumber, tostring; 20 local tonumber, tostring = tonumber, tostring;
214 "!aNULL", -- Ciphers that does not authenticate the connection 216 "!aNULL", -- Ciphers that does not authenticate the connection
215 }; 217 };
216 dane = tls.features.capabilities.dane and configmanager.get("*", "use_dane") and { "no_ee_namechecks" }; 218 dane = tls.features.capabilities.dane and configmanager.get("*", "use_dane") and { "no_ee_namechecks" };
217 } 219 }
218 220
219 -- https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.1
220 local ffdhe2048 = [[
221 -----BEGIN DH PARAMETERS-----
222 MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
223 +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
224 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
225 YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
226 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
227 ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
228 -----END DH PARAMETERS-----
229 ]]
230
231 local mozilla_ssl_configs = {
232 -- https://wiki.mozilla.org/Security/Server_Side_TLS
233 -- Version 5.7 as of 2023-07-09
234 modern = {
235 protocol = "tlsv1_3";
236 options = { cipher_server_preference = false };
237 ciphers = "DEFAULT"; -- TLS 1.3 uses 'ciphersuites' rather than these
238 curveslist = { "X25519"; "prime256v1"; "secp384r1" };
239 ciphersuites = { "TLS_AES_128_GCM_SHA256"; "TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
240 };
241 intermediate = {
242 protocol = "tlsv1_2+";
243 dhparam = ffdhe2048;
244 options = { cipher_server_preference = false };
245 ciphers = {
246 "ECDHE-ECDSA-AES128-GCM-SHA256";
247 "ECDHE-RSA-AES128-GCM-SHA256";
248 "ECDHE-ECDSA-AES256-GCM-SHA384";
249 "ECDHE-RSA-AES256-GCM-SHA384";
250 "ECDHE-ECDSA-CHACHA20-POLY1305";
251 "ECDHE-RSA-CHACHA20-POLY1305";
252 "DHE-RSA-AES128-GCM-SHA256";
253 "DHE-RSA-AES256-GCM-SHA384";
254 "DHE-RSA-CHACHA20-POLY1305";
255 };
256 curveslist = { "X25519"; "prime256v1"; "secp384r1" };
257 ciphersuites = { "TLS_AES_128_GCM_SHA256"; "TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
258 };
259 old = {
260 protocol = "tlsv1+";
261 dhparam = nil; -- openssl dhparam 1024
262 options = { cipher_server_preference = true };
263 ciphers = {
264 "ECDHE-ECDSA-AES128-GCM-SHA256";
265 "ECDHE-RSA-AES128-GCM-SHA256";
266 "ECDHE-ECDSA-AES256-GCM-SHA384";
267 "ECDHE-RSA-AES256-GCM-SHA384";
268 "ECDHE-ECDSA-CHACHA20-POLY1305";
269 "ECDHE-RSA-CHACHA20-POLY1305";
270 "DHE-RSA-AES128-GCM-SHA256";
271 "DHE-RSA-AES256-GCM-SHA384";
272 "DHE-RSA-CHACHA20-POLY1305";
273 "ECDHE-ECDSA-AES128-SHA256";
274 "ECDHE-RSA-AES128-SHA256";
275 "ECDHE-ECDSA-AES128-SHA";
276 "ECDHE-RSA-AES128-SHA";
277 "ECDHE-ECDSA-AES256-SHA384";
278 "ECDHE-RSA-AES256-SHA384";
279 "ECDHE-ECDSA-AES256-SHA";
280 "ECDHE-RSA-AES256-SHA";
281 "DHE-RSA-AES128-SHA256";
282 "DHE-RSA-AES256-SHA256";
283 "AES128-GCM-SHA256";
284 "AES256-GCM-SHA384";
285 "AES128-SHA256";
286 "AES256-SHA256";
287 "AES128-SHA";
288 "AES256-SHA";
289 "DES-CBC3-SHA";
290 };
291 curveslist = { "X25519"; "prime256v1"; "secp384r1" };
292 ciphersuites = { "TLS_AES_128_GCM_SHA256"; "TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
293 };
294 };
295
296
297 if tls.features.curves then 221 if tls.features.curves then
298 for i = #core_defaults.curveslist, 1, -1 do 222 for i = #core_defaults.curveslist, 1, -1 do
299 if not tls.features.curves[ core_defaults.curveslist[i] ] then 223 if not tls.features.curves[ core_defaults.curveslist[i] ] then
300 t_remove(core_defaults.curveslist, i); 224 t_remove(core_defaults.curveslist, i);
301 end 225 end
319 cfg:apply({ 243 cfg:apply({
320 mode = mode, 244 mode = mode,
321 -- We can't read the password interactively when daemonized 245 -- We can't read the password interactively when daemonized
322 password = function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; 246 password = function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end;
323 }); 247 });
324 local profile = configmanager.get("*", "tls_profile") or "intermediate"; 248 local profile_version = configmanager.get("*", "tls_profile_version");
325 if mozilla_ssl_configs[profile] then 249 local profile_name = configmanager.get("*", "tls_profile");
326 cfg:apply(mozilla_ssl_configs[profile]); 250
327 elseif profile ~= "legacy" then 251 if profile_name ~= "legacy" then
328 log("error", "Invalid value for 'tls_profile': expected one of \"modern\", \"intermediate\" (default), \"old\" or \"legacy\" but got %q", profile); 252 local tls_profile, tls_profile_err = tlsref.get_profile(profile_version, profile_name);
329 return nil, "Invalid configuration, 'tls_profile' had an unknown value."; 253 if not tls_profile then
254 if tls_profile_err == "unknown-version" then
255 log(
256 "error",
257 "Invalid value %q for 'tls_profile_version': expected one of: \"%s\" or \"latest\"",
258 profile_version,
259 tlsref.get_valid_versions():concat("\", \"")
260 );
261 return nil, "Invalid configuration, 'tls_profile_version' had an unknown value.";
262 elseif tls_profile_err == "unknown-profile" then
263 log(
264 "error",
265 "Invalid value %q for 'tls_profile': expected one of \"%s\" or \"legacy\" (default: %q)",
266 profile_name,
267 tlsref.get_valid_profile_names(profile_version):concat("\", \""),
268 tlsref.get_default_profile_name(profile_version)
269 );
270 return nil, "Invalid configuration, 'tls_profile' had an unknown value.";
271 end
272 else
273 cfg:apply(tls_profile);
274 end
330 end 275 end
331 cfg:apply(global_ssl_config); 276 cfg:apply(global_ssl_config);
332 277
333 for i = select('#', ...), 1, -1 do 278 for i = select('#', ...), 1, -1 do
334 cfg:apply(select(i, ...)); 279 cfg:apply(select(i, ...));