diff --git a/nselib/sslcert.lua b/nselib/sslcert.lua index 7d87f7624..abfff62f7 100644 --- a/nselib/sslcert.lua +++ b/nselib/sslcert.lua @@ -36,16 +36,32 @@ local tableaux = require "tableaux" local tls = require "tls" local vnc = require "vnc" local xmpp = require "xmpp" +local have_openssl, openssl = pcall(require, "openssl") _ENV = stdnse.module("sslcert", stdnse.seeall) ---- Parse an X.509 certificate from DER-encoded string ---@name parse_ssl_certificate ---@class function ---@param der DER-encoded certificate ---@return table containing decoded certificate or nil on failure ---@return error string if parsing failed ---@see nmap.get_ssl_certificate -_ENV.parse_ssl_certificate = nmap.socket.parse_ssl_certificate +if have_openssl then + --- Parse an X.509 certificate from DER-encoded string + -- + -- This uses OpenSSL's X.509 parsing routines, so if OpenSSL support is not + -- included, only the pem key of the returned table will be + -- present. + --@name parse_ssl_certificate + --@class function + --@param der DER-encoded certificate + --@return table containing decoded certificate or nil on failure + --@return error string if parsing failed + --@see nmap.get_ssl_certificate + _ENV.parse_ssl_certificate = nmap.socket.parse_ssl_certificate +else + local base64 = require "base64" + _ENV.parse_ssl_certificate = function(der) + return { + pem = ("-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n"):format( + base64.enc(der):gsub("(" .. ("."):rep(64) .. ")", "%1\n"):gsub("\n$", "") + ) + } + end +end -- Mark whether this port supports STARTTLS, to save connection attempts later. -- If it ever succeeds, it can't be marked as failing later, but if it fails @@ -956,7 +972,8 @@ function getCertificate(host, port) local cert local wrapper = SPECIALIZED_WRAPPED_TLS_WITHOUT_RECONNECT[port.service] or SPECIALIZED_WRAPPED_TLS_WITHOUT_RECONNECT[port.number] - local specialized = SPECIALIZED_PREPARE_TLS[port.service] or SPECIALIZED_PREPARE_TLS[port.number] + local special_table = have_openssl and SPECIALIZED_PREPARE_TLS or SPECIALIZED_PREPARE_TLS_WITHOUT_RECONNECT + local specialized = special_table[port.service] or special_table[port.number] local status = false @@ -980,14 +997,18 @@ function getCertificate(host, port) if not status then stdnse.debug1("Specialized function error: %s", socket) else - cert = socket:get_ssl_certificate() - status = not not cert + if have_openssl then + cert = socket:get_ssl_certificate() + status = not not cert + else + status, cert = handshake_cert(socket) + end socket:close() end end -- Now try to connect with Nsock's SSL connection - if not status then + if not status and have_openssl then local socket = nmap.new_socket() local errmsg status, errmsg = socket:connect(host, port, "ssl") diff --git a/scripts/ssl-cert.nse b/scripts/ssl-cert.nse index b7608c1cb..05da23a51 100644 --- a/scripts/ssl-cert.nse +++ b/scripts/ssl-cert.nse @@ -212,6 +212,10 @@ local function name_to_table(name) end local function output_tab(cert) + if not have_openssl then + -- OpenSSL is required to parse the cert, so just dump the PEM + return {pem = cert.pem} + end local o = stdnse.output_table() o.subject = name_to_table(cert.subject) o.issuer = name_to_table(cert.issuer) @@ -241,6 +245,10 @@ local function output_tab(cert) end local function output_str(cert) + if not have_openssl then + -- OpenSSL is required to parse the cert, so just dump the PEM + return "OpenSSL required to parse certificate.\n" .. cert.pem + end local lines = {} lines[#lines + 1] = "Subject: " .. stringify_name(cert.subject)