1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 12:41:29 +00:00

Sort ciphers according to server preference, when available

David's code, adapted to current script.
This commit is contained in:
dmiller
2014-08-12 02:38:10 +00:00
parent 2df9a5f678
commit d538cc81cd

View File

@@ -1,5 +1,6 @@
local coroutine = require "coroutine"
local io = require "io"
local math = require "math"
local nmap = require "nmap"
local shortport = require "shortport"
local sslcert = require "sslcert"
@@ -224,6 +225,63 @@ local function remove(t, e)
return nil
end
local function slice(t, i, j)
local output = {}
while i <= j do
output[#output+1] = t[i]
i = i + 1
end
return output
end
local function merge(a, b, cmp)
local output = {}
local i = 1
local j = 1
while i <= #a and j <= #b do
local winner, err = cmp(a[i], b[j])
if not winner then
return nil, err
end
if winner == a[i] then
output[#output+1] = a[i]
i = i + 1
else
output[#output+1] = b[j]
j = j + 1
end
end
while i <= #a do
output[#output+1] = a[i]
i = i + 1
end
while j <= #b do
output[#output+1] = b[j]
j = j + 1
end
return output
end
local function merge_recursive(chunks, cmp)
if #chunks == 0 then
return {}
elseif #chunks == 1 then
return chunks[1]
else
local m = math.floor(#chunks / 2)
local a, b = slice(chunks, 1, m), slice(chunks, m+1, #chunks)
local am, err = merge_recursive(a, cmp)
if not am then
return nil, err
end
local bm, err = merge_recursive(b, cmp)
if not bm then
return nil, err
end
return merge(am, bm, cmp)
end
end
local function find_ciphers_group(host, port, protocol, group)
local name, protocol_worked, record, results
results = {}
@@ -428,6 +486,32 @@ local function find_cipher_preference(host, port, protocol, ciphers)
return "server", nil
end
-- Sort ciphers according to server preference with a modified merge sort
local function sort_ciphers(host, port, protocol, ciphers)
local chunks = {}
for _, group in ipairs(in_chunks(ciphers, CHUNK_SIZE)) do
local size = #group
local chunk = find_ciphers_group(host, port, protocol, group)
if not chunk then
return nil, "Network error"
end
if #chunk ~= size then
stdnse.debug1("%s warning: %d ciphers offered but only %d accepted", protocol, size, #chunk)
end
table.insert(chunks, chunk)
end
-- The comparison operator for the merge is a 2-cipher ClientHello.
local function cmp(cipher_a, cipher_b)
return compare_ciphers(host, port, protocol, cipher_a, cipher_b)
end
local sorted, err = merge_recursive(chunks, cmp)
if not sorted then
return nil, err
end
return sorted
end
local function try_protocol(host, port, protocol, upresults)
local ciphers, compressors, results
local condvar = nmap.condvar(upresults)
@@ -456,6 +540,21 @@ local function try_protocol(host, port, protocol, upresults)
-- Note the server's cipher preference algorithm.
local cipher_pref, cipher_pref_err = find_cipher_preference(host, port, protocol, ciphers)
-- Order ciphers according to server preference, if possible
if cipher_pref == "server" then
local sorted, err = sort_ciphers(host, port, protocol, ciphers)
if sorted then
ciphers = sorted
else
-- Can't sort, fall back to alphabetical order
table.sort(ciphers)
cipher_pref_err = err
end
else
-- fall back to alphabetical order
table.sort(ciphers)
end
-- Add rankings to ciphers
local cipherstr
for i, name in ipairs(ciphers) do
@@ -476,8 +575,6 @@ local function try_protocol(host, port, protocol, upresults)
ciphers[i]=outcipher
end
-- Format the cipher table.
table.sort(ciphers, function(a, b) return a["name"] < b["name"] end)
results["ciphers"] = ciphers
-- Format the compressor table.