From 5ba20f8a9b1e93a99e38aedf9ec83a4f18f330f3 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 4 Jan 2019 10:20:51 +0100 Subject: util.x509: Add function that extracts usable names from a certificate --- util/x509.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'util/x509.lua') diff --git a/util/x509.lua b/util/x509.lua index 15cc4d3c..1cdf07dc 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -20,6 +20,7 @@ local nameprep = require "util.encodings".stringprep.nameprep; local idna_to_ascii = require "util.encodings".idna.to_ascii; +local idna_to_unicode = require "util.encodings".idna.to_unicode; local base64 = require "util.encodings".base64; local log = require "util.logger".init("x509"); local s_format = string.format; @@ -216,6 +217,32 @@ local function verify_identity(host, service, cert) return false end +-- TODO Support other SANs +local function get_identities(cert) --> set of names + if cert.setencode then + cert:setencode("utf8"); + end + + local names = {}; + + local ext = cert:extensions(); + local sans = ext[oid_subjectaltname]; + if sans and sans["dNSName"] then + for i = 1, #sans["dNSName"] do + names[ idna_to_unicode(sans["dNSName"][i]) ] = true; + end + end + + local subject = cert:subject(); + for i = 1, #subject do + local dn = subject[i]; + if dn.oid == oid_commonname and nameprep(dn.value) then + names[dn.value] = true; + end + end + return names; +end + local pat = "%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n".. "([0-9A-Za-z+/=\r\n]*)\r?\n%-%-%-%-%-END %1%-%-%-%-%-"; @@ -237,6 +264,7 @@ end return { verify_identity = verify_identity; + get_identities = get_identities; pem2der = pem2der; der2pem = der2pem; }; -- cgit v1.2.3 From 4caae044218601c3abf448776a6c0909f9135bd8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 10 Sep 2019 18:16:11 +0200 Subject: util.x509: Nameprep commonName once --- util/x509.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'util/x509.lua') diff --git a/util/x509.lua b/util/x509.lua index 1cdf07dc..c4001ecb 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -236,8 +236,11 @@ local function get_identities(cert) --> set of names local subject = cert:subject(); for i = 1, #subject do local dn = subject[i]; - if dn.oid == oid_commonname and nameprep(dn.value) then - names[dn.value] = true; + if dn.oid == oid_commonname then + local name = nameprep(dn.value); + if name then + names[name] = true; + end end end return names; -- cgit v1.2.3 From 833d955c39a5bf1036e507f85d9893664efa6c7f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 10 Sep 2019 18:17:13 +0200 Subject: util.x509: Only collect commonNames that pass idna Weeds out "Example Certificate" and the like, which are uninteresting for this function. --- util/x509.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/x509.lua') diff --git a/util/x509.lua b/util/x509.lua index c4001ecb..82f8285d 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -238,7 +238,7 @@ local function get_identities(cert) --> set of names local dn = subject[i]; if dn.oid == oid_commonname then local name = nameprep(dn.value); - if name then + if name and idna_to_ascii(name) then names[name] = true; end end -- cgit v1.2.3 From 6a6b2fedcef0be190f63cfa1aca2183f3c225377 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 10 Sep 2019 18:41:36 +0200 Subject: util.x509: Return sets of services per identity --- util/x509.lua | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'util/x509.lua') diff --git a/util/x509.lua b/util/x509.lua index 82f8285d..fe6e4b79 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -23,7 +23,9 @@ local idna_to_ascii = require "util.encodings".idna.to_ascii; local idna_to_unicode = require "util.encodings".idna.to_unicode; local base64 = require "util.encodings".base64; local log = require "util.logger".init("x509"); +local mt = require "util.multitable"; local s_format = string.format; +local ipairs = ipairs; local _ENV = nil; -- luacheck: std none @@ -218,18 +220,43 @@ local function verify_identity(host, service, cert) end -- TODO Support other SANs -local function get_identities(cert) --> set of names +local function get_identities(cert) --> map of names to sets of services if cert.setencode then cert:setencode("utf8"); end - local names = {}; + local names = mt.new(); local ext = cert:extensions(); local sans = ext[oid_subjectaltname]; - if sans and sans["dNSName"] then - for i = 1, #sans["dNSName"] do - names[ idna_to_unicode(sans["dNSName"][i]) ] = true; + if sans then + if sans["dNSName"] then -- Valid for any service + for _, name in ipairs(sans["dNSName"]) do + name = idna_to_unicode(nameprep(name)); + if name then + names:set(name, "*", true); + end + end + end + if sans[oid_xmppaddr] then + for _, name in ipairs(sans[oid_xmppaddr]) do + name = nameprep(name); + if name then + names:set(name, "xmpp-client", true); + names:set(name, "xmpp-server", true); + end + end + end + if sans[oid_dnssrv] then + for _, srvname in ipairs(sans[oid_dnssrv]) do + local srv, name = srvname:match("^_([^.]+)%.(.*)"); + if srv then + name = nameprep(name); + if name then + names:set(name, srv, true); + end + end + end end end @@ -239,11 +266,11 @@ local function get_identities(cert) --> set of names if dn.oid == oid_commonname then local name = nameprep(dn.value); if name and idna_to_ascii(name) then - names[name] = true; + names:set("*", name, true); end end end - return names; + return names.data; end local pat = "%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n".. -- cgit v1.2.3 From 5ba23c972b8453806af6aeca573df96a366c68ef Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 8 Dec 2019 17:48:37 +0100 Subject: util.x509: Fix recording of CommonNames in get_identities Don't worry, this function is not used by anything yet, this isn't a security issue. It'll be used by Prosody to pick the correct certificate for itself in the future. The `names` multitable is a collection of (name, service) pairs but it put them in the wrong order here. --- util/x509.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/x509.lua') diff --git a/util/x509.lua b/util/x509.lua index fe6e4b79..342dafde 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -266,7 +266,7 @@ local function get_identities(cert) --> map of names to sets of services if dn.oid == oid_commonname then local name = nameprep(dn.value); if name and idna_to_ascii(name) then - names:set("*", name, true); + names:set(name, "*", true); end end end -- cgit v1.2.3