lib/tls_map/app/extractor/extractor.rb in tls-map-2.1.0 vs lib/tls_map/app/extractor/extractor.rb in tls-map-2.2.0
- old
+ new
@@ -10,25 +10,28 @@
module TLSmap
class App
# External tools output data extractor
#
# Output files from [SSLyze][1] (JSON), [sslscan2][2] (XML), [testssl.sh][3] (JSON), [ssllabs-scan][4] (JSON)
+ # , [tlsx][5] (JSON)
#
# [1]:https://github.com/nabla-c0d3/sslyze
# [2]:https://github.com/rbsec/sslscan
# [3]:https://github.com/drwetter/testssl.sh
# [4]:https://github.com/ssllabs/ssllabs-scan
+ # [5]:https://github.com/projectdiscovery/tlsx
#
# Example of commands:
#
# - `sslyze --json_out=example.org.json example.org`
# - `sslscan2 --show-cipher-ids --xml=example.org.xml example.org`
# - `--show-cipher-ids` is mandatory else ciphers are not saved to the output
# - `testssl --jsonfile-pretty example.org.json --mapping no-openssl --cipher-per-proto example.org`
# - json-pretty is the only supported format, default json or csv, html won't work
# - `ssllabs-scan --quiet example.org > example.org.json`
# - The default output is the only supported format, using `-json-flat` won't work
+ # - `tlsx -u example.org -cipher-enum -o example.org.json -j -sm ctls`
class Extractor
# Get the list of ciphers extracted from the tool output file
# @return [Array<String>] Cipher array (IANA names)
attr_reader :ciphers
@@ -72,11 +75,11 @@
def tls13
@ciphers['TLS1.3']
end
# Extract the ciphers from the tool output file
- # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan`
+ # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan`, `tlsx`
# @param file [String] Path of the tool output file, beware of the format expected. See {TLSmap::App::Extractor}
# @return [Array<String>] Cipher array (IANA names)
def parse(tool, file)
# Convert string to class
@ciphers = Object.const_get("TLSmap::App::Extractor::#{normalize(tool)}").parse(file)
@@ -87,15 +90,16 @@
# Commands for {helper}
CMD = {
'sslyze' => 'sslyze --json_out=example.org.json example.org',
'sslscan2' => 'sslscan2 --show-cipher-ids --xml=example.org.xml example.org',
'testssl' => 'testssl --jsonfile-pretty example.org.json --mapping no-openssl --cipher-per-proto example.org',
- 'ssllabs-scan' => 'ssllabs-scan --quiet example.org > example.org.json'
+ 'ssllabs-scan' => 'ssllabs-scan --quiet example.org > example.org.json',
+ 'tlsx' => 'tlsx -u example.org -cipher-enum -o example.org.json -j -sm ctls'
}.freeze
# Get the external tool command used to generate the expected result format
- # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan`
+ # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan`, `tlsx`
# @return [String] external tool command used to generate the expected result format used in input of the extract
# command (CLI) / {parse} method (library)
def helper(tool)
intro = 'You may not be provinding the right format.'
outro = 'See https://noraj.github.io/tls-map/yard/TLSmap/App/Extractor'
@@ -262,9 +266,54 @@
# @return [String] protocol name in TLSmap format
def id2prot(id)
prot = {
512 => 'SSL2.0', 768 => 'SSL3.0', 769 => 'TLS1.0',
770 => 'TLS1.1', 771 => 'TLS1.2', 772 => 'TLS1.3'
+ }
+ prot[id]
+ end
+
+ protected :extract_cipher, :id2prot
+ end
+ end
+
+ # Parsing tlsx
+ class Tlsx
+ class << self
+ # Extract the ciphers from the tlsx output file
+ # @param file [String] Path of the tlsx output file, beware of the format expected.
+ # See {TLSmap::App::Extractor}
+ # @return [Array<String>] Cipher array (IANA names)
+ def parse(file)
+ data = Utils.json_load_file(file)
+ extract_cipher(data)
+ end
+
+ # Extract the ciphers from the tlsx output file
+ # @param json_data [Hash] Ruby hash of the parsed JSON
+ # @return [Array<String>] Cipher array (IANA names)
+ def extract_cipher(json_data) # rubocop:disable Metrics/MethodLength
+ raw = {
+ 'SSL2.0' => [], 'SSL3.0' => [],
+ 'TLS1.0' => [], 'TLS1.1' => [], 'TLS1.2' => [], 'TLS1.3' => []
+ }
+ json_data['cipher_enum'].each do |version|
+ next if version['ciphers'].nil?
+
+ version['ciphers'].each do |cipher|
+ raw[id2prot(version['version'])].push(cipher)
+ end
+ end
+ raw.transform_values(&:uniq)
+ end
+
+ # Convert tlsx protocol id to protocol name in TLSmap format
+ # @param id [String] tlsx protocol id
+ # @return [String] protocol name in TLSmap format
+ def id2prot(id)
+ prot = {
+ 'ssl30' => 'SSL3.0', 'tls10' => 'TLS1.0',
+ 'tls11' => 'TLS1.1', 'tls12' => 'TLS1.2', 'tls13' => 'TLS1.3'
}
prot[id]
end
protected :extract_cipher, :id2prot