Mercurial > prosody-hg
comparison core/certmanager.lua @ 5684:5554029d759b
certmanager: Overhaul of how ssl configs are built.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 13 Jun 2013 17:44:42 +0200 |
| parents | 51f7de1b6bb5 |
| children | 3137751751b4 |
comparison
equal
deleted
inserted
replaced
| 5683:624b874059bf | 5684:5554029d759b |
|---|---|
| 10 local log = require "util.logger".init("certmanager"); | 10 local log = require "util.logger".init("certmanager"); |
| 11 local ssl = ssl; | 11 local ssl = ssl; |
| 12 local ssl_newcontext = ssl and ssl.newcontext; | 12 local ssl_newcontext = ssl and ssl.newcontext; |
| 13 | 13 |
| 14 local tostring = tostring; | 14 local tostring = tostring; |
| 15 local pairs = pairs; | |
| 15 | 16 |
| 16 local prosody = prosody; | 17 local prosody = prosody; |
| 17 local resolve_path = configmanager.resolve_relative_path; | 18 local resolve_path = configmanager.resolve_relative_path; |
| 18 local config_path = prosody.paths.config; | 19 local config_path = prosody.paths.config; |
| 19 | 20 |
| 26 end | 27 end |
| 27 | 28 |
| 28 module "certmanager" | 29 module "certmanager" |
| 29 | 30 |
| 30 -- Global SSL options if not overridden per-host | 31 -- Global SSL options if not overridden per-host |
| 31 local default_ssl_config = configmanager.get("*", "ssl"); | 32 local global_ssl_config = configmanager.get("*", "ssl"); |
| 32 local default_capath = "/etc/ssl/certs"; | 33 |
| 33 local default_verify = (ssl and ssl.x509 and { "peer", "client_once", }) or "none"; | 34 local core_defaults = { |
| 34 local default_options = { "no_sslv2", luasec_has_noticket and "no_ticket" or nil }; | 35 capath = "/etc/ssl/certs"; |
| 35 local default_verifyext = { "lsec_continue", "lsec_ignore_purpose" }; | 36 protocol = "sslv23"; |
| 37 verify = (ssl and ssl.x509 and { "peer", "client_once", }) or "none"; | |
| 38 options = { "no_sslv2", luasec_has_noticket and "no_ticket" or nil }; | |
| 39 verifyext = { "lsec_continue", "lsec_ignore_purpose" }; | |
| 40 curve = "secp384r1"; | |
| 41 } | |
| 42 local path_options = { -- These we pass through resolve_path() | |
| 43 key = true, certificate = true, cafile = true, capath = true | |
| 44 } | |
| 36 | 45 |
| 37 if ssl and not luasec_has_verifyext and ssl.x509 then | 46 if ssl and not luasec_has_verifyext and ssl.x509 then |
| 38 -- COMPAT mw/luasec-hg | 47 -- COMPAT mw/luasec-hg |
| 39 for i=1,#default_verifyext do -- Remove lsec_ prefix | 48 for i=1,#core_defaults.verifyext do -- Remove lsec_ prefix |
| 40 default_verify[#default_verify+1] = default_verifyext[i]:sub(6); | 49 core_defaults.verify[#core_defaults.verify+1] = core_defaults.verifyext[i]:sub(6); |
| 41 end | 50 end |
| 42 end | 51 end |
| 52 | |
| 43 if luasec_has_no_compression and configmanager.get("*", "ssl_compression") ~= true then | 53 if luasec_has_no_compression and configmanager.get("*", "ssl_compression") ~= true then |
| 44 default_options[#default_options+1] = "no_compression"; | 54 core_defaults.options[#core_defaults.options+1] = "no_compression"; |
| 45 end | |
| 46 | |
| 47 if luasec_has_no_compression then -- Has no_compression? Then it has these too... | |
| 48 default_options[#default_options+1] = "single_dh_use"; | |
| 49 default_options[#default_options+1] = "single_ecdh_use"; | |
| 50 end | 55 end |
| 51 | 56 |
| 52 function create_context(host, mode, user_ssl_config) | 57 function create_context(host, mode, user_ssl_config) |
| 53 user_ssl_config = user_ssl_config or default_ssl_config; | 58 user_ssl_config = user_ssl_config or {} |
| 59 user_ssl_config.mode = mode; | |
| 54 | 60 |
| 55 if not ssl then return nil, "LuaSec (required for encryption) was not found"; end | 61 if not ssl then return nil, "LuaSec (required for encryption) was not found"; end |
| 56 if not user_ssl_config then return nil, "No SSL/TLS configuration present for "..host; end | 62 |
| 63 if global_ssl_config then | |
| 64 for option,default_value in pairs(global_ssl_config) do | |
| 65 if not user_ssl_config[option] then | |
| 66 user_ssl_config[option] = default_value; | |
| 67 end | |
| 68 end | |
| 69 end | |
| 70 for option,default_value in pairs(core_defaults) do | |
| 71 if not user_ssl_config[option] then | |
| 72 user_ssl_config[option] = default_value; | |
| 73 end | |
| 74 end | |
| 75 user_ssl_config.password = user_ssl_config.password or function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; | |
| 76 for option in pairs(path_options) do | |
| 77 user_ssl_config[option] = user_ssl_config[option] and resolve_path(config_path, user_ssl_config[option]); | |
| 78 end | |
| 79 | |
| 57 if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end | 80 if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end |
| 58 if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end | 81 if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end |
| 59 | |
| 60 local ssl_config = { | |
| 61 mode = mode; | |
| 62 protocol = user_ssl_config.protocol or "sslv23"; | |
| 63 key = resolve_path(config_path, user_ssl_config.key); | |
| 64 password = user_ssl_config.password or function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; | |
| 65 certificate = resolve_path(config_path, user_ssl_config.certificate); | |
| 66 capath = resolve_path(config_path, user_ssl_config.capath or default_capath); | |
| 67 cafile = resolve_path(config_path, user_ssl_config.cafile); | |
| 68 verify = user_ssl_config.verify or default_verify; | |
| 69 verifyext = user_ssl_config.verifyext or default_verifyext; | |
| 70 options = user_ssl_config.options or default_options; | |
| 71 depth = user_ssl_config.depth; | |
| 72 curve = user_ssl_config.curve or "secp384r1"; | |
| 73 dhparam = user_ssl_config.dhparam; | |
| 74 }; | |
| 75 | 82 |
| 76 local ctx, err = ssl_newcontext(ssl_config); | 83 local ctx, err = ssl_newcontext(user_ssl_config); |
| 77 | 84 |
| 78 -- LuaSec ignores the cipher list from the config, so we have to take care | 85 -- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care |
| 79 -- of it ourselves (W/A for #x) | 86 -- of it ourselves (W/A for #x) |
| 80 if ctx and user_ssl_config.ciphers then | 87 if ctx and user_ssl_config.ciphers then |
| 81 local success; | 88 local success; |
| 82 success, err = ssl.context.setcipher(ctx, user_ssl_config.ciphers); | 89 success, err = ssl.context.setcipher(ctx, user_ssl_config.ciphers); |
| 83 if not success then ctx = nil; end | 90 if not success then ctx = nil; end |
| 86 if not ctx then | 93 if not ctx then |
| 87 err = err or "invalid ssl config" | 94 err = err or "invalid ssl config" |
| 88 local file = err:match("^error loading (.-) %("); | 95 local file = err:match("^error loading (.-) %("); |
| 89 if file then | 96 if file then |
| 90 if file == "private key" then | 97 if file == "private key" then |
| 91 file = ssl_config.key or "your private key"; | 98 file = user_ssl_config.key or "your private key"; |
| 92 elseif file == "certificate" then | 99 elseif file == "certificate" then |
| 93 file = ssl_config.certificate or "your certificate file"; | 100 file = user_ssl_config.certificate or "your certificate file"; |
| 94 end | 101 end |
| 95 local reason = err:match("%((.+)%)$") or "some reason"; | 102 local reason = err:match("%((.+)%)$") or "some reason"; |
| 96 if reason == "Permission denied" then | 103 if reason == "Permission denied" then |
| 97 reason = "Check that the permissions allow Prosody to read this file."; | 104 reason = "Check that the permissions allow Prosody to read this file."; |
| 98 elseif reason == "No such file or directory" then | 105 elseif reason == "No such file or directory" then |
| 111 end | 118 end |
| 112 return ctx, err; | 119 return ctx, err; |
| 113 end | 120 end |
| 114 | 121 |
| 115 function reload_ssl_config() | 122 function reload_ssl_config() |
| 116 default_ssl_config = configmanager.get("*", "ssl"); | 123 global_ssl_config = configmanager.get("*", "ssl"); |
| 117 end | 124 end |
| 118 | 125 |
| 119 prosody.events.add_handler("config-reloaded", reload_ssl_config); | 126 prosody.events.add_handler("config-reloaded", reload_ssl_config); |
| 120 | 127 |
| 121 return _M; | 128 return _M; |
