mirror of
https://github.com/nmap/nmap.git
synced 2026-08-03 22:29:06 +00:00
Convert tls.lua from bin.(un)pack to Lua 5.3 string.(un)pack
This commit is contained in:
parent
dbc995b883
commit
0df1867dd1
1 changed files with 63 additions and 80 deletions
143
nselib/tls.lua
143
nselib/tls.lua
|
|
@ -7,12 +7,15 @@
|
|||
-- @author Daniel Miller
|
||||
|
||||
local stdnse = require "stdnse"
|
||||
local bin = require "bin"
|
||||
local string = require "string"
|
||||
local math = require "math"
|
||||
local os = require "os"
|
||||
local table = require "table"
|
||||
_ENV = stdnse.module("tls", stdnse.seeall)
|
||||
|
||||
local pack = string.pack
|
||||
local unpack = string.unpack
|
||||
|
||||
-- Most of the values in the tables below are from:
|
||||
-- http://www.iana.org/assignments/tls-parameters/
|
||||
PROTOCOLS = {
|
||||
|
|
@ -211,7 +214,7 @@ EXTENSION_HELPERS = {
|
|||
["server_name"] = function (server_name)
|
||||
-- Only supports host_name type (0), as per RFC
|
||||
-- Support for other types could be added later
|
||||
return bin.pack(">P", bin.pack(">CP", 0, server_name))
|
||||
return pack(">s2", pack(">Bs2", 0, server_name))
|
||||
end,
|
||||
["max_fragment_length"] = tostring,
|
||||
["client_certificate_url"] = tostring,
|
||||
|
|
@ -221,26 +224,26 @@ EXTENSION_HELPERS = {
|
|||
["elliptic_curves"] = function (elliptic_curves)
|
||||
local list = {}
|
||||
for _, name in ipairs(elliptic_curves) do
|
||||
list[#list+1] = bin.pack(">S", ELLIPTIC_CURVES[name])
|
||||
list[#list+1] = pack(">I2", ELLIPTIC_CURVES[name])
|
||||
end
|
||||
return bin.pack(">P", table.concat(list))
|
||||
return pack(">s2", table.concat(list))
|
||||
end,
|
||||
["ec_point_formats"] = function (ec_point_formats)
|
||||
local list = {}
|
||||
for _, format in ipairs(ec_point_formats) do
|
||||
list[#list+1] = bin.pack(">C", EC_POINT_FORMATS[format])
|
||||
list[#list+1] = pack(">B", EC_POINT_FORMATS[format])
|
||||
end
|
||||
return bin.pack(">p", table.concat(list))
|
||||
return pack(">s1", table.concat(list))
|
||||
end,
|
||||
["signature_algorithms"] = function(signature_algorithms)
|
||||
local list = {}
|
||||
for _, pair in ipairs(signature_algorithms) do
|
||||
list[#list+1] = bin.pack(">CC",
|
||||
list[#list+1] = pack(">BB",
|
||||
HashAlgorithms[pair[1]] or pair[1],
|
||||
SignatureAlgorithms[pair[2]] or pair[2]
|
||||
)
|
||||
end
|
||||
return bin.pack(">P", table.concat(list))
|
||||
return pack(">s2", table.concat(list))
|
||||
end,
|
||||
["next_protocol_negotiation"] = tostring,
|
||||
}
|
||||
|
|
@ -691,18 +694,18 @@ local cipher_info_cache = {
|
|||
-- A couple helpers for server_key_exchange parsing
|
||||
local function unpack_dhparams (blob, pos)
|
||||
local p, g, y
|
||||
pos, p, g, y = bin.unpack(">PPP", blob, pos)
|
||||
p, g, y, pos = unpack(">s2s2s2", blob, pos)
|
||||
return pos, {p=p, g=g, y=y}, #p * 8
|
||||
end
|
||||
|
||||
local function unpack_ecdhparams (blob, pos)
|
||||
local eccurvetype
|
||||
pos, eccurvetype = bin.unpack("C", blob, pos)
|
||||
eccurvetype, pos = unpack("B", blob, pos)
|
||||
local ret = {}
|
||||
local strength
|
||||
if eccurvetype == 1 then
|
||||
local p, a, b, base, order, cofactor
|
||||
pos, p, a, b, base, order, cofactor = bin.unpack("pppppp", blob, pos)
|
||||
p, a, b, base, order, cofactor, pos = unpack("s1s1s1s1s1s1", blob, pos)
|
||||
strength = math.log(order, 2)
|
||||
ret.curve_params = {
|
||||
ec_curve_type = "explicit_prime",
|
||||
|
|
@ -711,14 +714,14 @@ local function unpack_ecdhparams (blob, pos)
|
|||
elseif eccurvetype == 2 then
|
||||
local p = {}
|
||||
local m, basis
|
||||
pos, m, basis = bin.unpack(">SC", blob, pos)
|
||||
m, basis, pos = unpack(">I2B", blob, pos)
|
||||
if basis == 1 then -- ec_trinomial
|
||||
pos, p.k = bin.unpack("p", blob, pos)
|
||||
p.k, pos = unpack("s1", blob, pos)
|
||||
elseif basis == 2 then -- ec_pentanomial
|
||||
pos, p.k1, p.k2, p.k3 = bin.unpack("ppp", blob, pos)
|
||||
p.k1, p.k2, p.k3, pos = unpack("s1s1s1", blob, pos)
|
||||
end
|
||||
local a, b, base, order, cofactor
|
||||
pos, a, b, base, order, cofactor = bin.unpack("ppppp", blob, pos)
|
||||
a, b, base, order, cofactor, pos = unpack("s1s1s1s1s1", blob, pos)
|
||||
strength = math.log(order, 2)
|
||||
ret.curve_params = {
|
||||
ec_curve_type = "explicit_char2",
|
||||
|
|
@ -726,7 +729,7 @@ local function unpack_ecdhparams (blob, pos)
|
|||
}
|
||||
elseif eccurvetype == 3 then
|
||||
local curve
|
||||
pos, curve = bin.unpack(">S", blob, pos)
|
||||
curve, pos = unpack(">I2", blob, pos)
|
||||
ret.curve_params = {
|
||||
ec_curve_type = "namedcurve",
|
||||
curve = find_key(ELLIPTIC_CURVES, curve)
|
||||
|
|
@ -736,7 +739,7 @@ local function unpack_ecdhparams (blob, pos)
|
|||
strength = tonumber(size)
|
||||
end
|
||||
end
|
||||
pos, ret.public = bin.unpack("p", blob, pos)
|
||||
ret.public, pos = unpack("s1", blob, pos)
|
||||
return pos, ret, strength
|
||||
end
|
||||
|
||||
|
|
@ -747,9 +750,9 @@ local function unpack_signed (blob, pos, protocol)
|
|||
local hash_alg, sig_alg, sig
|
||||
-- TLSv1.2 changed to allow arbitrary hash and sig algorithms
|
||||
if protocol and PROTOCOLS[protocol] >= 0x0303 then
|
||||
pos, hash_alg, sig_alg, sig = bin.unpack("CC>P", blob, pos)
|
||||
hash_alg, sig_alg, sig, pos = unpack(">BBs2", blob, pos)
|
||||
else
|
||||
pos, sig = bin.unpack(">P", blob, pos)
|
||||
sig, pos = unpack(">s2", blob, pos)
|
||||
end
|
||||
return pos, {hash_algorithm=hash_alg, signature_algorithm=sig_alg, signature=sig}
|
||||
end
|
||||
|
|
@ -830,7 +833,7 @@ KEX_ALGORITHMS.RSA_EXPORT = {
|
|||
server_key_exchange = function (blob, protocol)
|
||||
local pos
|
||||
local ret = {rsa={}}
|
||||
pos, ret.rsa.modulus, ret.rsa.exponent = bin.unpack(">PP", blob)
|
||||
ret.rsa.modulus, ret.rsa.exponent, pos = unpack(">s2s2", blob)
|
||||
pos, ret.signed = unpack_signed(blob, pos, protocol)
|
||||
ret.strength = #ret.rsa.modulus
|
||||
return ret
|
||||
|
|
@ -915,7 +918,7 @@ KEX_ALGORITHMS.ECMQV_ECDSA={
|
|||
server_key_exchange = function (blob, protocol)
|
||||
local pos
|
||||
local ret = {}
|
||||
pos, ret.mqvparams = bin.unpack("p", blob)
|
||||
ret.mqvparams, pos = unpack("s1", blob)
|
||||
return ret
|
||||
end
|
||||
}
|
||||
|
|
@ -927,7 +930,7 @@ KEX_ALGORITHMS.ECMQV_ECNRA={
|
|||
KEX_ALGORITHMS.PSK = {
|
||||
type = "psk",
|
||||
server_key_exchange = function (blob, protocol)
|
||||
local pos, hint = bin.unpack(">P", blob)
|
||||
local hint, pos = unpack(">s2", blob)
|
||||
return {psk_identity_hint=hint}
|
||||
end
|
||||
}
|
||||
|
|
@ -941,7 +944,7 @@ KEX_ALGORITHMS.DHE_PSK = {
|
|||
server_key_exchange = function (blob, protocol)
|
||||
local pos
|
||||
local ret = {}
|
||||
pos, ret.psk_identity_hint = bin.unpack(">P", blob)
|
||||
ret.psk_identity_hint, pos = unpack(">s2", blob)
|
||||
pos, ret.dhparams, ret.strength = unpack_dhparams(blob, pos)
|
||||
return ret
|
||||
end
|
||||
|
|
@ -955,7 +958,7 @@ KEX_ALGORITHMS.ECDHE_PSK={
|
|||
server_key_exchange = function (blob, protocol)
|
||||
local pos
|
||||
local ret = {}
|
||||
pos, ret.psk_identity_hint = bin.unpack(">P", blob)
|
||||
ret.psk_identity_hint, pos = unpack(">s2", blob)
|
||||
pos, ret.ecdhparams, ret.strength = unpack_ecdhparams(blob, pos)
|
||||
return ret
|
||||
end
|
||||
|
|
@ -967,7 +970,7 @@ KEX_ALGORITHMS.SRP_SHA = {
|
|||
server_key_exchange = function (blob, protocol)
|
||||
local pos
|
||||
local ret = {srp={}}
|
||||
pos, ret.srp.N, ret.srp.g, ret.srp.s, ret.srp.B = bin.unpack(">PPpP", blob)
|
||||
ret.srp.N, ret.srp.g, ret.srp.s, ret.srp.B, pos = unpack(">s2s2s1s2", blob)
|
||||
pos, ret.signed = unpack_signed(blob, pos, protocol)
|
||||
ret.strength = #ret.srp.N
|
||||
return ret
|
||||
|
|
@ -1111,13 +1114,6 @@ SCSVS = {
|
|||
["TLS_FALLBACK_SCSV"] = 0x5600, -- draft-ietf-tls-downgrade-scsv-00
|
||||
}
|
||||
|
||||
-- Helper function to unpack a 3-byte integer value
|
||||
local function unpack_3byte (buffer, pos)
|
||||
local low, high
|
||||
pos, high, low = bin.unpack("C>S", buffer, pos)
|
||||
return pos, low + high * 0x10000
|
||||
end
|
||||
|
||||
---
|
||||
-- Read a SSL/TLS record
|
||||
-- @param buffer The read buffer
|
||||
|
|
@ -1140,7 +1136,7 @@ function record_read(buffer, i, fragment)
|
|||
|
||||
-- Parse header.
|
||||
h = {}
|
||||
local j, typ, proto = bin.unpack(">CS", buffer, i)
|
||||
local typ, proto, j = unpack(">BI2", buffer, i)
|
||||
local name = find_key(TLS_CONTENTTYPE_REGISTRY, typ)
|
||||
if name == nil then
|
||||
stdnse.debug1("Unknown TLS ContentType: %d", typ)
|
||||
|
|
@ -1154,7 +1150,7 @@ function record_read(buffer, i, fragment)
|
|||
end
|
||||
h["protocol"] = name
|
||||
|
||||
j, h["length"] = bin.unpack(">S", buffer, j)
|
||||
h["length"], j = unpack(">I2", buffer, j)
|
||||
|
||||
-- Ensure we have enough data for the body.
|
||||
len = j + h["length"] - 1
|
||||
|
|
@ -1184,8 +1180,7 @@ function record_read(buffer, i, fragment)
|
|||
b = {}
|
||||
if h["type"] == "alert" then
|
||||
-- Parse body.
|
||||
j, b["level"] = bin.unpack("C", buffer, j)
|
||||
j, b["description"] = bin.unpack("C", buffer, j)
|
||||
b.level, b.description, j = unpack("BB", buffer, j)
|
||||
|
||||
-- Convert to human-readable form.
|
||||
b["level"] = find_key(TLS_ALERT_LEVELS, b["level"])
|
||||
|
|
@ -1201,9 +1196,8 @@ function record_read(buffer, i, fragment)
|
|||
end
|
||||
|
||||
-- Parse body.
|
||||
j, b["type"] = bin.unpack("C", buffer, j)
|
||||
local msg_end
|
||||
j, msg_end = unpack_3byte(buffer, j)
|
||||
b.type, msg_end, j = unpack("B>I3", buffer, j)
|
||||
msg_end = msg_end + j
|
||||
|
||||
-- Convert to human-readable form.
|
||||
|
|
@ -1217,24 +1211,19 @@ function record_read(buffer, i, fragment)
|
|||
|
||||
if b["type"] == "server_hello" then
|
||||
-- Parse body.
|
||||
j, b["protocol"] = bin.unpack(">S", buffer, j)
|
||||
j, b["time"] = bin.unpack(">I", buffer, j)
|
||||
j, b["random"] = bin.unpack("A28", buffer, j)
|
||||
j, b["session_id_length"] = bin.unpack("C", buffer, j)
|
||||
j, b["session_id"] = bin.unpack("A" .. b["session_id_length"], buffer, j)
|
||||
j, b["cipher"] = bin.unpack(">S", buffer, j)
|
||||
j, b["compressor"] = bin.unpack("C", buffer, j)
|
||||
b.protocol, b.time, b.random, b.session_id, j = unpack(">I2 I4 c28 s1", buffer, j)
|
||||
b.cipher, b.compressor, j = unpack(">I2 B", buffer, j)
|
||||
-- Optional extensions for TLS only
|
||||
if j < msg_end and h["protocol"] ~= "SSLv3" then
|
||||
local num_exts
|
||||
b["extensions"] = {}
|
||||
j, num_exts = bin.unpack(">S", buffer, j)
|
||||
num_exts, j = unpack(">I2", buffer, j)
|
||||
for e = 0, num_exts do
|
||||
if j >= msg_end then break end
|
||||
local extcode, datalen
|
||||
j, extcode = bin.unpack(">S", buffer, j)
|
||||
extcode, j = unpack(">I2", buffer, j)
|
||||
extcode = find_key(EXTENSIONS, extcode) or extcode
|
||||
j, b["extensions"][extcode] = bin.unpack(">P", buffer, j)
|
||||
b["extensions"][extcode], j = unpack(">s2", buffer, j)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1244,7 +1233,7 @@ function record_read(buffer, i, fragment)
|
|||
b["compressor"] = find_key(COMPRESSORS, b["compressor"])
|
||||
elseif b["type"] == "certificate" then
|
||||
local cert_end
|
||||
j, cert_end = unpack_3byte(buffer, j)
|
||||
cert_end, j = unpack(">I3", buffer, j)
|
||||
cert_end = cert_end + j
|
||||
if cert_end > msg_end then
|
||||
stdnse.debug2("server_certificate length > handshake body length!")
|
||||
|
|
@ -1252,21 +1241,19 @@ function record_read(buffer, i, fragment)
|
|||
b["certificates"] = {}
|
||||
while j < cert_end do
|
||||
local cert_len, cert
|
||||
j, cert_len = unpack_3byte(buffer, j)
|
||||
j, cert = bin.unpack("A" .. cert_len, buffer, j)
|
||||
cert, j = unpack(">s3", buffer, j)
|
||||
-- parse these with sslcert.parse_ssl_certificate
|
||||
table.insert(b["certificates"], cert)
|
||||
end
|
||||
else
|
||||
-- TODO: implement other handshake message types
|
||||
stdnse.debug2("Unknown handshake message type: %s", b["type"])
|
||||
j, b["data"] = bin.unpack("A" .. msg_end - j, buffer, j)
|
||||
b.data, j = unpack("c" .. msg_end - j, buffer, j)
|
||||
end
|
||||
|
||||
table.insert(h["body"], b)
|
||||
elseif h["type"] == "heartbeat" then
|
||||
j, b["type"], b["payload_length"] = bin.unpack("C>S", buffer, j)
|
||||
j, b["payload"], b["padding"] = bin.unpack("PP", buffer, j)
|
||||
b.type, b.payload_length, b.payload, b.padding, j = unpack(">B I2 s2 s2", buffer, j)
|
||||
table.insert(h["body"], b)
|
||||
else
|
||||
stdnse.debug1("Unknown message type: %s", h["type"])
|
||||
|
|
@ -1288,12 +1275,11 @@ end
|
|||
function record_write(type, protocol, b)
|
||||
return table.concat({
|
||||
-- Set the header as a handshake.
|
||||
bin.pack("C", TLS_CONTENTTYPE_REGISTRY[type]),
|
||||
pack("B", TLS_CONTENTTYPE_REGISTRY[type]),
|
||||
-- Set the protocol.
|
||||
bin.pack(">S", PROTOCOLS[protocol]),
|
||||
pack(">I2", PROTOCOLS[protocol]),
|
||||
-- Set the length of the header body.
|
||||
bin.pack(">S", #b),
|
||||
b
|
||||
pack(">s2", b)
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -1336,10 +1322,11 @@ function client_hello(t)
|
|||
b = {}
|
||||
-- Set the protocol.
|
||||
local protocol = t["protocol"] or HIGHEST_PROTOCOL
|
||||
table.insert(b, bin.pack(">S", PROTOCOLS[protocol]))
|
||||
|
||||
-- Set the random data.
|
||||
table.insert(b, bin.pack(">I", os.time()))
|
||||
table.insert(b, pack(">I2 I4",
|
||||
PROTOCOLS[protocol],
|
||||
-- Set the random data.
|
||||
os.time()
|
||||
))
|
||||
|
||||
-- Set the random data.
|
||||
table.insert(b, stdnse.generate_random_string(28))
|
||||
|
|
@ -1355,12 +1342,12 @@ function client_hello(t)
|
|||
cipher = CIPHERS[cipher] or SCSVS[cipher]
|
||||
end
|
||||
if type(cipher) == "number" and cipher >= 0 and cipher <= 0xffff then
|
||||
table.insert(ciphers, bin.pack(">S", cipher))
|
||||
table.insert(ciphers, pack(">I2", cipher))
|
||||
else
|
||||
stdnse.debug1("Unknown cipher in client_hello: %s", cipher)
|
||||
end
|
||||
end
|
||||
table.insert(b, bin.pack(">P", table.concat(ciphers)))
|
||||
table.insert(b, pack(">s2", table.concat(ciphers)))
|
||||
|
||||
-- Compression methods.
|
||||
compressors = {}
|
||||
|
|
@ -1368,13 +1355,13 @@ function client_hello(t)
|
|||
-- Add specified compressors.
|
||||
for _, compressor in pairs(t["compressors"]) do
|
||||
if compressor ~= "NULL" then
|
||||
table.insert(compressors, bin.pack("C", COMPRESSORS[compressor]))
|
||||
table.insert(compressors, pack("B", COMPRESSORS[compressor]))
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Always include NULL as last choice
|
||||
table.insert(compressors, bin.pack("C", COMPRESSORS["NULL"]))
|
||||
table.insert(b, bin.pack(">p", table.concat(compressors)))
|
||||
table.insert(compressors, pack("B", COMPRESSORS["NULL"]))
|
||||
table.insert(b, pack("s1", table.concat(compressors)))
|
||||
|
||||
-- TLS extensions
|
||||
if PROTOCOLS[protocol] and protocol ~= "SSLv3" then
|
||||
|
|
@ -1385,23 +1372,23 @@ function client_hello(t)
|
|||
-- Add specified extensions.
|
||||
for extension, data in pairs(t["extensions"]) do
|
||||
if type(extension) == "number" then
|
||||
table.insert(extensions, bin.pack(">S", extension))
|
||||
table.insert(extensions, pack(">I2", extension))
|
||||
else
|
||||
if extension == "signature_algorithms" then
|
||||
need_sigalg = false
|
||||
end
|
||||
table.insert(extensions, bin.pack(">S", EXTENSIONS[extension]))
|
||||
table.insert(extensions, pack(">I2", EXTENSIONS[extension]))
|
||||
end
|
||||
table.insert(extensions, bin.pack(">P", data))
|
||||
table.insert(extensions, pack(">s2", data))
|
||||
end
|
||||
if need_sigalg then
|
||||
table.insert(extensions, bin.pack(">S", EXTENSIONS["signature_algorithms"]))
|
||||
table.insert(extensions, bin.pack(">P", signature_algorithms_all))
|
||||
table.insert(extensions, pack(">I2", EXTENSIONS["signature_algorithms"]))
|
||||
table.insert(extensions, pack(">s2", signature_algorithms_all))
|
||||
end
|
||||
end
|
||||
-- Extensions are optional
|
||||
if #extensions ~= 0 then
|
||||
table.insert(b, bin.pack(">P", table.concat(extensions)))
|
||||
table.insert(b, pack(">s2", table.concat(extensions)))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1414,14 +1401,10 @@ function client_hello(t)
|
|||
h = {}
|
||||
|
||||
-- Set type to ClientHello.
|
||||
table.insert(h, bin.pack("C", TLS_HANDSHAKETYPE_REGISTRY["client_hello"]))
|
||||
table.insert(h, pack("B", TLS_HANDSHAKETYPE_REGISTRY["client_hello"]))
|
||||
|
||||
-- Set the length of the body.
|
||||
len = bin.pack(">I", #b)
|
||||
-- body length is 24 bits big-endian, so the 3 LSB of len
|
||||
table.insert(h, len:sub(2,4))
|
||||
|
||||
table.insert(h, b)
|
||||
table.insert(h, pack(">s3", b))
|
||||
|
||||
-- Record layer version should be SSLv3 (lowest compatible record version)
|
||||
return record_write("handshake", "SSLv3", table.concat(h))
|
||||
|
|
@ -1466,7 +1449,7 @@ function record_buffer(sock, buffer, i)
|
|||
count = count + #resp
|
||||
end
|
||||
-- ContentType, ProtocolVersion, length
|
||||
local _, _, _, len = bin.unpack(">CSS", buffer, i)
|
||||
local _, _, len = unpack(">BI2I2", buffer, i)
|
||||
if count < TLS_RECORD_HEADER_LENGTH + len then
|
||||
status, resp = read_atleast(sock, TLS_RECORD_HEADER_LENGTH + len - count)
|
||||
if not status then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue