Merge 0.9->0.10
[prosody.git] / util / x509.lua
index f106e6faa391133be143ec72fb5dd9d233881b10..f228b20130316e21e76f96b4e44d62dc9d2c0ebc 100644 (file)
 
 local nameprep = require "util.encodings".stringprep.nameprep;
 local idna_to_ascii = require "util.encodings".idna.to_ascii;
+local base64 = require "util.encodings".base64;
 local log = require "util.logger".init("x509");
-local pairs, ipairs = pairs, ipairs;
 local s_format = string.format;
-local t_insert = table.insert;
-local t_concat = table.concat;
 
-module "x509"
+local _ENV = nil;
 
 local oid_commonname = "2.5.4.3"; -- [LDAP] 2.3
 local oid_subjectaltname = "2.5.29.17"; -- [PKIX] 4.2.1.6
@@ -149,7 +147,10 @@ local function compare_srvname(host, service, asserted_names)
        return false
 end
 
-function verify_identity(host, service, cert)
+local function verify_identity(host, service, cert)
+       if cert.setencode then
+               cert:setencode("utf8");
+       end
        local ext = cert:extensions()
        if ext[oid_subjectaltname] then
                local sans = ext[oid_subjectaltname];
@@ -161,7 +162,9 @@ function verify_identity(host, service, cert)
 
                if sans[oid_xmppaddr] then
                        had_supported_altnames = true
-                       if compare_xmppaddr(host, sans[oid_xmppaddr]) then return true end
+                       if service == "_xmpp-client" or service == "_xmpp-server" then
+                               if compare_xmppaddr(host, sans[oid_xmppaddr]) then return true end
+                       end
                end
 
                if sans[oid_dnssrv] then
@@ -212,109 +215,27 @@ function verify_identity(host, service, cert)
        return false
 end
 
--- TODO Rename? Split out subroutines?
--- Also, this is probably openssl specific, what TODO about that?
-function genx509san(hosts, config, certhosts, raw) -- recive config through that or some better way?
-       local function utf8string(s)
-               -- This is how we tell openssl not to encode UTF-8 strings as Latin1
-               return s_format("FORMAT:UTF8,UTF8:%s", s);
-       end
-
-       local function ia5string(s)
-               return s_format("IA5STRING:%s", s);
-       end
-
-       local function dnsname(t, host)
-               t_insert(t.DNS, idna_to_ascii(host));
-       end
-
-       local function srvname(t, host, service)
-               t_insert(t.otherName, s_format("%s;%s", oid_dnssrv, ia5string("_" .. service .."." .. idna_to_ascii(host))));
-       end
-
-       local function xmppAddr(t, host)
-               t_insert(t.otherName, s_format("%s;%s", oid_xmppaddr, utf8string(host)));
-       end
-
-       -----------------------------
-
-       local san = {
-               DNS = {};
-               otherName = {};
-       };
-
-       local sslsanconf = { };
+local pat = "%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n"..
+"([0-9A-Za-z+/=\r\n]*)\r?\n%-%-%-%-%-END %1%-%-%-%-%-";
 
-       for i = 1,#certhosts do
-               local certhost = certhosts[i];
-               for name, host in pairs(hosts) do
-                       if name == certhost or name:sub(-1-#certhost) == "."..certhost then
-                               dnsname(san, name);
-                               --print(name .. "#component_module: " .. (config.get(name, "core", "component_module") or "nil"));
-                               if config.get(name, "core", "component_module") == nil then
-                                       srvname(san, name, "xmpp-client");
-                               end
-                               --print(name .. "#anonymous_login: " .. tostring(config.get(name, "core", "anonymous_login")));
-                               if not (config.get(name, "core", "anonymous_login") or
-                                               config.get(name, "core", "authentication") == "anonymous") then
-                                       srvname(san, name, "xmpp-server");
-                               end
-                               xmppAddr(san, name);
-                       end
-               end
-       end
-
-       for t, n in pairs(san) do
-               for i = 1,#n do
-                       t_insert(sslsanconf, s_format("%s.%d = %s", t, i -1, n[i]));
-               end
+local function pem2der(pem)
+       local typ, data = pem:match(pat);
+       if typ and data then
+               return base64.decode(data), typ;
        end
-
-       return raw and sslsanconf or t_concat(sslsanconf, "\n");
 end
 
-function baseconf()
-       return {
-               req = {
-                       distinguished_name = "distinguished_name",
-                       req_extensions = "v3_extensions",
-                       x509_extensions = "v3_extensions",
-                       prompt = "no",
-               },
-               distinguished_name = {
-                       commonName = "example.com",
-                       countryName = "GB",
-                       localityName = "The Internet",
-                       organizationName = "Your Organisation",
-                       organizationalUnitName = "XMPP Department",
-                       emailAddress = "xmpp@example.com",
-               },
-               v3_extensions = {
-                       basicConstraints = "CA:FALSE",
-                       keyUsage = "digitalSignature,keyEncipherment",
-                       extendedKeyUsage = "serverAuth,clientAuth",
-                       subjectAltName = "@subject_alternative_name",
-               },
-               subject_alternative_name = { },
-       }
-end
+local wrap = ('.'):rep(64);
+local envelope = "-----BEGIN %s-----\n%s\n-----END %s-----\n"
 
-function serialize_conf(conf)
-       local s = "";
-       for k, t in pairs(conf) do
-               s = s .. ("[%s]\n"):format(k);
-               if t[1] then
-                       for i, v in ipairs(t) do
-                               s = s .. ("%s\n"):format(v);
-                       end
-               else
-                       for k, v in pairs(t) do
-                               s = s .. ("%s = %s\n"):format(k, v);
-                       end
-               end
-               s = s .. "\n";
-       end
-       return s;
+local function der2pem(data, typ)
+       typ = typ and typ:upper() or "CERTIFICATE";
+       data = base64.encode(data);
+       return s_format(envelope, typ, data:gsub(wrap, '%0\n', (#data-1)/64), typ);
 end
 
-return _M;
+return {
+       verify_identity = verify_identity;
+       pem2der = pem2der;
+       der2pem = der2pem;
+};