tls-map 1.3.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0eadde9b90bc4cfb3dc23e8b6263fdaf5fc1815a262ee8c6f2db3dfc0fe54db7
4
- data.tar.gz: 7c80ee6fa969f77643e8256cc0d4a33f1de8bf1f540fefe7d1641e3691e76044
3
+ metadata.gz: cb7893544cb7037e6076051880f66d3140c2a0b4218446ca40a2616b81cf2fbd
4
+ data.tar.gz: bfea4a2849792217d32b3fee7c5c426748302b40291bf16e4ba966be44489915
5
5
  SHA512:
6
- metadata.gz: a7303c826807b76c35d3899b02ce0af2874471e7dc55f19d6dcef85447270c5ea8fbb67e7bdb21fa5acf9a352f5355adcaa83e23bc4aeb83f42ca0d2149964aa
7
- data.tar.gz: c148a6770e6619bb7d32a435d7ad314e55871f4188cbff01c1f21c8e02e58497e3c6d32ec007bb27b6b9020c85bbd596a32e99575c7a1fab3cd4d224f7969184
6
+ metadata.gz: 521b9a33d845ae0af2101e581937154f491bd8eaa8d8ab57f6378b02994c35973ac1b41f53a080307c51325899ce89e714abe99bc92af001cb29269800f34694
7
+ data.tar.gz: dd096edd552d51a1e510e8bb0a82293f1ac67090626e88daab11578eb9f34ad6f11faa51216f8300472d189c051f879aca0a17d1e4957b38f148c295ed718e97
data/LICENSE CHANGED
@@ -1,5 +1,6 @@
1
1
  MIT License
2
2
 
3
+ Copyright (c) 2021 Alexandre ZANNI
3
4
  Copyright (c) 2021 Alexandre ZANNI at SEC-IT
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
data/bin/tls-map CHANGED
@@ -5,7 +5,7 @@
5
5
  require 'pp'
6
6
  # Project internal
7
7
  require 'tls_map'
8
- require 'tls_map/cli'
8
+ require 'tls_map/cli/cli'
9
9
  # External
10
10
  require 'docopt'
11
11
  require 'paint'
@@ -16,23 +16,23 @@ doc = <<~DOCOPT
16
16
  TLS map #{TLSmap::VERSION}
17
17
 
18
18
  Usage:
19
- tls-map search <critera> <term> [-o <output> --force -e -a] [--no-color --debug]
20
- tls-map bulk <critera> <file> [-q <output> --force] [--no-color --debug]
19
+ tls-map search <criteria> <term> [-o <output> --force -e -a] [--no-color --debug]
20
+ tls-map bulk <criteria> <file> [-q <output> --force] [--no-color --debug]
21
21
  tls-map export <filename> <format> [--force] [--debug]
22
- tls-map extract <filename> <format> [--no-color --debug]
23
- tls-map update [--debug]
22
+ tls-map extract <filename> <format> [--no-color --debug [--only-weak | --hide-weak]]
23
+ tls-map update [--with-extended] [--debug]
24
24
  tls-map -h | --help
25
25
  tls-map --version
26
26
 
27
27
  Search options: (offline) search and translate cipher names between SSL/TLS libraries
28
- <critera> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
28
+ <criteria> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
29
29
  <term> The cipher algorithm name.
30
30
  -o, --output <output> Displayed fields. Accepted values: all, codepoint, iana, openssl, gnutls, nss. [default: all]
31
31
  -e, --extended (Online) Display additional information about the cipher (requires output = all or iana)
32
32
  -a, --acronym (Online) Display full acronym name (requires -e / --extended option)
33
33
 
34
34
  Bulk options: (offline) search and translate cipher names between SSL/TLS libraries in bulk
35
- <critera> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
35
+ <criteria> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
36
36
  <file> File containing the cipher algorithm names, one per line.
37
37
  -q, --output2 <output> Displayed fields. Accepted values: codepoint, iana, openssl, gnutls, nss. [default: iana]
38
38
 
@@ -43,8 +43,11 @@ doc = <<~DOCOPT
43
43
  Extract options: (offline) extract ciphers from external tools output file
44
44
  <filename> The external tool output file
45
45
  <format> Supported formats: sslyze, sslscan2, testssl, ssllabs-scan (check the documentation for the expected file format)
46
+ --only-weak Show only ciphers with a security level equal to weak or insecure (hide secure and recommended) (work only with TLS not SSL).
47
+ --hide-weak Hide ciphers with a security level equal to weak or insecure (show only secure and recommended) (work only with TLS not SSL).
46
48
 
47
49
  Update options: (online) DANGEROUS, will break database integrity, force option will be required
50
+ --with-extended (Online) Also save extended information used by search --extended option.
48
51
 
49
52
  Other options:
50
53
  --force Force parsing even if integrity check failed (DANGEROUS, may result in command execution vulnerability)
@@ -60,7 +63,7 @@ begin
60
63
  pp args if args['--debug']
61
64
  if args['search']
62
65
  cli = TLSmap::CLI.new(args['--force'])
63
- res = cli.search(args['<critera>'].to_sym, args['<term>'], args['--output'].to_sym)
66
+ res = cli.search(args['<criteria>'].to_sym, args['<term>'], args['--output'].to_sym)
64
67
  puts Paint['No match found', :red] if res.empty?
65
68
  res.each do |k, v|
66
69
  puts "#{Paint[k, :green]}: #{Paint[v, :white]}"
@@ -71,6 +74,7 @@ begin
71
74
  ext = tmext_i.extend(res[:iana])
72
75
  dic = tmext::DICO
73
76
  sev = tmext::VULN_SEVERITY
77
+ sec_lvl = tmext::SECURITY_LEVEL
74
78
  ext.each do |k, v|
75
79
  case k
76
80
  when 'vulns'
@@ -81,6 +85,8 @@ begin
81
85
  end
82
86
  when 'tls_version'
83
87
  puts "#{Paint[dic[k], :magenta]}: #{Paint[v.join(', '), :white]}"
88
+ when 'security'
89
+ puts "#{Paint[dic[k], :magenta]}: #{Paint[v, sec_lvl[v][:color]]}"
84
90
  else
85
91
  print "#{Paint[dic[k], :magenta]}: #{Paint[v, :white]}"
86
92
  print " (#{tmext_i.translate_acronym(v)})" if args['--acronym'] && !tmext_i.translate_acronym(v).nil? # rubocop:disable Metrics/BlockNesting
@@ -90,7 +96,7 @@ begin
90
96
  end
91
97
  elsif args['bulk']
92
98
  cli = TLSmap::CLI.new(args['--force'])
93
- res = cli.bulk_search(args['<critera>'].to_sym, args['<file>'], args['--output2'].to_sym)
99
+ res = cli.bulk_search(args['<criteria>'].to_sym, args['<file>'], args['--output2'].to_sym)
94
100
  puts Paint['No match found', :red] if res.empty?
95
101
  res.each do |h|
96
102
  puts Paint[h[args['--output2'].to_sym], :green]
@@ -103,13 +109,26 @@ begin
103
109
  extractor = TLSmap::App::Extractor.new
104
110
  ciphers = extractor.parse(args['<format>'], args['<filename>'])
105
111
  ciphers.each do |k, v|
106
- puts Paint[k, :blue] unless v.empty?
107
- puts Paint[v.join("\n"), :white] unless v.empty?
112
+ if args['--only-weak'] || args['--hide-weak']
113
+ cliext = TLSmap::CLI::Extended.new
114
+ v.each do |alg|
115
+ ci = TLSmap::App::Cipher.new(:iana, alg, enhanced_data: cliext.enhanced_data)
116
+ puts Paint[alg, :white] if (args['--only-weak'] && !ci.should_i_use?) ||
117
+ (args['--hide-weak'] && ci.should_i_use?)
118
+ end
119
+ else
120
+ puts Paint[k, :blue] unless v.empty?
121
+ puts Paint[v.join("\n"), :white] unless v.empty?
122
+ end
108
123
  end
109
124
  elsif args['update']
110
125
  cli = TLSmap::CLI.new
111
126
  cli.update
112
- puts 'Database updated'
127
+ if args['--with-extended']
128
+ cliext = TLSmap::CLI::Extended.new
129
+ cliext.update
130
+ end
131
+ puts 'Database(s) updated'
113
132
  end
114
133
  rescue Docopt::Exit => e
115
134
  puts e.message
Binary file
data/lib/tls_map.rb CHANGED
@@ -4,19 +4,24 @@
4
4
  require 'pathname'
5
5
  # Project internal
6
6
  require 'tls_map/version'
7
- require 'tls_map/utils'
8
- require 'tls_map/iana'
9
- require 'tls_map/openssl'
10
- require 'tls_map/gnutls'
11
- require 'tls_map/nss'
12
- require 'tls_map/output'
13
- require 'tls_map/ciphersuiteinfo'
14
- require 'tls_map/extractor'
7
+ require 'tls_map/utils/utils'
8
+ require 'tls_map/app/iana'
9
+ require 'tls_map/app/openssl'
10
+ require 'tls_map/app/gnutls'
11
+ require 'tls_map/app/nss'
12
+ require 'tls_map/app/output'
13
+ require 'tls_map/app/extended/ciphersuiteinfo'
14
+ require 'tls_map/app/extractor/extractor'
15
+ require 'tls_map/app/cipher/cipher'
15
16
 
16
17
  # TLS map module
17
18
  module TLSmap
18
19
  # TLS mapping
19
20
  class App
21
+ # Get the mapping of all TLS cipher suites
22
+ # @return [Hash] mapping of all TLS cipher suites
23
+ attr_reader :tls_map
24
+
20
25
  # Will automatically fetch source files and parse them.
21
26
  def initialize
22
27
  @iana_file = Utils.tmpfile('iana', IANA_URL)
@@ -37,17 +42,42 @@ module TLSmap
37
42
  end
38
43
 
39
44
  # Search for corresponding cipher algorithms in other libraries
40
- # @param critera [Symbol] The type of `term`.
45
+ # @param criteria [Symbol] The type of `term`.
41
46
  # Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
42
47
  # @param term [String] The cipher algorithm name.
43
48
  # @param output [Symbol] The corresponding type to be included in the return value.
44
49
  # Accepted values: `:all` (default), `:codepoint`, `:iana`, `:openssl`,
45
50
  # `:gnutls`, `:nss`.
46
51
  # @return [Hash] The corresponding type matching `term`.
47
- def search(critera, term, output = :all)
52
+ def search(criteria, term, output = :all)
48
53
  @tls_map.each do |alg|
49
- term = term.upcase if critera == :codepoint
50
- next unless alg[critera] == term
54
+ term = term.upcase if criteria == :codepoint
55
+ next unless alg[criteria] == term
56
+ return alg if output == :all
57
+
58
+ return { output => alg[output] }
59
+ end
60
+ {}
61
+ end
62
+
63
+ # Stateless version of {App#search}.
64
+ # @param tls_map [Hash] mapping of all TLS cipher suites returned by {tls_map}.
65
+ # @param criteria [Symbol] Same as `criteria` from {TLSmap::App#search}
66
+ # @param term [String] Same as `term` from {TLSmap::App#search}
67
+ # @param output [Symbol] Same as `output` from {TLSmap::App#search}
68
+ # @see App#search
69
+ # @example
70
+ # tm = TLSmap::App.new
71
+ # TLSmap::App.search(tm.tls_map, :iana, 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256')
72
+ # # => {:codepoint=>"CCA9", :iana=>"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
73
+ # :openssl=>"ECDHE-ECDSA-CHACHA20-POLY1305", :gnutls=>"ECDHE_ECDSA_CHACHA20_POLY1305",
74
+ # :nss=>"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"}
75
+ # # or to use with the Cipher class
76
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', tm.tls_map)
77
+ def self.search(tls_map, criteria, term, output = :all)
78
+ tls_map.each do |alg|
79
+ term = term.upcase if criteria == :codepoint
80
+ next unless alg[criteria] == term
51
81
  return alg if output == :all
52
82
 
53
83
  return { output => alg[output] }
@@ -56,7 +86,7 @@ module TLSmap
56
86
  end
57
87
 
58
88
  # Search for corresponding cipher algorithms in other libraries in bulk
59
- # @param critera [Symbol] The type of `term`.
89
+ # @param criteria [Symbol] The type of `term`.
60
90
  # Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
61
91
  # @param file [String] File containing the cipher algorithm names, one per line.
62
92
  # @param output [Symbol] The corresponding type to be included in the return value.
@@ -64,10 +94,10 @@ module TLSmap
64
94
  # `:gnutls`, `:nss`.
65
95
  # @return [Array<Hash>] The corresponding type, same as {search} return value
66
96
  # but one per line stored in an array.
67
- def bulk_search(critera, file, output = :all)
97
+ def bulk_search(criteria, file, output = :all)
68
98
  res = []
69
99
  File.foreach(file) do |line|
70
- res.push(search(critera, line.chomp, output))
100
+ res.push(search(criteria, line.chomp, output))
71
101
  end
72
102
  res
73
103
  end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Project internal
4
+ require 'tls_map/cli/cli'
5
+
6
+ module TLSmap
7
+ # TLS mapping
8
+ class App
9
+ # Manipulate cipher suite information
10
+ class Cipher
11
+ # Get the hexadecimal codepoint of the cipher suite
12
+ # @return [String] Hexadecimal codepoint
13
+ attr_reader :codepoint
14
+
15
+ # Get the IANA name of the cipher suite
16
+ # @return [String] IANA name
17
+ attr_reader :iana
18
+
19
+ # Get the OpenSSL name of the cipher suite
20
+ # @return [String] OpenSSL name
21
+ attr_reader :openssl
22
+
23
+ # Get the GnuTLS name of the cipher suite
24
+ # @return [String] GnuTLS name
25
+ attr_reader :gnutls
26
+
27
+ # Get the NSS name of the cipher suite
28
+ # @return [String] NSS name
29
+ attr_reader :nss
30
+
31
+ # Get extended information
32
+ # @!attribute [r] extended
33
+ # @return [Hash]
34
+ # @example
35
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_RSA_WITH_SEED_CBC_SHA')
36
+ # ci.extended
37
+ # # =>
38
+ # # {"protocol_version"=>"TLS",
39
+ # # "kex_algorithm"=>"RSA",
40
+ # # "auth_algorithm"=>"RSA",
41
+ # # "enc_algorithm"=>"SEED CBC",
42
+ # # "hash_algorithm"=>"SHA",
43
+ # # "security"=>"weak",
44
+ # # "tls_version"=>["TLS1.0", "TLS1.1", "TLS1.2"],
45
+ # # "vulns"=>
46
+ # # [{:severity=>1, :description=>"This key exchange algorithm does not support Perfect Forward Secrecy (PFS)
47
+ # # which is recommended, so attackers cannot decrypt the complete communication stream."},
48
+ # # {:severity=>1,
49
+ # # :description=>
50
+ # # "In 2013, researchers demonstrated a timing attack against several TLS implementations using the CBC
51
+ # # encryption algorithm (see [isg.rhul.ac.uk](http://www.isg.rhul.ac.uk/tls/Lucky13.html)). Additionally,
52
+ # # the CBC mode is vulnerable to plain-text attacks in TLS 1.0, SSL 3.0 and lower. A fix has been
53
+ # # introduced with TLS 1.2 in form of the GCM mode which is not vulnerable to the BEAST attack. GCM should
54
+ # # be preferred over CBC."},
55
+ # # {:severity=>1, :description=>"The Secure Hash Algorithm 1 has been proven to be insecure as of 2017 (see
56
+ # # [shattered.io](https://shattered.io))."}],
57
+ # # "url"=>"https://ciphersuite.info/cs/TLS_RSA_WITH_SEED_CBC_SHA/"}
58
+ def extended
59
+ fetch_extended
60
+ @extended
61
+ end
62
+
63
+ # Initialize {TLSmap::App::Cipher} instance
64
+ # @param type [Symbol] Same as `criteria` from {TLSmap::App#search}
65
+ # @param value [String] Same as `term` from {TLSmap::App#search}
66
+ # @param opts [Hash] the option hash
67
+ # @option opts [Hash] :tls_map mapping of all TLS cipher suites returned by {App#tls_map}.
68
+ # (better performance for batch usage)
69
+ # @option opts [Hash] :enhanced_data enhanced information of all cipher suites returned by
70
+ # {Extended#enhanced_data}. (better performance for batch usage)
71
+ # @example
72
+ # # Offline TLS data + online extended data
73
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5')
74
+ # # Online TLS data + online extended data
75
+ # tm = TLSmap::App.new
76
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', tls_map: tm.tls_map)
77
+ # # Offline TLS data + online extended data but more efficient for batch requesting
78
+ # tmext = TLSmap::App::Extended.new
79
+ # tmext.enhance_all
80
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', enhanced_data: tmext.enhanced_data)
81
+ # # Offline TLS data + offline extended data (better performance but may be outdated)
82
+ # cliext = TLSmap::CLI::Extended.new
83
+ # ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', enhanced_data: cliext.enhanced_data)
84
+ def initialize(type, value, opts = {}) # rubocop:disable Metrics/MethodLength
85
+ res = if opts[:tls_map].nil?
86
+ TLSmap::CLI.new.search(type, value)
87
+ else
88
+ TLSmap::App.search(opts[:tls_map], type, value)
89
+ end
90
+ @codepoint = res[:codepoint]
91
+ @iana = res[:iana]
92
+ @openssl = res[:openssl]
93
+ @gnutls = res[:gnutls]
94
+ @nss = res[:nss]
95
+ @extended = opts.dig(:enhanced_data, @iana)
96
+ end
97
+
98
+ # Retrieve extended data by using #{App:Extended}
99
+ def fetch_extended
100
+ return unless @extended.nil?
101
+
102
+ tmext = TLSmap::App::Extended.new
103
+ @extended = tmext.extend(@iana)
104
+ end
105
+
106
+ # Is the security level defined to `weak`?
107
+ # @return [Boolean]
108
+ def weak?
109
+ fetch_extended
110
+ @extended['security'] == 'weak'
111
+ end
112
+
113
+ # Is the security level defined to `insecure`?
114
+ # @return [Boolean]
115
+ def insecure?
116
+ fetch_extended
117
+ @extended['security'] == 'insecure'
118
+ end
119
+
120
+ # Is the security level defined to `secure`?
121
+ # @return [Boolean]
122
+ def secure?
123
+ fetch_extended
124
+ @extended['security'] == 'secure'
125
+ end
126
+
127
+ # Is the security level defined to `recommended`?
128
+ # @return [Boolean]
129
+ def recommended?
130
+ fetch_extended
131
+ @extended['security'] == 'recommended'
132
+ end
133
+
134
+ # Is the security level defined to `secure` or `recommended`?
135
+ # It will return `false` for `weak` and `insecure` cipher suites.
136
+ # @return [Boolean]
137
+ def should_i_use?
138
+ recommended? || secure?
139
+ end
140
+
141
+ # Is the cipher suite vulnerable?
142
+ # @return [Boolean] `true` if one (or more) vulnerability is declared
143
+ def vulnerable?
144
+ fetch_extended
145
+ !@extended['vulns'].empty?
146
+ end
147
+
148
+ protected :fetch_extended
149
+ end
150
+ end
151
+ end
@@ -22,9 +22,9 @@ module TLSmap
22
22
  ROOT = 'https://ciphersuite.info/'
23
23
  # Root URL of Cipher Suite Info API
24
24
  API_ROOT = "#{ROOT}api/"
25
- # URL of the data file containig vulnerabilities information
25
+ # URL of the data file containing vulnerabilities information
26
26
  VULN_DATA = 'https://raw.githubusercontent.com/hcrudolph/ciphersuite.info/master/directory/fixtures/00_vulnerabilities.yaml'
27
- # URL of the data file containig technologies information
27
+ # URL of the data file containing technologies information
28
28
  TECH_DATA = 'https://raw.githubusercontent.com/hcrudolph/ciphersuite.info/master/directory/fixtures/01_technologies.yaml'
29
29
  # Hash mapping API key and display name for CLI
30
30
  DICO = {
@@ -44,6 +44,17 @@ module TLSmap
44
44
  1 => { title: 'Medium', color: 'orange' },
45
45
  2 => { title: 'High', color: :red }
46
46
  }.freeze
47
+ # Hash mapping the security level used by the API and color for the CLI
48
+ SECURITY_LEVEL = {
49
+ 'recommended' => { color: :green },
50
+ 'secure' => { color: :green },
51
+ 'weak' => { color: 'orange' },
52
+ 'insecure' => { color: :red }
53
+ }.freeze
54
+
55
+ # Get the enhanced information of all cipher suites returned by {enhance_all}.
56
+ # @return [Hash] Enhanced information of all cipher suites
57
+ attr_reader :enhanced_data
47
58
 
48
59
  # Will automatically fetch source files and parse them.
49
60
  def initialize
@@ -51,16 +62,47 @@ module TLSmap
51
62
  @vuln_file = Utils.tmpfile('vuln', VULN_DATA)
52
63
  @tech = parse_tech
53
64
  @vuln = parse_vuln
65
+ @ciphersuite_all = nil
66
+ @enhanced_data = nil
67
+ end
68
+
69
+ # Fetch all cipher suite data from ciphersuite.info and store it in the instance attribute for batch usage.
70
+ def fetch_ciphersuite
71
+ return unless @ciphersuite_all.nil?
72
+
73
+ @ciphersuite_all = JSON.parse(Net::HTTP.get(URI("#{API_ROOT}cs/")))['ciphersuites'].reduce(:merge!)
54
74
  end
55
75
 
56
- # Retrieve advanced about a cipher on Cipher Suite Info API and enhanced it
76
+ # Enhance data from ciphersuite.info for all cipher suites and store it
77
+ # for batch usage.
78
+ # The data will be available through {enhanced_data}.
79
+ def enhance_all
80
+ fetch_ciphersuite
81
+ out = {}
82
+ @ciphersuite_all.each do |k, _v|
83
+ out.store(k, extend(k, true))
84
+ end
85
+ @enhanced_data = out
86
+ end
87
+
88
+ # Retrieve advanced information about a cipher on Cipher Suite Info API and enhanced it.
89
+ # Fetch only the requested cipher suite, small network footprint, ideal for low bandwidth or punctual use.
57
90
  # @param iana_name [String] IANA cipher name
58
- # @return [Hash] Hash containing advanced information. The keys are the same as {DICO}. All valeus are string
91
+ # @param caching [Boolean] if true will fetch info for all cipher suites the 1st time and used the cached value
92
+ # for further requests
93
+ # @return [Hash] Hash containing advanced information. The keys are the same as {DICO}. All values are string
59
94
  # except `vulns` which is an array of hashes containing two keys: `:severity` (integer) and `:description`
60
95
  # (string). Each hash in `vulns` correspond to a vulnerability.
61
- def extend(iana_name) # rubocop:disable Metrics/MethodLength
62
- obj = Net::HTTP.get(URI("#{API_ROOT}cs/#{iana_name}/"))
63
- out = JSON.parse(obj)[iana_name]
96
+ def extend(iana_name, caching = false) # rubocop:disable Metrics/MethodLength
97
+ if caching
98
+ fetch_ciphersuite
99
+ out = @ciphersuite_all[iana_name]
100
+ else
101
+ obj = Net::HTTP.get(URI("#{API_ROOT}cs/#{iana_name}/"))
102
+ out = JSON.parse(obj)[iana_name]
103
+ end
104
+ return {} if out.nil?
105
+
64
106
  out.store('vulns', [])
65
107
  %w[openssl_name gnutls_name hex_byte_1 hex_byte_2].each do |key|
66
108
  out.delete(key)
@@ -114,7 +156,7 @@ module TLSmap
114
156
  nil
115
157
  end
116
158
 
117
- protected :parse_tech, :parse_vuln
159
+ protected :parse_tech, :parse_vuln, :fetch_ciphersuite
118
160
  end
119
161
  end
120
162
  end
@@ -3,7 +3,7 @@
3
3
  # Ruby internal
4
4
  require 'json'
5
5
  # Project internal
6
- require 'tls_map/cli'
6
+ require 'tls_map/cli/cli'
7
7
  # External
8
8
  require 'rexml/document'
9
9
 
@@ -98,7 +98,7 @@ module TLSmap
98
98
  # command (CLI) / {parse} method (library)
99
99
  def helper(tool)
100
100
  intro = 'You may not be provinding the right format.'
101
- outro = 'See https://sec-it.github.io/tls-map/yard/TLSmap/App/Extractor'
101
+ outro = 'See https://noraj.github.io/tls-map/yard/TLSmap/App/Extractor'
102
102
  "#{intro}\nUse this command: #{CMD[tool]}\n#{outro}"
103
103
  end
104
104
 
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby internal
4
+ require 'digest'
5
+
6
+ # TLS map module
7
+ module TLSmap
8
+ # Offline version of {App}
9
+ class CLI < App
10
+ INTEGRITY = '42e44f89550365da2bc8d33d87f88b65d85d6474e90f9edb65e0ea6c78f61a53' # sha2-256
11
+
12
+ # Load and parse data from marshalized hash (`data/mapping.marshal`).
13
+ # It must match the integrity check for security purpose.
14
+ # @param force [Boolean] Force parsing even if integrity check failed (DANGEROUS,
15
+ # may result in command execution vulnerability)
16
+ def initialize(force = false) # rubocop:disable Lint/MissingSuper
17
+ @storage_location = 'data/'
18
+ @database_path = absolute_db_path('mapping.marshal')
19
+ database_exists?
20
+ @tls_map = []
21
+ parse(force)
22
+ end
23
+
24
+ # Find the absolute path of the a data file from its relative location
25
+ # @param filename [String] file name
26
+ # @return [String] absolute filename of the data file
27
+ def absolute_db_path(filename)
28
+ pn = Pathname.new(__FILE__)
29
+ install_dir = pn.dirname.parent.parent.parent.to_s + Pathname::SEPARATOR_LIST
30
+ install_dir + @storage_location + filename
31
+ end
32
+
33
+ # Check if the TLS database DB exists
34
+ # @return [Boolean] `true` if the file exists
35
+ def database_exists?
36
+ exists = File.file?(@database_path)
37
+ raise "Database does not exist: #{@database_path}" unless exists
38
+
39
+ exists
40
+ end
41
+
42
+ def parse(force = false)
43
+ if Digest::SHA256.file(@database_path).hexdigest == INTEGRITY || force # rubocop:disable Style/GuardClause
44
+ @tls_map = Marshal.load(File.read(@database_path)) # rubocop:disable Security/MarshalLoad
45
+ else
46
+ raise 'Integrity check failed, maybe be due to unvalidated database after update'
47
+ end
48
+ end
49
+
50
+ def update
51
+ tm = TLSmap::App.new
52
+ tm.export(@database_path, :marshal)
53
+ end
54
+
55
+ protected :database_exists?, :absolute_db_path, :parse
56
+
57
+ # Offline version of {App::Extended}
58
+ class Extended < App::Extended
59
+ INTEGRITY = '6573b7208668485e6bdd4495627f5fdbdd7f80040b277603bc42f20d16a665e7' # sha2-256
60
+
61
+ # Load and parse data from marshalized hash (`data/extended.marshal`).
62
+ # It must match the integrity check for security purpose.
63
+ # @param force [Boolean] Force parsing even if integrity check failed (DANGEROUS,
64
+ # may result in command execution vulnerability)
65
+ def initialize(force = false) # rubocop:disable Lint/MissingSuper
66
+ @storage_location = 'data/'
67
+ @extended_path = absolute_db_path('extended.marshal')
68
+ @enhanced_data = {}
69
+ extended_exists?
70
+ parse(force)
71
+ end
72
+
73
+ # Find the absolute path of the a data file from its relative location
74
+ # @param filename [String] file name
75
+ # @return [String] absolute filename of the data file
76
+ def absolute_db_path(filename)
77
+ pn = Pathname.new(__FILE__)
78
+ install_dir = pn.dirname.parent.parent.parent.to_s + Pathname::SEPARATOR_LIST
79
+ install_dir + @storage_location + filename
80
+ end
81
+
82
+ # Check if the extended DB exists
83
+ # @return [Boolean] `true` if the files exists
84
+ def extended_exists?
85
+ exists = File.file?(@extended_path)
86
+ raise "Database does not exist: #{@extended_path}" unless exists
87
+
88
+ exists
89
+ end
90
+
91
+ def parse(force = false)
92
+ if Digest::SHA256.file(@extended_path).hexdigest == INTEGRITY || force # rubocop:disable Style/GuardClause
93
+ @enhanced_data = Marshal.load(File.read(@extended_path)) # rubocop:disable Security/MarshalLoad
94
+ else
95
+ raise 'Integrity check failed, maybe be due to unvalidated database after update'
96
+ end
97
+ end
98
+
99
+ def update
100
+ tmext = TLSmap::App::Extended.new
101
+ tmext.enhance_all
102
+ File.write(@extended_path, Marshal.dump(tmext.enhanced_data))
103
+ end
104
+
105
+ # Same as {App::Extended} but loading data from offline database, so there
106
+ # is no caching option.
107
+ # @see App::Extended
108
+ def extend(iana_name)
109
+ @enhanced_data[iana_name]
110
+ end
111
+
112
+ protected :extended_exists?, :absolute_db_path, :parse
113
+ undef_method :enhance_all, :fetch_ciphersuite, :parse_tech, :parse_vuln
114
+ end
115
+ end
116
+ end
File without changes
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TLSmap
4
- VERSION = '1.3.2'
4
+ VERSION = '2.0.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tls-map
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre ZANNI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-22 00:00:00.000000000 Z
11
+ date: 2021-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docopt
@@ -53,7 +53,8 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.2'
55
55
  description: 'CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL,
56
- GnuTLS, NSS'
56
+ GnuTLS, NSS;get information and vulnerabilities about cipher suites;extract cipher
57
+ suites from external tools: SSLyze, sslscan2, testssl.sh, ssllabs-scan'
57
58
  email: alexandre.zanni@engineer.com
58
59
  executables:
59
60
  - tls-map
@@ -64,31 +65,33 @@ files:
64
65
  - LICENSE
65
66
  - bin/tls-map
66
67
  - bin/tls-map_console
68
+ - data/extended.marshal
67
69
  - data/mapping.json
68
70
  - data/mapping.marshal
69
71
  - data/mapping.md
70
72
  - data/mapping.min.json
71
73
  - lib/tls_map.rb
72
- - lib/tls_map/ciphersuiteinfo.rb
73
- - lib/tls_map/cli.rb
74
- - lib/tls_map/extractor.rb
75
- - lib/tls_map/gnutls.rb
76
- - lib/tls_map/iana.rb
77
- - lib/tls_map/nss.rb
78
- - lib/tls_map/openssl.rb
79
- - lib/tls_map/output.rb
80
- - lib/tls_map/utils.rb
74
+ - lib/tls_map/app/cipher/cipher.rb
75
+ - lib/tls_map/app/extended/ciphersuiteinfo.rb
76
+ - lib/tls_map/app/extractor/extractor.rb
77
+ - lib/tls_map/app/gnutls.rb
78
+ - lib/tls_map/app/iana.rb
79
+ - lib/tls_map/app/nss.rb
80
+ - lib/tls_map/app/openssl.rb
81
+ - lib/tls_map/app/output.rb
82
+ - lib/tls_map/cli/cli.rb
83
+ - lib/tls_map/utils/utils.rb
81
84
  - lib/tls_map/version.rb
82
- homepage: https://sec-it.github.io/tls-map/
85
+ homepage: https://noraj.github.io/tls-map/
83
86
  licenses:
84
87
  - MIT
85
88
  metadata:
86
89
  yard.run: yard
87
- bug_tracker_uri: https://github.com/sec-it/tls-map/issues
88
- changelog_uri: https://github.com/sec-it/tls-map/blob/master/docs/CHANGELOG.md
89
- documentation_uri: https://sec-it.github.io/tls-map/yard/
90
- homepage_uri: https://sec-it.github.io/tls-map/
91
- source_code_uri: https://github.com/sec-it/tls-map/
90
+ bug_tracker_uri: https://github.com/noraj/tls-map/issues
91
+ changelog_uri: https://github.com/noraj/tls-map/blob/master/docs/CHANGELOG.md
92
+ documentation_uri: https://noraj.github.io/tls-map/yard/
93
+ homepage_uri: https://noraj.github.io/tls-map/
94
+ source_code_uri: https://github.com/noraj/tls-map/
92
95
  post_install_message:
93
96
  rdoc_options: []
94
97
  require_paths:
@@ -107,9 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
110
  - !ruby/object:Gem::Version
108
111
  version: '0'
109
112
  requirements: []
110
- rubygems_version: 3.2.15
113
+ rubygems_version: 3.2.22
111
114
  signing_key:
112
115
  specification_version: 4
113
- summary: 'CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS,
114
- NSS'
116
+ summary: CLI & library for TLS cipher suites manipulation
115
117
  test_files: []
data/lib/tls_map/cli.rb DELETED
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Ruby internal
4
- require 'digest'
5
-
6
- # TLS map module
7
- module TLSmap
8
- # TLS mapping
9
- class CLI < App
10
- INTEGRITY = '42e44f89550365da2bc8d33d87f88b65d85d6474e90f9edb65e0ea6c78f61a53' # sha2-256
11
-
12
- # Load and parse data from marshalized hash (`data/mapping.marshal`).
13
- # It must match the integrity check for security purpose.
14
- # @param force [Boolean] Force parsing even if intigrity check failed (DANGEROUS,
15
- # may result in command execution vulnerability)
16
- def initialize(force = false) # rubocop:disable Lint/MissingSuper
17
- @storage_location = 'data/'
18
- @database_name = 'mapping.marshal'
19
- @database_path = absolute_db_path
20
- database_exists?
21
- @tls_map = []
22
- parse(force)
23
- end
24
-
25
- # Find the absolute path of the DB from its relative location
26
- # @return [String] absolute filename of the DB
27
- def absolute_db_path
28
- pn = Pathname.new(__FILE__)
29
- install_dir = pn.dirname.parent.parent.to_s + Pathname::SEPARATOR_LIST
30
- install_dir + @storage_location + @database_name
31
- end
32
-
33
- # Check if the password database exists
34
- # @return [Boolean] `true` if the file exists
35
- def database_exists?
36
- exists = File.file?(@database_path)
37
- raise "Database does not exist: #{@database_path}" unless exists
38
-
39
- exists
40
- end
41
-
42
- def parse(force = false)
43
- if Digest::SHA256.file(@database_path).hexdigest == INTEGRITY || force # rubocop:disable Style/GuardClause
44
- @tls_map = Marshal.load(File.read(@database_path)) # rubocop:disable Security/MarshalLoad
45
- else
46
- raise 'Integry check failed, maybe be due to unavalidated database after update'
47
- end
48
- end
49
-
50
- def update
51
- tm = TLSmap::App.new
52
- tm.export(@database_path, :marshal)
53
- end
54
-
55
- protected :database_exists?, :absolute_db_path, :parse
56
- end
57
- end