Skip to content

Commit

Permalink
v2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
noraj committed Aug 12, 2021
1 parent 13610bc commit 6209dc7
Show file tree
Hide file tree
Showing 39 changed files with 3,418 additions and 417 deletions.
2 changes: 2 additions & 0 deletions .yardopts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
--output-dir docs/yard
--markup=markdown
--markup-provider=redcarpet
--plugin coderay
-
--main README.md
LICENSE
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ group :development, :lint do
end

group :development, :docs do
gem 'commonmarker', '~> 0.21' # for GMF support in YARD
gem 'github-markup', '~> 4.0' # for GMF support in YARD
gem 'redcarpet', '~> 3.5' # for GMF support in YARD
gem 'webrick', '~> 1.7' # for server support in YARD
gem 'yard', '~> 0.9'
gem 'yard-coderay', '~> 0.1' # for syntax highlight support in YARD
end
15 changes: 9 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
tls-map (1.3.2)
tls-map (2.0.0)
docopt (~> 0.6)
paint (~> 2.2)
rexml (~> 3.2)
Expand All @@ -10,7 +10,7 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
commonmarker (0.22.0)
coderay (1.1.3)
docopt (0.6.1)
github-markup (4.0.0)
minitest (5.14.4)
Expand All @@ -25,28 +25,30 @@ GEM
redcarpet (3.5.1)
regexp_parser (2.1.1)
rexml (3.2.5)
rubocop (1.18.4)
rubocop (1.19.0)
parallel (~> 1.10)
parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.8.0, < 2.0)
rubocop-ast (>= 1.9.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.8.0)
rubocop-ast (1.10.0)
parser (>= 3.0.1.1)
ruby-progressbar (1.11.0)
unicode-display_width (2.0.0)
webrick (1.7.0)
yard (0.9.26)
yard-coderay (0.1.0)
coderay
yard

PLATFORMS
x86_64-linux

DEPENDENCIES
bundler (>= 2.1.0, < 2.3)
commonmarker (~> 0.21)
docopt (~> 0.6)
github-markup (~> 4.0)
minitest (~> 5.12)
Expand All @@ -59,6 +61,7 @@ DEPENDENCIES
tls-map!
webrick (~> 1.7)
yard (~> 0.9)
yard-coderay (~> 0.1)

BUNDLED WITH
2.2.22
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

![logo](docs/_media/logo.png)

> CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS
> CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS and get information about cipher suites
**CLI**

Expand Down
38 changes: 27 additions & 11 deletions bin/tls-map
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ doc = <<~DOCOPT
TLS map #{TLSmap::VERSION}
Usage:
tls-map search <critera> <term> [-o <output> --force -e -a] [--no-color --debug]
tls-map bulk <critera> <file> [-q <output> --force] [--no-color --debug]
tls-map search <criteria> <term> [-o <output> --force -e -a] [--no-color --debug]
tls-map bulk <criteria> <file> [-q <output> --force] [--no-color --debug]
tls-map export <filename> <format> [--force] [--debug]
tls-map extract <filename> <format> [--no-color --debug]
tls-map update [--debug]
tls-map extract <filename> <format> [--no-color --debug [--only-weak | --hide-weak]]
tls-map update [--with-extended] [--debug]
tls-map -h | --help
tls-map --version
Search options: (offline) search and translate cipher names between SSL/TLS libraries
<critera> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
<criteria> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
<term> The cipher algorithm name.
-o, --output <output> Displayed fields. Accepted values: all, codepoint, iana, openssl, gnutls, nss. [default: all]
-e, --extended (Online) Display additional information about the cipher (requires output = all or iana)
-a, --acronym (Online) Display full acronym name (requires -e / --extended option)
Bulk options: (offline) search and translate cipher names between SSL/TLS libraries in bulk
<critera> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
<criteria> The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss.
<file> File containing the cipher algorithm names, one per line.
-q, --output2 <output> Displayed fields. Accepted values: codepoint, iana, openssl, gnutls, nss. [default: iana]
Expand All @@ -43,8 +43,11 @@ doc = <<~DOCOPT
Extract options: (offline) extract ciphers from external tools output file
<filename> The external tool output file
<format> Supported formats: sslyze, sslscan2, testssl, ssllabs-scan (check the documentation for the expected file format)
--only-weak Show only ciphers with a security level equal to weak or insecure (hide secure and recommended) (work only with TLS not SSL).
--hide-weak Hide ciphers with a security level equal to weak or insecure (show only secure and recommended) (work only with TLS not SSL).
Update options: (online) DANGEROUS, will break database integrity, force option will be required
--with-extended (Online) Also save extended information used by search --extended option.
Other options:
--force Force parsing even if integrity check failed (DANGEROUS, may result in command execution vulnerability)
Expand All @@ -60,7 +63,7 @@ begin
pp args if args['--debug']
if args['search']
cli = TLSmap::CLI.new(args['--force'])
res = cli.search(args['<critera>'].to_sym, args['<term>'], args['--output'].to_sym)
res = cli.search(args['<criteria>'].to_sym, args['<term>'], args['--output'].to_sym)
puts Paint['No match found', :red] if res.empty?
res.each do |k, v|
puts "#{Paint[k, :green]}: #{Paint[v, :white]}"
Expand Down Expand Up @@ -93,7 +96,7 @@ begin
end
elsif args['bulk']
cli = TLSmap::CLI.new(args['--force'])
res = cli.bulk_search(args['<critera>'].to_sym, args['<file>'], args['--output2'].to_sym)
res = cli.bulk_search(args['<criteria>'].to_sym, args['<file>'], args['--output2'].to_sym)
puts Paint['No match found', :red] if res.empty?
res.each do |h|
puts Paint[h[args['--output2'].to_sym], :green]
Expand All @@ -106,13 +109,26 @@ begin
extractor = TLSmap::App::Extractor.new
ciphers = extractor.parse(args['<format>'], args['<filename>'])
ciphers.each do |k, v|
puts Paint[k, :blue] unless v.empty?
puts Paint[v.join("\n"), :white] unless v.empty?
if args['--only-weak'] || args['--hide-weak']
cliext = TLSmap::CLI::Extended.new
v.each do |alg|
ci = TLSmap::App::Cipher.new(:iana, alg, enhanced_data: cliext.enhanced_data)
puts Paint[alg, :white] if (args['--only-weak'] && !ci.should_i_use?) ||
(args['--hide-weak'] && ci.should_i_use?)
end
else
puts Paint[k, :blue] unless v.empty?
puts Paint[v.join("\n"), :white] unless v.empty?
end
end
elsif args['update']
cli = TLSmap::CLI.new
cli.update
puts 'Database updated'
if args['--with-extended']
cliext = TLSmap::CLI::Extended.new
cliext.update
end
puts 'Database(s) updated'
end
rescue Docopt::Exit => e
puts e.message
Expand Down
Binary file added data/extended.marshal
Binary file not shown.
34 changes: 30 additions & 4 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,39 @@

Additions:

- Extended:
- add security level mapping
- colorize `security` value depending on the security level
- `TLSmap::App::Extended`:
- add security level mapping: `SECURITY_LEVEL`
- add a new attribute and getter `enhanced_data`, it contains a hash with enhanced information of all cipher suites (like the output of `extend` but for all cipher suites)
- add a new attribute `ciphersuite_all` containing raw data from ciphersuite.info (non-yet enhanced version of `enhanced_data`), only for internal use.
- internal method `fetch_ciphersuite` that populate `ciphersuite_all` attribute
- add `enhance_all` method, fetch and enhance data from ciphersuite.info for all cipher suites and store it for batch usage.
- new attribute for `extend` method: `caching`: will fetch info for all cipher suites the 1st time and used the cached value for further requests
- `TLSmap::App`:
- add a `search` class method for stateless usage
- add a getter for `tls_map` attribute
- `TLSmap::App::Cipher`:
- New class allowing to manipulate cipher suite information (check the library doc for more details)
- `TLSmap::CLI`
- small transparent fixes and spelling mistakes corrected
- `TLSmap::CLI::Extended`
- new class implementing an offline version of `TLSmap::CLI::Extended`, intended for CLI or offline usage and batch requests (using `data/extended.marshal`)
- CLI
- `Search`
- `--extended`: colorize `security` value depending on the security level
- `Extract`
- add `--only-weak` to `--hide-weak` to have the ability to show/hide weak cipher suites
- `Update`
- add `--with-extended` option to backup `extended.marshal` in addition to `mapping.marshal`

Chore:

- Fork: repository move from [sec-it/tls-map](https://github.com/sec-it/tls-map) to [noraj/tls-map](https://github.com/noraj/tls-map)
- Dev dependencies:
- Remove commonmarker since it's not supported by yard yet
- Add yard-coderay for basic syntax highlight
- Update rubocop

- Fork:
- repository move from [sec-it/tls-map](https://github.com/sec-it/tls-map) to [noraj/tls-map](https://github.com/noraj/tls-map)

## [1.3.2]

Expand Down
159 changes: 159 additions & 0 deletions docs/pages/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,66 @@ TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
```

Hide weak cipher suites while extracting (show only strong ones):

```
$ tls-map extract test/file_sample/testssl.json testssl --hide-weak
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
```

Show only weak cipher suites while extracting:

```
$ tls-map extract test/file_sample/sslyze.json sslyze --only-weak
TLS_RSA_WITH_SEED_CBC_SHA
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_SEED_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_SEED_CBC_SHA
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_SEED_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_SEED_CBC_SHA
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_SEED_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
```

### Update

The CLI is working with an offline database (Marshaled Ruby hash) to avoid
Expand Down Expand Up @@ -311,3 +371,102 @@ tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt')
# {:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", # :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"},
# {:codepoint=>"1302", :iana=>"TLS_AES_256_GCM_SHA384", :openssl=>"TLS_AES_256_GCM_SHA384", :gnutls=>"AES_256_GCM_SHA384", # :nss=>"TLS_AES_256_GCM_SHA384"}]
```

Manipulate a cipher suite:

```ruby
require 'tls_map'

ci = TLSmap::App::Cipher.new(:iana, 'TLS_RSA_WITH_SEED_CBC_SHA')

# Get the OpenSSL name
ci.openssl
# => "SEED-SHA"

# Try to get the GnuTLS one (output is nil because it's not implemented in GnuTLS)
ci.gnutls
# => nil

# Some boolean checker
ci.weak?
# => true
ci.vulnerable?
# => true
ci.should_i_use?
# => false

# Get the vulnerabilities
ci.extended['vulns']
# =>
# [{:severity=>1, :description=>"This key exchange algorithm does not support Perfect Forward Secrecy (PFS) which is recommended, so attackers cannot decrypt the complete communication stream."},
# {:severity=>1,
# :description=>
# "In 2013, researchers demonstrated a timing attack against several TLS implementations using the CBC encryption algorithm (see [isg.rhul.ac.uk](http://www.isg.rhul.ac.uk/tls/Lucky13.html)). Additionally, the CBC mode is vulnerable to plain-text attacks in TLS 1.0, SSL 3.0 and lower. A fix has been introduced with TLS 1.2 in form of the GCM mode which is not vulnerable to the BEAST attack. GCM should be preferred over CBC."},
# {:severity=>1, :description=>"The Secure Hash Algorithm 1 has been proven to be insecure as of 2017 (see [shattered.io](https://shattered.io))."}]

# Get the TLS version it is implemented in
ci.extended['tls_version']
# => ["TLS1.0", "TLS1.1", "TLS1.2"]
```

By default the `Cipher` class will use the offline database for TLS library
conversions (eg. OpenSSL to IANA name) and online API call to retrieve
advanced information such as the details about key exchange algorithm, authentication algorithm,
vulnerabilities, etc.

Bulk usage of cipher manipulation can be slow if we use the regular way to get
advanced information (online),
because we will have to make one HTTP request per cipher suite.

One solution is to pre-feed the `Cipher` class with one fetch-all call to the API.
This way we still have the most up-to-date data.

```ruby
require 'tls_map'

# Get ONCE the advanced data about all cipher suites
tmext = TLSmap::App::Extended.new
tmext.enhance_all
# Note: The data is accessible via tmext.enhanced_data

# Now each time we want to manipulate a cipher we can feed the Cipher
# class with the pre-fetched data.
# If we have to use this in a loop for hundreds or thousands of cipher suites
# there is no new HTTP call.
ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', enhanced_data: tmext.enhanced_data)
ci.insecure?
# => true
```

Another solution which has even better performance is to use the offline database
to pre-feed the `Cipher` class.

```ruby
require 'tls_map'

# Load advanced data from the offline database
cliext = TLSmap::CLI::Extended.new

# Load pre-fetched data into the Cipher class
ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', enhanced_data: cliext.enhanced_data)
```

Of course if you have only to access TLS names you don't need to bother with that
because advanced information are not fetch during the initialization but only when
a method needing it is called.

But at the contrary, the `Cipher` class is using the offline database for TLS
name by default to have a decent execution time, but if you want to be sure to
have the latest data available (directly fetched from upstream DVCS) you can
pre-fetch and feed the `Cipher` class too in a manner similar to what we did
earlier with the advanced data.

```ruby
require 'tls_map'

# Pre-fetch basic TLS data from the main class
tm = TLSmap::App.new

# Feed it into the cipher class
ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', tls_map: tm.tls_map)
```
Loading

0 comments on commit 6209dc7

Please sign in to comment.