diff --git a/CHANGELOG b/CHANGELOG index ab274d168..f94fbe312 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Fix a crash when parsing TLS certificates that OpenSSL doesn't support, + like DH certificates or corrupted certs. When this happens, ssl-enum-ciphers + will label the ciphersuite strength as "unknown." Reported by Bertrand + Bonnefoy-Claudet. [Daniel Miller] + o [NSE] Fix two issues in sslcert.lua that prevented correct operations against LDAP services when version detection or STARTTLS were used. [Tom Sellers] diff --git a/nse_ssl_cert.cc b/nse_ssl_cert.cc index 8446d0be6..6be29b9f7 100644 --- a/nse_ssl_cert.cc +++ b/nse_ssl_cert.cc @@ -134,6 +134,7 @@ #include #include #include +#include extern "C" { @@ -455,16 +456,15 @@ int lua_push_ecdhparams(lua_State *L, EVP_PKEY *pubkey) { nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); if (nid == NID_X9_62_prime_field) { lua_pushstring(L, "explicit_prime"); - lua_setfield(L, -2, "ec_curve_type"); } else if (nid == NID_X9_62_characteristic_two_field) { lua_pushstring(L, "explicit_char2"); - lua_setfield(L, -2, "ec_curve_type"); } else { /* Something weird happened. */ - return luaL_error(L, "Unknown EC field type in certificate."); + lua_pushstring(L, "UNKNOWN"); } + lua_setfield(L, -2, "ec_curve_type"); } lua_setfield(L, -2, "curve_params"); EC_KEY_free(ec_key); @@ -549,6 +549,11 @@ static int parse_ssl_cert(lua_State *L, X509 *cert) lua_setfield(L, -2, "pem"); pubkey = X509_get_pubkey(cert); + if (pubkey == NULL) { + lua_pushnil(L); + lua_pushfstring(L, "Error parsing cert: %s", ERR_error_string(ERR_get_error(), NULL)); + return 2; + } lua_newtable(L); #if OPENSSL_VERSION_NUMBER < 0x10100000L pkey_type = EVP_PKEY_type(pubkey->type); diff --git a/nselib/sslcert.lua b/nselib/sslcert.lua index d88d390c5..656e0eead 100644 --- a/nselib/sslcert.lua +++ b/nselib/sslcert.lua @@ -43,7 +43,8 @@ _ENV = stdnse.module("sslcert", stdnse.seeall) --@name parse_ssl_certificate --@class function --@param der DER-encoded certificate ---@return table containing decoded 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 @@ -893,10 +894,10 @@ function getCertificate(host, port) return false, "Server sent no certificate" end - cert = parse_ssl_certificate(certs.certificates[1]) + cert, err = parse_ssl_certificate(certs.certificates[1]) if not cert then mutex "done" - return false, "Unable to get cert" + return false, ("Unable to get cert: %s"):format(err) end else -- If we don't already know the service is TLS wrapped check to see if diff --git a/scripts/ssl-enum-ciphers.nse b/scripts/ssl-enum-ciphers.nse index 311b2774f..23db5a364 100644 --- a/scripts/ssl-enum-ciphers.nse +++ b/scripts/ssl-enum-ciphers.nse @@ -685,8 +685,10 @@ local function find_ciphers_group(host, port, protocol, group, scores) -- This may not always be the case, so -- TODO: reorder certificates and validate entire chain -- TODO: certificate validation (date, self-signed, etc) - local c = sslcert.parse_ssl_certificate(certs.certificates[1]) - if c.pubkey.type == kex.pubkey then + local c, err = sslcert.parse_ssl_certificate(certs.certificates[1]) + if not c then + stdnse.debug1("Failed to parse certificate: %s", err) + elseif c.pubkey.type == kex.pubkey then local sigalg = c.sig_algorithm:match("([mM][dD][245])") if sigalg then -- MD2 and MD5 are broken