├── docs ├── .nojekyll ├── yard │ ├── css │ │ ├── common.css │ │ └── full_list.css │ ├── frames.html │ ├── file_list.html │ ├── top-level-namespace.html │ ├── file.LICENSE.html │ ├── TLSmap.html │ ├── class_list.html │ ├── index.html │ ├── file.README.html │ ├── _index.html │ ├── js │ │ ├── full_list.js │ │ └── app.js │ ├── TLSmap │ │ ├── Utils.html │ │ ├── CLI.html │ │ └── App │ │ │ └── Extractor │ │ │ └── Sslyze.html │ └── method_list.html ├── _media │ └── logo.png ├── pages │ ├── demo.md │ ├── limitations.md │ ├── publishing.md │ ├── documentation.md │ ├── install.md │ ├── quick-start.md │ ├── usage.md │ └── examples.md ├── _navbar.md ├── _coverpage.md ├── _sidebar.md ├── about.md ├── index.html ├── vendor │ ├── prismjs │ │ └── components │ │ │ └── prism-ruby.min.js │ ├── plugins │ │ └── search.min.js │ └── themes │ │ └── dark.css └── CHANGELOG.md ├── .tool-versions ├── .yardopts ├── lib ├── tls_map │ ├── version.rb │ ├── nss.rb │ ├── gnutls.rb │ ├── utils.rb │ ├── iana.rb │ ├── output.rb │ ├── cli.rb │ ├── openssl.rb │ ├── ciphersuiteinfo.rb │ └── extractor.rb └── tls_map.rb ├── bin ├── tls-map_console └── tls-map ├── test ├── file_sample │ ├── bulk_IANA.txt │ └── sslscan2.xml ├── test_cli.rb ├── test_extractor.rb ├── test_extended.rb └── test_app.rb ├── Rakefile ├── .rubocop.yml ├── .editorconfig ├── LICENSE ├── Gemfile ├── .github └── workflows │ └── ruby.yml ├── .gitignore ├── Gemfile.lock ├── tls-map.gemspec └── README.md /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 3.0.1 2 | nodejs 14.15.1 3 | -------------------------------------------------------------------------------- /docs/yard/css/common.css: -------------------------------------------------------------------------------- 1 | /* Override this file with custom rules */ -------------------------------------------------------------------------------- /docs/_media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sec-it/tls-map/HEAD/docs/_media/logo.png -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --output-dir docs/yard 2 | --markup=markdown 3 | - 4 | --main README.md 5 | LICENSE 6 | -------------------------------------------------------------------------------- /lib/tls_map/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TLSmap 4 | VERSION = '1.3.2' 5 | end 6 | -------------------------------------------------------------------------------- /docs/pages/demo.md: -------------------------------------------------------------------------------- 1 | # Demonstration 2 | 3 | [![asciicast](https://asciinema.org/a/410877.svg)](https://asciinema.org/a/410877) 4 | -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | - [Home](/) 2 | - [Source](https://github.com/sec-it/tls-map) 3 | - [Library doc](https://sec-it.github.io/tls-map/yard/) 4 | -------------------------------------------------------------------------------- /bin/tls-map_console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'tls_map' 5 | require 'irb' 6 | 7 | IRB.start(__FILE__) 8 | -------------------------------------------------------------------------------- /test/file_sample/bulk_IANA.txt: -------------------------------------------------------------------------------- 1 | TLS_DH_RSA_WITH_AES_256_CBC_SHA 2 | TLS_RSA_WITH_RC4_128_SHA 3 | TLS_RSA_WITH_AES_128_CBC_SHA 4 | TLS_INVALID 5 | TLS_CHACHA20_POLY1305_SHA256 6 | TLS_AES_256_GCM_SHA384 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rake/testtask' 4 | 5 | Rake::TestTask.new(:test) do |t| 6 | t.libs << 'test' 7 | t.libs << 'lib' 8 | t.test_files = FileList['test/**/test_*.rb'] 9 | end 10 | 11 | desc 'Run tests' 12 | task default: :test 13 | -------------------------------------------------------------------------------- /test/test_cli.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: false 2 | 3 | require 'minitest/autorun' 4 | require 'minitest/skip_dsl' 5 | require 'tls_map' 6 | require 'tls_map/cli' 7 | 8 | class TLSmapCLITest < Minitest::Test 9 | def test_CLI 10 | assert(TLSmap::CLI.new) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 | # TLS map 4 | 5 | > CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS 6 | 7 | [GitHub](https://github.com/sec-it/tls-map) 8 | [Get Started](pages/quick-start?id=quick-start) 9 | 10 | ![color](#101010) 11 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_mode: 2 | merge: 3 | - Exclude 4 | AllCops: 5 | TargetRubyVersion: 2.6 6 | NewCops: enable 7 | Exclude: 8 | - 'test/*.rb' 9 | SuggestExtensions: false 10 | Layout/HashAlignment: 11 | Exclude: 12 | - '*.gemspec' 13 | Metrics/AbcSize: 14 | Enabled: false 15 | Style/OptionalBooleanParameter: 16 | Enabled: false 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # ruby 12 | [*.rb] 13 | charset = utf-8 14 | indent_style = space 15 | indent_size = 2 16 | trim_trailing_whitespace = true 17 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - Getting started 2 | 3 | - [Quick start](pages/quick-start.md) 4 | - [Installation](pages/install.md) 5 | - [Usage](pages/usage.md) 6 | - [Examples](pages/examples.md) 7 | - [Demo](pages/demo.md) 8 | - [Mapping](pages/mapping.md) 9 | - [Limitations](pages/limitations.md) 10 | 11 | - Guide 12 | 13 | - [Documentation](pages/documentation.md) 14 | - [Publishing](pages/publishing.md) 15 | 16 | - [About](about.md) 17 | - [Changelog](CHANGELOG.md) 18 | -------------------------------------------------------------------------------- /docs/pages/limitations.md: -------------------------------------------------------------------------------- 1 | # Limitations 2 | 3 | TLS map is only taking into account the TLS protocol. This means it will list 4 | ciphers of TLS 1.0, TLS 1.1, TLS 1.2 and TLS 1.3 but not from SSL 2.0 and SSL 5 | 3.0. 6 | 7 | Some TLS libraries are using some custom cipher suites that are not 8 | included the TLS standard, those non-standard algorithm are not supported by 9 | TLS map. 10 | 11 | In the TLS standard, there are hexadecimal codepoints that are reserved or 12 | unassigned. Those won't be shown in TLS map. 13 | -------------------------------------------------------------------------------- /docs/yard/frames.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Documentation by YARD 0.9.26 6 | 7 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /lib/tls_map/nss.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | 5 | # TLS map module 6 | module TLSmap 7 | # TLS mapping 8 | class App 9 | # Timeout https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ssl/sslproto.h 10 | # so use github RO mirror instead. 11 | NSS_URL = 'https://raw.githubusercontent.com/nss-dev/nss/master/lib/ssl/sslproto.h' 12 | 13 | def parse_nss 14 | File.read(@nss_file.path).scan(/(TLS_[a-zA-Z0-9_]+)\s+0x([[:xdigit:]]{4})/) do |alg| 15 | @tls_map.each do |h| 16 | h[:nss] ||= h[:codepoint] == alg[1].upcase ? alg[0] : nil 17 | end 18 | end 19 | end 20 | 21 | private :parse_nss 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/tls_map/gnutls.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | 5 | # TLS map module 6 | module TLSmap 7 | # TLS mapping 8 | class App 9 | GNUTLS_URL = 'https://gitlab.com/gnutls/gnutls/raw/master/lib/algorithms/ciphersuites.c' 10 | 11 | def parse_gnutls 12 | reg = /(GNUTLS_[a-zA-Z0-9_]+)\s+{\s?(0x[[:xdigit:]]{2},\s?0x[[:xdigit:]]{2})\s?}/ 13 | File.read(@gnutls_file.path).scan(reg).each do |alg| 14 | codepoint = codepoint_iana(alg[1]) 15 | name = alg[0][7..] 16 | @tls_map.each do |h| 17 | h[:gnutls] ||= h[:codepoint] == codepoint.upcase ? name : nil 18 | end 19 | end 20 | end 21 | 22 | private :parse_gnutls 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /docs/pages/publishing.md: -------------------------------------------------------------------------------- 1 | # Publishing 2 | 3 | ## On Rubygems.org 4 | 5 | ```plaintext 6 | $ git tag -a vx.x.x 7 | $ git push --follow-tags 8 | $ gem push pass-station-x.x.x.gem 9 | ``` 10 | 11 | See https://guides.rubygems.org/publishing/. 12 | 13 | On new release don't forget to rebuild the library documentation: 14 | 15 | ```plaintext 16 | $ bundle exec yard doc 17 | ``` 18 | 19 | And to be sure all tests pass! 20 | 21 | ```plaintext 22 | $ rake test 23 | ``` 24 | 25 | ## On BlackArch 26 | 27 | BA process 28 | 29 | On new release don't forget to rebuild the library documentation: 30 | 31 | ```plaintext 32 | $ bundle exec yard doc 33 | ``` 34 | 35 | And to be sure all tests pass! 36 | 37 | ```plaintext 38 | $ rake test 39 | ``` 40 | -------------------------------------------------------------------------------- /lib/tls_map/utils.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'net/http' 5 | require 'tempfile' 6 | require 'json' 7 | 8 | # TLS map module 9 | module TLSmap 10 | # Generic utilities 11 | module Utils 12 | def self.tmpfile(name, url) 13 | tmp = Tempfile.new(name) 14 | tmp.write(Net::HTTP.get(URI(url))) 15 | tmp.close 16 | tmp 17 | end 18 | 19 | # bring JSON.load_file before ruby 3.0.0 20 | # https://ruby-doc.org/stdlib-3.0.0/libdoc/json/rdoc/JSON.html#method-i-load_file 21 | def self.json_load_file(filespec, opts = {}) 22 | if RUBY_VERSION < '3.0.0' 23 | JSON.parse(File.read(filespec), opts) 24 | else 25 | JSON.load_file(filespec, opts) 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | ## Logo 4 | 5 | Logo made with [DesignEvo](https://www.designevo.com). 6 | 7 | ## References 8 | 9 | - testssl.sh 10 | - https://testssl.sh/openssl-iana.mapping.html 11 | - https://github.com/drwetter/testssl.sh/blob/3.1dev/openssl-iana.mapping.html 12 | - Iana 13 | - https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 14 | - Mozilla 15 | - https://wiki.mozilla.org/Security/Cipher_Suites 16 | - April King work (thanks for the inspiration) 17 | - https://github.com/april/tls-table 18 | - Openssl 19 | - https://www.openssl.org/docs/man1.1.1/man1/ciphers.html 20 | - Cipher Suite Info 21 | - https://ciphersuite.info/blog/2019/04/05/how-to-use-our-api/ 22 | - https://ciphersuite.info/api/ 23 | - https://github.com/hcrudolph/ciphersuite.info 24 | -------------------------------------------------------------------------------- /docs/pages/documentation.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | ## CLI doc 4 | 5 | See [Usage](pages/usage.md?id=cli). 6 | 7 | ### Serve locally 8 | 9 | ```plaintext 10 | $ npm i docsify-cli -g 11 | $ docsify serve docs 12 | ``` 13 | 14 | Documentation available at: http://localhost:3000/ 15 | 16 | ## Library doc 17 | 18 | The output directory of the library documentation will be `docs/yard`. 19 | 20 | You can consult it online on [GitHub](https://sec-it.github.io/tls-map/yard/) or on [RubyDoc](https://www.rubydoc.info/gems/tls-map/). 21 | 22 | ### Building locally: for library users 23 | 24 | For developers who only want to use the library. 25 | 26 | ```plaintext 27 | $ bundle exec yard doc 28 | ``` 29 | 30 | ### Serve locally 31 | 32 | Serve with live reload: 33 | 34 | ``` 35 | $ bundle exec yard server --reload 36 | ``` 37 | 38 | Documentation available at: http://localhost:8808/ 39 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alexandre ZANNI at SEC-IT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | # Specify your gem's dependencies in .gemspec 6 | gemspec 7 | 8 | # Needed for the CLI only 9 | group :runtime, :cli do 10 | gem 'docopt', '~> 0.6' # for argument parsing 11 | gem 'paint', '~> 2.2' # for colorized ouput 12 | end 13 | 14 | # Needed for the CLI & library 15 | group :runtime, :all do 16 | gem 'rexml', '~> 3.2' # XML parser 17 | end 18 | 19 | # Needed to install dependencies 20 | group :development, :install do 21 | gem 'bundler', ['>= 2.1.0', '< 2.3'] 22 | end 23 | 24 | # Needed to run tests 25 | group :development, :test do 26 | gem 'minitest', '~> 5.12' 27 | gem 'minitest-skip', '~> 0.0' # skip dummy tests 28 | gem 'rake', '~> 13.0' 29 | end 30 | 31 | # Needed for linting 32 | group :development, :lint do 33 | gem 'rubocop', '~> 1.10' 34 | end 35 | 36 | group :development, :docs do 37 | gem 'commonmarker', '~> 0.21' # for GMF support in YARD 38 | gem 'github-markup', '~> 4.0' # for GMF support in YARD 39 | gem 'redcarpet', '~> 3.5' # for GMF support in YARD 40 | gem 'webrick', '~> 1.7' # for server support in YARD 41 | gem 'yard', '~> 0.9' 42 | end 43 | -------------------------------------------------------------------------------- /lib/tls_map/iana.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'csv' 5 | 6 | # TLS map module 7 | module TLSmap 8 | # TLS mapping 9 | class App 10 | IANA_URL = 'https://www.iana.org/assignments/tls-parameters/tls-parameters-4.csv' 11 | 12 | # remove Reserved, Unassigned codepoints (those with a range: X-X or *) 13 | # also works with gnutls 14 | def codepoint_iana(raw_cp) 15 | c1, c2 = raw_cp.split(',') 16 | c2.strip! 17 | return nil unless c2.size == 4 18 | 19 | "#{c1[2..3]}#{c2[2..3]}" 20 | end 21 | 22 | # remove remaining Reserved, Unassigned codepoints 23 | def desc_iana(desc) 24 | return nil if /Reserved|Unassigned/.match?(desc) 25 | 26 | desc 27 | end 28 | 29 | def parse_iana 30 | CSV.foreach(@iana_file.path, **{ headers: true, header_converters: :symbol }) do |alg| 31 | codepoint = codepoint_iana(alg[:value]) 32 | description = desc_iana(alg[:description]) 33 | @tls_map << { codepoint: codepoint, iana: description } unless codepoint.nil? || description.nil? 34 | end 35 | end 36 | 37 | private :codepoint_iana, :desc_iana, :parse_iana 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: Ruby 9 | 10 | on: 11 | push: 12 | branches: [ master ] 13 | pull_request: 14 | branches: [ master ] 15 | 16 | jobs: 17 | test: 18 | 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | ruby-version: ['3.0', '2.7', '2.6'] 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Set up Ruby 27 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 28 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 29 | uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: ${{ matrix.ruby-version }} 32 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 33 | - name: Run test 34 | run: bundle exec rake test 35 | - name: Run lint 36 | run: bundle exec rubocop 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # Gemfile.lock 49 | # .ruby-version 50 | # .ruby-gemset 51 | 52 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 53 | .rvmrc 54 | 55 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 56 | # .rubocop-https?--* 57 | 58 | # PoC and tests 59 | poc.rb 60 | test.rb 61 | -------------------------------------------------------------------------------- /test/test_extractor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: false 2 | 3 | require 'minitest/autorun' 4 | require 'minitest/skip_dsl' 5 | require 'tls_map' 6 | 7 | class TLSmapExtractorTest < Minitest::Test 8 | def setup 9 | @ex = TLSmap::App::Extractor.new 10 | @ex.parse('ssllabs-scan', 'test/file_sample/ssllabs-scan_newwebsite.json') 11 | end 12 | 13 | def test_App_Extractor_attributes 14 | assert_instance_of(Hash, @ex.ciphers) 15 | assert_instance_of(Array, @ex.ciphers['SSL2.0']) 16 | assert_empty(@ex.ciphers['SSL3.0']) 17 | assert_equal('TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', @ex.ciphers['TLS1.2'][0]) 18 | assert_equal(@ex.ciphers['TLS1.3'], @ex.tls13) 19 | end 20 | 21 | skip def test_App_Extractor_ssllabs_scan 22 | # skip, done in setup 23 | end 24 | 25 | def test_App_Extractor_sslyze 26 | ex = TLSmap::App::Extractor.new 27 | assert(ex.parse('sslyze', 'test/file_sample/sslyze.json')) 28 | assert_includes(ex.ciphers['TLS1.0'], 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA') 29 | end 30 | 31 | def test_App_Extractor_sslscan2 32 | ex = TLSmap::App::Extractor.new 33 | assert(ex.parse('sslscan2', 'test/file_sample/sslscan2.xml')) 34 | assert_includes(ex.ciphers['TLS1.3'], 'TLS_CHACHA20_POLY1305_SHA256') 35 | end 36 | 37 | def test_App_Extractor_testssl 38 | ex = TLSmap::App::Extractor.new 39 | assert(ex.parse('testssl', 'test/file_sample/testssl.json')) 40 | assert_includes(ex.ciphers['TLS1.2'], 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384') 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | tls-map (1.3.2) 5 | docopt (~> 0.6) 6 | paint (~> 2.2) 7 | rexml (~> 3.2) 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | specs: 12 | ast (2.4.2) 13 | commonmarker (0.22.0) 14 | docopt (0.6.1) 15 | github-markup (4.0.0) 16 | minitest (5.14.4) 17 | minitest-skip (0.0.3) 18 | minitest (~> 5.0) 19 | paint (2.2.1) 20 | parallel (1.20.1) 21 | parser (3.0.2.0) 22 | ast (~> 2.4.1) 23 | rainbow (3.0.0) 24 | rake (13.0.6) 25 | redcarpet (3.5.1) 26 | regexp_parser (2.1.1) 27 | rexml (3.2.5) 28 | rubocop (1.18.3) 29 | parallel (~> 1.10) 30 | parser (>= 3.0.0.0) 31 | rainbow (>= 2.2.2, < 4.0) 32 | regexp_parser (>= 1.8, < 3.0) 33 | rexml 34 | rubocop-ast (>= 1.7.0, < 2.0) 35 | ruby-progressbar (~> 1.7) 36 | unicode-display_width (>= 1.4.0, < 3.0) 37 | rubocop-ast (1.8.0) 38 | parser (>= 3.0.1.1) 39 | ruby-progressbar (1.11.0) 40 | unicode-display_width (2.0.0) 41 | webrick (1.7.0) 42 | yard (0.9.26) 43 | 44 | PLATFORMS 45 | x86_64-linux 46 | 47 | DEPENDENCIES 48 | bundler (>= 2.1.0, < 2.3) 49 | commonmarker (~> 0.21) 50 | docopt (~> 0.6) 51 | github-markup (~> 4.0) 52 | minitest (~> 5.12) 53 | minitest-skip (~> 0.0) 54 | paint (~> 2.2) 55 | rake (~> 13.0) 56 | redcarpet (~> 3.5) 57 | rexml (~> 3.2) 58 | rubocop (~> 1.10) 59 | tls-map! 60 | webrick (~> 1.7) 61 | yard (~> 0.9) 62 | 63 | BUNDLED WITH 64 | 2.2.15 65 | -------------------------------------------------------------------------------- /test/test_extended.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: false 2 | 3 | require 'minitest/autorun' 4 | require 'minitest/skip_dsl' 5 | require 'tls_map' 6 | 7 | class TLSmapExtendedTest < Minitest::Test 8 | def setup 9 | @ext = TLSmap::App::Extended.new 10 | end 11 | 12 | def test_App_Extended_extend 13 | cipher = 'TLS_RSA_WITH_RC4_128_SHA' 14 | data = @ext.extend(cipher) 15 | assert_instance_of(Hash, data) 16 | assert_instance_of(String, data['protocol_version']) 17 | assert_instance_of(Array, data['tls_version']) 18 | assert_instance_of(Hash, data['vulns'][0]) 19 | assert_equal('TLS', data['protocol_version']) 20 | assert_equal('RSA', data['kex_algorithm']) 21 | assert_equal('RSA', data['auth_algorithm']) 22 | assert_equal('RC4 128', data['enc_algorithm']) 23 | assert_equal('SHA', data['hash_algorithm']) 24 | assert_equal('insecure', data['security']) 25 | assert_equal('https://ciphersuite.info/cs/TLS_RSA_WITH_RC4_128_SHA/', data['url']) 26 | end 27 | 28 | def test_App_Extended_translate_acronym 29 | assert_equal('Rivest Shamir Adleman algorithm', @ext.translate_acronym('RSA')) 30 | assert_equal('Digital Signature Standard', @ext.translate_acronym('DSS')) 31 | assert_nil(@ext.translate_acronym('PPP')) 32 | end 33 | 34 | def test_App_Extended_find_vuln 35 | data = @ext.find_vuln('MD5') 36 | assert_instance_of(Array, data) 37 | assert_instance_of(Hash, data[0]) 38 | assert_instance_of(Integer, data[0][:severity]) 39 | assert_instance_of(String, data[0][:description]) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /docs/pages/install.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Production 4 | 5 | ### Install from rubygems.org 6 | 7 | ```plaintext 8 | $ gem install tls-map 9 | ``` 10 | 11 | Gem: [tls-map](https://rubygems.org/gems/tls-map) 12 | 13 | ### Install from BlackArch 14 | 15 | From the repository: 16 | 17 | ```plaintext 18 | # pacman -S tls-map 19 | ``` 20 | 21 | PKGBUILD: [tls-map](https://github.com/BlackArch/blackarch/blob/master/packages/tls-map/PKGBUILD) 22 | 23 | ### Install from Pentoo 24 | 25 | From the repository: 26 | 27 | ```plaintext 28 | # emerge TODO/tls-map 29 | ``` 30 | 31 | ## Development 32 | 33 | It's better to use [rbenv](https://github.com/rbenv/rbenv) or [asdf](https://github.com/asdf-vm/asdf) to have latests version of ruby and to avoid trashing your system ruby. 34 | 35 | ### Install from rubygems.org 36 | 37 | ```plaintext 38 | $ gem install --development tls-map 39 | ``` 40 | 41 | ### Build from git 42 | 43 | Just replace `x.x.x` with the gem version you see after `gem build`. 44 | 45 | ```plaintext 46 | $ git clone https://github.com/sec-it/tls-map.git tls-map 47 | $ cd tls-map 48 | $ gem install bundler 49 | $ bundler install 50 | $ gem build tls-map.gemspec 51 | $ gem install tls-map-x.x.x.gem 52 | ``` 53 | 54 | Note: if an automatic install is needed you can get the version with `$ gem build tls-map.gemspec | grep Version | cut -d' ' -f4`. 55 | 56 | ### Run without installing the gem 57 | 58 | From local file: 59 | 60 | ```plaintext 61 | $ irb -Ilib -rtls_map 62 | ``` 63 | 64 | Same for the CLI tool: 65 | 66 | ```plaintext 67 | $ ruby -Ilib -rtls_map bin/tls-map 68 | ``` 69 | -------------------------------------------------------------------------------- /tls-map.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/tls_map/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'tls-map' 7 | s.version = TLSmap::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.summary = 'CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS' 10 | s.description = 'CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS' 11 | s.authors = ['Alexandre ZANNI'] 12 | s.email = 'alexandre.zanni@engineer.com' 13 | s.homepage = 'https://sec-it.github.io/tls-map/' 14 | s.license = 'MIT' 15 | 16 | s.files = Dir['bin/*'] + Dir['lib/**/*.rb'] + Dir['data/*'] + ['LICENSE'] 17 | s.bindir = 'bin' 18 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | s.require_paths = ['lib'] 20 | 21 | s.metadata = { 22 | 'yard.run' => 'yard', 23 | 'bug_tracker_uri' => 'https://github.com/sec-it/tls-map/issues', 24 | 'changelog_uri' => 'https://github.com/sec-it/tls-map/blob/master/docs/CHANGELOG.md', 25 | 'documentation_uri' => 'https://sec-it.github.io/tls-map/yard/', 26 | 'homepage_uri' => 'https://sec-it.github.io/tls-map/', 27 | 'source_code_uri' => 'https://github.com/sec-it/tls-map/' 28 | } 29 | 30 | s.required_ruby_version = ['>= 2.6.0', '< 3.1'] 31 | 32 | s.add_runtime_dependency('docopt', '~> 0.6') # for argument parsing 33 | s.add_runtime_dependency('paint', '~> 2.2') # for colorized ouput 34 | s.add_runtime_dependency('rexml', '~> 3.2') # XML parser 35 | end 36 | -------------------------------------------------------------------------------- /lib/tls_map/output.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'json' 5 | 6 | # TLS map module 7 | module TLSmap 8 | # TLS mapping 9 | class App 10 | def markdown(table) 11 | output = "Codepoint | IANA | OpenSSL | GnuTLS | NSS\n" 12 | output += "--- | --- | --- | --- | ---\n" 13 | table.each do |alg| 14 | values = alg.values.map { |x| x.nil? ? '-' : x } 15 | output += "#{values.join(' | ')}\n" 16 | end 17 | output 18 | end 19 | 20 | def output_markdown(filename) 21 | File.write(filename, markdown(@tls_map)) 22 | end 23 | 24 | def output_json_pretty(filename) 25 | File.write(filename, JSON.pretty_generate(@tls_map)) 26 | end 27 | 28 | def output_json_compact(filename) 29 | File.write(filename, JSON.generate(@tls_map)) 30 | end 31 | 32 | def output_marshal(filename) 33 | File.write(filename, Marshal.dump(@tls_map)) 34 | end 35 | 36 | # Export the mapping to a file, supporting various formats. 37 | # @param filename [String] The output file name to write to. 38 | # @param format [Symbol] Supported formats: `:markdown` (a markdown table), 39 | # `:json_pretty` (expanded JSON), `:json_compact` (minified JSON), 40 | # `:marshal` (Ruby marshalized hash). 41 | def export(filename, format) 42 | case format 43 | when :markdown then output_markdown(filename) 44 | when :json_pretty then output_json_pretty(filename) 45 | when :json_compact then output_json_compact(filename) 46 | when :marshal then output_marshal(filename) 47 | else raise "Wrong format: #{format}" 48 | end 49 | end 50 | 51 | protected :markdown, :output_markdown, :output_json_pretty, :output_json_compact, :output_marshal 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /docs/yard/file_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | File List 19 | 20 | 21 | 22 |
23 |
24 |

File List

25 |
26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
40 | 41 | 42 |
43 | 44 | 59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /test/test_app.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: false 2 | 3 | require 'minitest/autorun' 4 | require 'minitest/skip_dsl' 5 | require 'tls_map' 6 | 7 | class TLSmapAppTest < Minitest::Test 8 | def setup 9 | @tm = TLSmap::App.new 10 | end 11 | 12 | def test_App_search 13 | assert_equal({:iana=>"TLS_RSA_WITH_RC4_128_SHA"}, @tm.search(:gnutls, 'RSA_ARCFOUR_128_SHA1', :iana)) 14 | assert_equal({:iana=>"TLS_RSA_WITH_AES_128_CBC_SHA"}, @tm.search(:openssl, 'AES128-SHA', :iana)) 15 | assert_equal({:codepoint=>"0037"}, @tm.search(:iana, 'TLS_DH_RSA_WITH_AES_256_CBC_SHA', :codepoint)) 16 | assert_equal({:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"}, @tm.search(:codepoint, '1303')) 17 | assert_equal({: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"}, @tm.search(:nss, 'TLS_AES_256_GCM_SHA384')) 18 | end 19 | 20 | def test_App_bulk_search 21 | res = @tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt', :openssl) 22 | assert_equal({:openssl=>"DH-RSA-AES256-SHA"}, res[0]) 23 | assert_equal({:openssl=>"RC4-SHA"}, res[1]) 24 | assert_equal({:openssl=>"AES128-SHA"}, res[2]) 25 | assert_equal({}, res[3]) 26 | res = @tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt', :codepoint) 27 | assert_equal({:codepoint=>"1303"}, res[4]) 28 | res = @tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt', :iana) 29 | assert_equal({:iana=>"TLS_AES_256_GCM_SHA384"}, res[5]) 30 | end 31 | 32 | def test_App_export 33 | formats = [:markdown, :json_pretty, :json_compact, :marshal] 34 | formats.each do |format| 35 | tmp = Tempfile.new 36 | assert_instance_of(Integer, @tm.export(tmp.path, format)) 37 | tmp.close 38 | end 39 | assert_raises(RuntimeError, 'Wrong format: wrong') {@tm.export('/dev/shm/tlsmap', :wrong)} 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TLS map 2 | 3 | [![Gem Version](https://badge.fury.io/rb/tls-map.svg)](https://badge.fury.io/rb/tls-map) 4 | ![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/sec-it/tls-map) 5 | [![GitHub forks](https://img.shields.io/github/forks/sec-it/tls-map)](https://github.com/sec-it/tls-map/network) 6 | [![GitHub stars](https://img.shields.io/github/stars/sec-it/tls-map)](https://github.com/sec-it/tls-map/stargazers) 7 | [![GitHub license](https://img.shields.io/github/license/sec-it/tls-map)](https://github.com/sec-it/tls-map/blob/master/LICENSE.txt) 8 | [![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/tools.html#TLS%20map) 9 | 10 | [![Packaging status](https://repology.org/badge/vertical-allrepos/tls-map.svg)](https://repology.org/project/tls-map/versions) 11 | 12 | ![logo](docs/_media/logo.png) 13 | 14 | > CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS 15 | 16 | **CLI** 17 | 18 | [![asciicast](https://asciinema.org/a/410877.svg)](https://asciinema.org/a/410877) 19 | 20 | **Library** 21 | 22 | ![library example](https://i.imgur.com/3KZgZ6b.png) 23 | 24 | ## Features 25 | 26 | - CLI and library 27 | - Search feature: hexadecimal codepoint and major TLS libraries cipher algorithm name: IANA, OpenSSL, GnuTLS, NSS 28 | - get extra info about a cipher 29 | - Export to files: markdown table, expanded JSON, minified JSON, Ruby marshalized hash 30 | - Extract ciphers from external tools file output (SSLyze, sslscan2, testssl.sh, ssllabs-scan) 31 | - Bulk search (file with one cipher per line) 32 | 33 | ## Installation 34 | 35 | ```plaintext 36 | $ gem install tls-map 37 | ``` 38 | 39 | Check the [installation](https://sec-it.github.io/tls-map/#/pages/install) page on the documentation to discover more methods. 40 | 41 | ## Documentation 42 | 43 | Homepage / Documentation: https://sec-it.github.io/tls-map/ 44 | 45 | ## Author 46 | 47 | Made by Alexandre ZANNI ([@noraj](https://pwn.by/noraj/)), pentester at [SEC-IT](https://sec-it.fr). 48 | -------------------------------------------------------------------------------- /lib/tls_map/cli.rb: -------------------------------------------------------------------------------- 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 58 | -------------------------------------------------------------------------------- /docs/vendor/prismjs/components/prism-ruby.min.js: -------------------------------------------------------------------------------- 1 | !function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin\s[\s\S]*?^=end/m,greedy:!0}],"class-name":{pattern:/(\b(?:class)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.languages.ruby}};delete e.languages.ruby.function,e.languages.insertBefore("ruby","keyword",{regex:[{pattern:RegExp("%r(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1[gim]{0,3}","\\((?:[^()\\\\]|\\\\[^])*\\)[gim]{0,3}","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}[gim]{0,3}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\][gim]{0,3}","<(?:[^<>\\\\]|\\\\[^])*>[gim]{0,3}"].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[gim]{0,3}(?=\s*(?:$|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0},"method-definition":{pattern:/(\bdef\s+)[\w.]+/,lookbehind:!0,inside:{function:/\w+$/,rest:e.languages.ruby}}}),e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z]\w*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:RegExp("%[qQiIwWxs]?(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1","\\((?:[^()\\\\]|\\\\[^])*\\)","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\]","<(?:[^<>\\\\]|\\\\[^])*>"].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:n}}],e.languages.rb=e.languages.ruby}(Prism); -------------------------------------------------------------------------------- /lib/tls_map/openssl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # TLS map module 4 | module TLSmap 5 | # TLS mapping 6 | class App 7 | OPENSSL_URL = 'https://raw.githubusercontent.com/openssl/openssl/master/include/openssl/tls1.h' 8 | OPENSSL_URL2 = 'https://raw.githubusercontent.com/openssl/openssl/master/include/openssl/ssl3.h' 9 | 10 | def raw_data_openssl 11 | openssl_h = File.read(@openssl_file.path) 12 | openssl_h2 = File.read(@openssl_file2.path) 13 | 14 | ck1 = openssl_h.scan(/(TLS1_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) 15 | txt1 = openssl_h.scan(/(TLS1_TXT_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9-]+)"/) 16 | ck2 = openssl_h.scan(/(TLS1_3_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) 17 | rfc2 = openssl_h.scan(/(TLS1_3_RFC_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9_]+)"/) 18 | ck3 = openssl_h2.scan(/(SSL3_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) 19 | txt3 = openssl_h2.scan(/(SSL3_TXT_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9-]+)"/) 20 | { ck1: ck1, txt1: txt1, ck2: ck2, rfc2: rfc2, ck3: ck3, txt3: txt3 } 21 | end 22 | 23 | def clean_raw_data_openssl 24 | ck1, txt1, ck2, rfc2, ck3, txt3 = raw_data_openssl.values 25 | 26 | ck1.map! { |e| [e[0][8..], e[1]] } 27 | txt1.map! { |e| [e[0][9..], e[1]] } 28 | ck2.map! { |e| [e[0][10..], e[1]] } 29 | rfc2.map! { |e| [e[0][11..], e[1]] } 30 | ck3.map! { |e| [e[0][8..], e[1]] } 31 | txt3.map! { |e| [e[0][9..], e[1]] } 32 | 33 | { ck1: ck1, txt1: txt1, ck2: ck2, rfc2: rfc2, ck3: ck3, txt3: txt3 } 34 | end 35 | 36 | def data_openssl # rubocop:disable Metrics/CyclomaticComplexity 37 | ck1, txt1, ck2, rfc2, ck3, txt3 = clean_raw_data_openssl.values 38 | data = ck1.map { |e| [e[1], txt1.select { |x| x[0] == e[0] }[0][1]] } 39 | data += ck2.map { |e| [e[1], rfc2.select { |x| x[0] == e[0] }[0][1]] } 40 | data += ck3.map do |e| 41 | candidate = txt3.select { |x| x[0] == e[0] } 42 | [e[1], candidate.empty? ? nil : candidate[0][1]] 43 | end 44 | data 45 | end 46 | 47 | def parse_openssl 48 | data_openssl.each do |alg| 49 | @tls_map.each do |h| 50 | h[:openssl] ||= h[:codepoint] == alg[0].upcase ? alg[1] : nil 51 | end 52 | end 53 | end 54 | 55 | private :parse_openssl, :raw_data_openssl, :clean_raw_data_openssl, :data_openssl 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | 5 | ## [1.3.2] 6 | 7 | Additions: 8 | 9 | - add `helper()` method to `TLSmap::App::Extractor` so it will display a useful error message when the wrong format is provided. 10 | 11 | Chore: 12 | 13 | - New dependency requirement architecture: runtime dependencies are set both in `.gemspec` + `Gemfile` while development ones are set in `Gemfile` only. 14 | - `Gemfile` dependencies are categorized in groups. So it's now possible to exclude the _docs_ group while installing in a CI while keeping _test_ and _lint_. `.gempsec` is only able to create _runtime_ and _development_ but not custom groups. 15 | 16 | ## [1.3.1] 17 | 18 | Fixes: 19 | 20 | - `JSON.load_file()` is only available since Ruby 3.0 so `Utils.json_load_file()` was created to bring compatibility with Ruby 2.X 21 | 22 | Chore: 23 | 24 | - Convert `Utils` methods as module methods instead of instance methods 25 | 26 | ## [1.3.0] 27 | 28 | Additions: 29 | 30 | - add `bulk_search()` method for bulk search (file with one cipher per line) 31 | - new `bulk` CLI command 32 | 33 | Documentation: 34 | 35 | - add `webrick` in dev dependencies to be able to use `yard server` 36 | 37 | ## [1.2.0] 38 | 39 | Additions: 40 | 41 | - New `TLSmap::App::Extractor` class: extract ciphers from external tools file output (see [lib doc](https://sec-it.github.io/tls-map/yard/TLSmap/App/Extractor)) 42 | - Support SSLyze, sslscan2, testssl.sh, ssllabs-scan 43 | - New `extract` CLI command 44 | 45 | Documentation: 46 | 47 | - Change yard doc format from rdoc to markdown 48 | 49 | Quality: 50 | 51 | - Create unit tests 52 | 53 | ## [1.1.0] 54 | 55 | Additions: 56 | 57 | - New `TLSmap::App::Extended` class: partial wrapper around ciphersuite.info API to get extra info about a cipher 58 | - New `--extended` and `--acronym` CLI option for the `search` command using the new class 59 | 60 | Changes: 61 | 62 | - Move `tmpfile()` to a `Utils` module (no breaking changes) 63 | 64 | Fix: 65 | 66 | - fix NSS and GnuTLS parser: many ciphers were not parsed due to a wrong regexp 67 | - make search case-insensitive for hexadecimal codepoints 68 | - fix OpenSSL parser: some TLS 1.0 ciphers where defined in SSL 3.0 source code file 69 | 70 | Documentation: 71 | 72 | - Added a _limitations_ page 73 | - No SSL support 74 | - No custom cipher suites support 75 | - Unassigned and reserved codepoints are hidden 76 | 77 | ## [1.0.0] 78 | 79 | - First version 80 | -------------------------------------------------------------------------------- /docs/yard/top-level-namespace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Top Level Namespace 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Top Level Namespace 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 | 81 |

Defined Under Namespace

82 |

83 | 84 | 85 | Modules: TLSmap 86 | 87 | 88 | 89 | 90 |

91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 | 102 | 107 | 108 |
109 | 110 | -------------------------------------------------------------------------------- /lib/tls_map.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'pathname' 5 | # Project internal 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' 15 | 16 | # TLS map module 17 | module TLSmap 18 | # TLS mapping 19 | class App 20 | # Will automatically fetch source files and parse them. 21 | def initialize 22 | @iana_file = Utils.tmpfile('iana', IANA_URL) 23 | @openssl_file = Utils.tmpfile('openssl', OPENSSL_URL) 24 | @openssl_file2 = Utils.tmpfile('openssl', OPENSSL_URL2) 25 | @gnutls_file = Utils.tmpfile('gnutls', GNUTLS_URL) 26 | @nss_file = Utils.tmpfile('nss', NSS_URL) 27 | 28 | @tls_map = [] 29 | parse 30 | end 31 | 32 | def parse 33 | parse_iana # must be first 34 | parse_openssl 35 | parse_gnutls 36 | parse_nss 37 | end 38 | 39 | # Search for corresponding cipher algorithms in other libraries 40 | # @param critera [Symbol] The type of `term`. 41 | # Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`. 42 | # @param term [String] The cipher algorithm name. 43 | # @param output [Symbol] The corresponding type to be included in the return value. 44 | # Accepted values: `:all` (default), `:codepoint`, `:iana`, `:openssl`, 45 | # `:gnutls`, `:nss`. 46 | # @return [Hash] The corresponding type matching `term`. 47 | def search(critera, term, output = :all) 48 | @tls_map.each do |alg| 49 | term = term.upcase if critera == :codepoint 50 | next unless alg[critera] == term 51 | return alg if output == :all 52 | 53 | return { output => alg[output] } 54 | end 55 | {} 56 | end 57 | 58 | # Search for corresponding cipher algorithms in other libraries in bulk 59 | # @param critera [Symbol] The type of `term`. 60 | # Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`. 61 | # @param file [String] File containing the cipher algorithm names, one per line. 62 | # @param output [Symbol] The corresponding type to be included in the return value. 63 | # Accepted values: `:all` (default), `:codepoint`, `:iana`, `:openssl`, 64 | # `:gnutls`, `:nss`. 65 | # @return [Array] The corresponding type, same as {search} return value 66 | # but one per line stored in an array. 67 | def bulk_search(critera, file, output = :all) 68 | res = [] 69 | File.foreach(file) do |line| 70 | res.push(search(critera, line.chomp, output)) 71 | end 72 | res 73 | end 74 | 75 | protected :parse 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /docs/yard/file.LICENSE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: LICENSE 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 59 | 60 |

MIT License

61 | 62 |

Copyright (c) 2021 Alexandre ZANNI at SEC-IT

63 | 64 |

Permission is hereby granted, free of charge, to any person obtaining a copy 65 | of this software and associated documentation files (the "Software"), to deal 66 | in the Software without restriction, including without limitation the rights 67 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 68 | copies of the Software, and to permit persons to whom the Software is 69 | furnished to do so, subject to the following conditions:

70 | 71 |

The above copyright notice and this permission notice shall be included in all 72 | copies or substantial portions of the Software.

73 | 74 |

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 75 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 76 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 77 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 78 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 79 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 80 | SOFTWARE.

81 |
82 | 83 | 88 | 89 |
90 | 91 | -------------------------------------------------------------------------------- /docs/pages/quick-start.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | ## Quick install 4 | 5 | ```plaintext 6 | $ gem install tls-map 7 | ``` 8 | 9 | See [Installation](/pages/install) 10 | 11 | ## Default usage: CLI 12 | 13 | ```plaintext 14 | $ tls-map --help 15 | TLS map 1.3.0 16 | 17 | Usage: 18 | tls-map search [-o --force -e -a] [--no-color --debug] 19 | tls-map bulk [-q --force] [--no-color --debug] 20 | tls-map export [--force] [--debug] 21 | tls-map extract [--no-color --debug] 22 | tls-map update [--debug] 23 | tls-map -h | --help 24 | tls-map --version 25 | 26 | Search options: (offline) search and translate cipher names between SSL/TLS libraries 27 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 28 | The cipher algorithm name. 29 | -o, --output Displayed fields. Accepted values: all, codepoint, iana, openssl, gnutls, nss. [default: all] 30 | -e, --extended (Online) Display additional information about the cipher (requires output = all or iana) 31 | -a, --acronym (Online) Display full acronym name (requires -e / --extended option) 32 | 33 | Bulk options: (offline) search and translate cipher names between SSL/TLS libraries in bulk 34 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 35 | File containing the cipher algorithm names, one per line. 36 | -q, --output2 Displayed fields. Accepted values: codepoint, iana, openssl, gnutls, nss. [default: iana] 37 | 38 | Export options: (offline) export the list of all ciphers (mapping) in various formats 39 | The output file name to write to. 40 | Supported formats: markdown (a markdown table), json_pretty (expanded JSON), json_compact (minified JSON), marshal (Ruby marshalized hash). 41 | 42 | Extract options: (offline) extract ciphers from external tools output file 43 | The external tool output file 44 | Supported formats: sslyze, sslscan2, testssl, ssllabs-scan (check the documentation for the expected file format) 45 | 46 | Update options: (online) DANGEROUS, will break database integrity, force option will be required 47 | 48 | Other options: 49 | --force Force parsing even if integrity check failed (DANGEROUS, may result in command execution vulnerability) 50 | --no-color Disable colorized output 51 | --debug Display arguments 52 | -h, --help Show this screen 53 | --version Show version 54 | ``` 55 | 56 | See [Usage](/pages/usage) 57 | 58 | ## Default usage: library 59 | 60 | ```ruby 61 | require 'tls_map' 62 | 63 | tm = TLSmap::App.new 64 | 65 | # Translate from one lib to another 66 | tm.search(:gnutls, 'RSA_ARCFOUR_128_SHA1', :iana) #=> {:iana=>"TLS_RSA_WITH_RC4_128_SHA" 67 | tm.search(:openssl, 'AES128-SHA', :iana) #=> {:iana=>"TLS_RSA_WITH_AES_128_CBC_SHA"} 68 | tm.search(:iana, 'TLS_DH_RSA_WITH_AES_256_CBC_SHA', :codepoint) #=> {:codepoint=>"0037"} 69 | 70 | # Get all 71 | tm.search(:codepoint, '1303') #=> {:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"} 72 | tm.search(:nss, 'TLS_AES_256_GCM_SHA384') #=> {: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"} 73 | ``` 74 | 75 | See [Usage](/pages/usage) 76 | -------------------------------------------------------------------------------- /docs/pages/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ## CLI 4 | 5 | ```plaintext 6 | $ tls-map --help 7 | TLS map 1.3.0 8 | 9 | Usage: 10 | tls-map search [-o --force -e -a] [--no-color --debug] 11 | tls-map bulk [-q --force] [--no-color --debug] 12 | tls-map export [--force] [--debug] 13 | tls-map extract [--no-color --debug] 14 | tls-map update [--debug] 15 | tls-map -h | --help 16 | tls-map --version 17 | 18 | Search options: (offline) search and translate cipher names between SSL/TLS libraries 19 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 20 | The cipher algorithm name. 21 | -o, --output Displayed fields. Accepted values: all, codepoint, iana, openssl, gnutls, nss. [default: all] 22 | -e, --extended (Online) Display additional information about the cipher (requires output = all or iana) 23 | -a, --acronym (Online) Display full acronym name (requires -e / --extended option) 24 | 25 | Bulk options: (offline) search and translate cipher names between SSL/TLS libraries in bulk 26 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 27 | File containing the cipher algorithm names, one per line. 28 | -q, --output2 Displayed fields. Accepted values: codepoint, iana, openssl, gnutls, nss. [default: iana] 29 | 30 | Export options: (offline) export the list of all ciphers (mapping) in various formats 31 | The output file name to write to. 32 | Supported formats: markdown (a markdown table), json_pretty (expanded JSON), json_compact (minified JSON), marshal (Ruby marshalized hash). 33 | 34 | Extract options: (offline) extract ciphers from external tools output file 35 | The external tool output file 36 | Supported formats: sslyze, sslscan2, testssl, ssllabs-scan (check the documentation for the expected file format) 37 | 38 | Update options: (online) DANGEROUS, will break database integrity, force option will be required 39 | 40 | Other options: 41 | --force Force parsing even if integrity check failed (DANGEROUS, may result in command execution vulnerability) 42 | --no-color Disable colorized output 43 | --debug Display arguments 44 | -h, --help Show this screen 45 | --version Show version 46 | ``` 47 | 48 | See [Examples](/pages/examples) 49 | 50 | ## Library 51 | 52 | ```ruby 53 | require 'tls_map' 54 | 55 | tm = TLSmap::App.new 56 | 57 | # Translate from one lib to another 58 | tm.search(:gnutls, 'RSA_ARCFOUR_128_SHA1', :iana) #=> {:iana=>"TLS_RSA_WITH_RC4_128_SHA"} 59 | tm.search(:openssl, 'AES128-SHA', :iana) #=> {:iana=>"TLS_RSA_WITH_AES_128_CBC_SHA"} 60 | tm.search(:iana, 'TLS_DH_RSA_WITH_AES_256_CBC_SHA', :codepoint) #=> {:codepoint=>"0037"} 61 | 62 | # Get all 63 | tm.search(:codepoint, '1303') #=> {:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"} 64 | tm.search(:nss, 'TLS_AES_256_GCM_SHA384') #=> {: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"} 65 | ``` 66 | 67 | See [Examples](/pages/examples) or [the library doc](https://sec-it.github.io/tls-map/yard/TLSmap/App.html) 68 | 69 | ## Console 70 | 71 | Launch `irb` with the library loaded. 72 | 73 | ```plaintext 74 | $ tls-map_console 75 | irb(main):001:0> 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/yard/TLSmap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: TLSmap 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: TLSmap 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
Defined in:
81 |
lib/tls_map.rb,
82 | lib/tls_map/cli.rb,
lib/tls_map/nss.rb,
lib/tls_map/iana.rb,
lib/tls_map/utils.rb,
lib/tls_map/gnutls.rb,
lib/tls_map/output.rb,
lib/tls_map/openssl.rb,
lib/tls_map/version.rb,
lib/tls_map/extractor.rb,
lib/tls_map/ciphersuiteinfo.rb
83 |
84 |
85 | 86 |
87 | 88 |

Overview

89 |
90 |

TLS map module

91 | 92 | 93 |
94 |
95 |
96 | 97 | 98 |

Defined Under Namespace

99 |

100 | 101 | 102 | Modules: Utils 103 | 104 | 105 | 106 | Classes: App, CLI 107 | 108 | 109 |

110 | 111 | 112 |

113 | Constant Summary 114 | collapse 115 |

116 | 117 |
118 | 119 |
VERSION = 120 | 121 |
122 |
'1.3.2'
123 | 124 |
125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 | 142 | 143 |
144 | 145 | -------------------------------------------------------------------------------- /docs/yard/class_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Class List 19 | 20 | 21 | 22 |
23 |
24 |

Class List

25 |
26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
40 | 41 | 42 |
43 | 44 | 49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/yard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: README 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 59 | 60 |

TLS map

61 | 62 |

Gem Version 63 | GitHub tag (latest SemVer) 64 | GitHub forks 65 | GitHub stars 66 | GitHub license 67 | Rawsec's CyberSecurity Inventory

68 | 69 |

Packaging status

70 | 71 |

logo

72 | 73 |
74 |

CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS

75 |
76 | 77 |

CLI

78 | 79 |

asciicast

80 | 81 |

Library

82 | 83 |

library example

84 | 85 |

Features

86 | 87 |
    88 |
  • CLI and library
  • 89 |
  • Search feature: hexadecimal codepoint and major TLS libraries cipher algorithm name: IANA, OpenSSL, GnuTLS, NSS 90 | 91 |
      92 |
    • get extra info about a cipher
    • 93 |
  • 94 |
  • Export to files: markdown table, expanded JSON, minified JSON, Ruby marshalized hash
  • 95 |
  • Extract ciphers from external tools file output (SSLyze, sslscan2, testssl.sh, ssllabs-scan)
  • 96 |
  • Bulk search (file with one cipher per line)
  • 97 |
98 | 99 |

Installation

100 | 101 |
$ gem install tls-map
102 | 
103 | 104 |

Check the installation page on the documentation to discover more methods.

105 | 106 |

Documentation

107 | 108 |

Homepage / Documentation: https://sec-it.github.io/tls-map/

109 | 110 |

Author

111 | 112 |

Made by Alexandre ZANNI (@noraj), pentester at SEC-IT.

113 |
114 | 115 | 120 | 121 |
122 | 123 | -------------------------------------------------------------------------------- /docs/yard/file.README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: README 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 59 | 60 |

TLS map

61 | 62 |

Gem Version 63 | GitHub tag (latest SemVer) 64 | GitHub forks 65 | GitHub stars 66 | GitHub license 67 | Rawsec's CyberSecurity Inventory

68 | 69 |

Packaging status

70 | 71 |

logo

72 | 73 |
74 |

CLI & library for mapping TLS cipher algorithm names: IANA, OpenSSL, GnuTLS, NSS

75 |
76 | 77 |

CLI

78 | 79 |

asciicast

80 | 81 |

Library

82 | 83 |

library example

84 | 85 |

Features

86 | 87 |
    88 |
  • CLI and library
  • 89 |
  • Search feature: hexadecimal codepoint and major TLS libraries cipher algorithm name: IANA, OpenSSL, GnuTLS, NSS 90 | 91 |
      92 |
    • get extra info about a cipher
    • 93 |
  • 94 |
  • Export to files: markdown table, expanded JSON, minified JSON, Ruby marshalized hash
  • 95 |
  • Extract ciphers from external tools file output (SSLyze, sslscan2, testssl.sh, ssllabs-scan)
  • 96 |
  • Bulk search (file with one cipher per line)
  • 97 |
98 | 99 |

Installation

100 | 101 |
$ gem install tls-map
102 | 
103 | 104 |

Check the installation page on the documentation to discover more methods.

105 | 106 |

Documentation

107 | 108 |

Homepage / Documentation: https://sec-it.github.io/tls-map/

109 | 110 |

Author

111 | 112 |

Made by Alexandre ZANNI (@noraj), pentester at SEC-IT.

113 |
114 | 115 | 120 | 121 |
122 | 123 | -------------------------------------------------------------------------------- /lib/tls_map/ciphersuiteinfo.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'net/http' 5 | require 'json' 6 | require 'yaml' 7 | # Project internal 8 | 9 | # TLS map module 10 | module TLSmap 11 | class App 12 | # Partial wrapper around ciphersuite.info API to get extra info about a cipher 13 | # 14 | # Documentation: 15 | # 16 | # - https://ciphersuite.info/blog/2019/04/05/how-to-use-our-api/ 17 | # - https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md 18 | # - https://ciphersuite.info/api/ 19 | # - https://github.com/hcrudolph/ciphersuite.info 20 | class Extended 21 | # Root URL of Cipher Suite Info 22 | ROOT = 'https://ciphersuite.info/' 23 | # Root URL of Cipher Suite Info API 24 | API_ROOT = "#{ROOT}api/" 25 | # URL of the data file containig vulnerabilities information 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 28 | TECH_DATA = 'https://raw.githubusercontent.com/hcrudolph/ciphersuite.info/master/directory/fixtures/01_technologies.yaml' 29 | # Hash mapping API key and display name for CLI 30 | DICO = { 31 | 'tls_version' => 'TLS Version(s)', 32 | 'protocol_version' => 'Protocol', 33 | 'kex_algorithm' => 'Key Exchange', 34 | 'auth_algorithm' => 'Authentication', 35 | 'enc_algorithm' => 'Encryption', 36 | 'hash_algorithm' => 'Hash', 37 | 'security' => 'Security', 38 | 'url' => 'More info', 39 | 'vulns' => 'Vulnerabilities' 40 | }.freeze 41 | # Hash mapping the severity number used by the API and the severity text and color for the CLI 42 | VULN_SEVERITY = { 43 | 0 => { title: 'Low', color: :yellow }, 44 | 1 => { title: 'Medium', color: 'orange' }, 45 | 2 => { title: 'High', color: :red } 46 | }.freeze 47 | 48 | # Will automatically fetch source files and parse them. 49 | def initialize 50 | @tech_file = Utils.tmpfile('tech', TECH_DATA) 51 | @vuln_file = Utils.tmpfile('vuln', VULN_DATA) 52 | @tech = parse_tech 53 | @vuln = parse_vuln 54 | end 55 | 56 | # Retrieve advanced about a cipher on Cipher Suite Info API and enhanced it 57 | # @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 59 | # except `vulns` which is an array of hashes containing two keys: `:severity` (integer) and `:description` 60 | # (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] 64 | out.store('vulns', []) 65 | %w[openssl_name gnutls_name hex_byte_1 hex_byte_2].each do |key| 66 | out.delete(key) 67 | end 68 | out.each_value do |v| 69 | out['vulns'].push(find_vuln(v)) if @tech.keys.include?(v) 70 | end 71 | out['vulns'].flatten! 72 | out['vulns'].uniq! 73 | out.store('url', "#{ROOT}cs/#{iana_name}/") # Add upstream URL 74 | out 75 | end 76 | 77 | # Extract data from the YAML file ({TECH_DATA}) to craft a simplified Ruby hash 78 | def parse_tech 79 | data = Psych.load_file(@tech_file) 80 | out = {} 81 | data.each do |item| 82 | out.store(item['pk'], { long_name: item['fields']['long_name'], 83 | vulnerabilities: item['fields']['vulnerabilities'] }) 84 | end 85 | out 86 | end 87 | 88 | # Extract data from the YAML file ({VULN_DATA}) to craft a simplified Ruby hash 89 | def parse_vuln 90 | data = Psych.load_file(@vuln_file) 91 | out = {} 92 | data.each do |item| 93 | out.store(item['pk'], { severity: item['fields']['severity'], 94 | description: item['fields']['description'] }) 95 | end 96 | out 97 | end 98 | 99 | # Translate cipher related acronyms 100 | # @param term [String] Acronym, eg. DSS 101 | # @return [String] The long name of the acronym, eg. Digital Signature Standard or `nil` if it's not found 102 | def translate_acronym(term) 103 | return @tech[term][:long_name] unless @tech[term].nil? 104 | 105 | nil 106 | end 107 | 108 | # Find vulnerabilities related to a technology 109 | # @param tech [String] The technology acronym, eg. CBC 110 | # @return [Array] Array of vulnerabilities as described for {extend} return value in the `vulns` key. 111 | def find_vuln(tech) 112 | return @tech[tech][:vulnerabilities].map { |vuln| @vuln[vuln] } unless @tech[tech][:vulnerabilities].nil? 113 | 114 | nil 115 | end 116 | 117 | protected :parse_tech, :parse_vuln 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /bin/tls-map: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # Ruby internal 5 | require 'pp' 6 | # Project internal 7 | require 'tls_map' 8 | require 'tls_map/cli' 9 | # External 10 | require 'docopt' 11 | require 'paint' 12 | 13 | # can't specify 2 options with the same name even if used in different commands 14 | # https://github.com/docopt/docopt/issues/296#issuecomment-857477191 15 | doc = <<~DOCOPT 16 | TLS map #{TLSmap::VERSION} 17 | 18 | Usage: 19 | tls-map search [-o --force -e -a] [--no-color --debug] 20 | tls-map bulk [-q --force] [--no-color --debug] 21 | tls-map export [--force] [--debug] 22 | tls-map extract [--no-color --debug] 23 | tls-map update [--debug] 24 | tls-map -h | --help 25 | tls-map --version 26 | 27 | Search options: (offline) search and translate cipher names between SSL/TLS libraries 28 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 29 | The cipher algorithm name. 30 | -o, --output Displayed fields. Accepted values: all, codepoint, iana, openssl, gnutls, nss. [default: all] 31 | -e, --extended (Online) Display additional information about the cipher (requires output = all or iana) 32 | -a, --acronym (Online) Display full acronym name (requires -e / --extended option) 33 | 34 | Bulk options: (offline) search and translate cipher names between SSL/TLS libraries in bulk 35 | The type of term. Accepted values: codepoint, iana, openssl, gnutls, nss. 36 | File containing the cipher algorithm names, one per line. 37 | -q, --output2 Displayed fields. Accepted values: codepoint, iana, openssl, gnutls, nss. [default: iana] 38 | 39 | Export options: (offline) export the list of all ciphers (mapping) in various formats 40 | The output file name to write to. 41 | Supported formats: markdown (a markdown table), json_pretty (expanded JSON), json_compact (minified JSON), marshal (Ruby marshalized hash). 42 | 43 | Extract options: (offline) extract ciphers from external tools output file 44 | The external tool output file 45 | Supported formats: sslyze, sslscan2, testssl, ssllabs-scan (check the documentation for the expected file format) 46 | 47 | Update options: (online) DANGEROUS, will break database integrity, force option will be required 48 | 49 | Other options: 50 | --force Force parsing even if integrity check failed (DANGEROUS, may result in command execution vulnerability) 51 | --no-color Disable colorized output 52 | --debug Display arguments 53 | -h, --help Show this screen 54 | --version Show version 55 | DOCOPT 56 | 57 | begin 58 | args = Docopt.docopt(doc, version: TLSmap::VERSION) 59 | Paint.mode = 0 if args['--no-color'] 60 | pp args if args['--debug'] 61 | if args['search'] 62 | cli = TLSmap::CLI.new(args['--force']) 63 | res = cli.search(args[''].to_sym, args[''], args['--output'].to_sym) 64 | puts Paint['No match found', :red] if res.empty? 65 | res.each do |k, v| 66 | puts "#{Paint[k, :green]}: #{Paint[v, :white]}" 67 | end 68 | if args['--extended'] 69 | tmext = TLSmap::App::Extended 70 | tmext_i = tmext.new 71 | ext = tmext_i.extend(res[:iana]) 72 | dic = tmext::DICO 73 | sev = tmext::VULN_SEVERITY 74 | ext.each do |k, v| 75 | case k 76 | when 'vulns' 77 | puts "#{Paint[dic[k], :magenta]}:" 78 | v.each do |vuln| 79 | print " - #{Paint[sev[vuln[:severity]][:title], sev[vuln[:severity]][:color]]} - " 80 | puts Paint[vuln[:description], :white] 81 | end 82 | when 'tls_version' 83 | puts "#{Paint[dic[k], :magenta]}: #{Paint[v.join(', '), :white]}" 84 | else 85 | print "#{Paint[dic[k], :magenta]}: #{Paint[v, :white]}" 86 | print " (#{tmext_i.translate_acronym(v)})" if args['--acronym'] && !tmext_i.translate_acronym(v).nil? # rubocop:disable Metrics/BlockNesting 87 | puts 88 | end 89 | end 90 | end 91 | elsif args['bulk'] 92 | cli = TLSmap::CLI.new(args['--force']) 93 | res = cli.bulk_search(args[''].to_sym, args[''], args['--output2'].to_sym) 94 | puts Paint['No match found', :red] if res.empty? 95 | res.each do |h| 96 | puts Paint[h[args['--output2'].to_sym], :green] 97 | end 98 | elsif args['export'] 99 | cli = TLSmap::CLI.new(args['--force']) 100 | cli.export(args[''], args[''].to_sym) 101 | puts "#{args['']} exported" 102 | elsif args['extract'] 103 | extractor = TLSmap::App::Extractor.new 104 | ciphers = extractor.parse(args[''], args['']) 105 | ciphers.each do |k, v| 106 | puts Paint[k, :blue] unless v.empty? 107 | puts Paint[v.join("\n"), :white] unless v.empty? 108 | end 109 | elsif args['update'] 110 | cli = TLSmap::CLI.new 111 | cli.update 112 | puts 'Database updated' 113 | end 114 | rescue Docopt::Exit => e 115 | puts e.message 116 | end 117 | -------------------------------------------------------------------------------- /docs/yard/css/full_list.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 4 | font-size: 13px; 5 | height: 101%; 6 | overflow-x: hidden; 7 | background: #fafafa; 8 | } 9 | 10 | h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } 11 | .clear { clear: both; } 12 | .fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } 13 | #search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } 14 | #content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } 15 | #full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } 16 | #full_list ul { padding: 0; } 17 | #full_list li { padding: 0; margin: 0; list-style: none; } 18 | #full_list li .item { padding: 5px 5px 5px 12px; } 19 | #noresults { padding: 7px 12px; background: #fff; } 20 | #content.insearch #noresults { margin-left: 7px; } 21 | li.collapsed ul { display: none; } 22 | li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } 23 | li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } 24 | li { color: #888; cursor: pointer; } 25 | li.deprecated { text-decoration: line-through; font-style: italic; } 26 | li.odd { background: #f0f0f0; } 27 | li.even { background: #fafafa; } 28 | .item:hover { background: #ddd; } 29 | li small:before { content: "("; } 30 | li small:after { content: ")"; } 31 | li small.search_info { display: none; } 32 | a, a:visited { text-decoration: none; color: #05a; } 33 | li.clicked > .item { background: #05a; color: #ccc; } 34 | li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } 35 | li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } 36 | li.collapsed.clicked a.toggle { background-position: top right; } 37 | #search input { border: 1px solid #bbb; border-radius: 3px; } 38 | #full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } 39 | #full_list_nav a, #nav a:visited { color: #358; } 40 | #full_list_nav a:hover { background: transparent; color: #5af; } 41 | #full_list_nav span:after { content: ' | '; } 42 | #full_list_nav span:last-child:after { content: ''; } 43 | 44 | #content h1 { margin-top: 0; } 45 | li { white-space: nowrap; cursor: normal; } 46 | li small { display: block; font-size: 0.8em; } 47 | li small:before { content: ""; } 48 | li small:after { content: ""; } 49 | li small.search_info { display: none; } 50 | #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } 51 | #content.insearch #search { background-position: center right; } 52 | #search input { width: 110px; } 53 | 54 | #full_list.insearch ul { display: block; } 55 | #full_list.insearch .item { display: none; } 56 | #full_list.insearch .found { display: block; padding-left: 11px !important; } 57 | #full_list.insearch li a.toggle { display: none; } 58 | #full_list.insearch li small.search_info { display: block; } 59 | -------------------------------------------------------------------------------- /docs/yard/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation by YARD 0.9.26 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 |
34 | 54 | 55 |

Documentation by YARD 0.9.26

56 |
57 |

Alphabetic Index

58 | 59 |

File Listing

60 | 70 | 71 |
72 |

Namespace Listing A-Z

73 | 74 | 75 | 76 | 77 | 78 | 79 | 198 | 199 |
80 | 81 | 82 |
    83 |
  • A
  • 84 |
      85 | 86 |
    • 87 | App 88 | 89 | (TLSmap) 90 | 91 |
    • 92 | 93 |
    94 |
95 | 96 | 97 |
    98 |
  • C
  • 99 |
      100 | 101 |
    • 102 | CLI 103 | 104 | (TLSmap) 105 | 106 |
    • 107 | 108 |
    109 |
110 | 111 | 112 |
    113 |
  • E
  • 114 |
      115 | 116 |
    • 117 | Extended 118 | 119 | (TLSmap::App) 120 | 121 |
    • 122 | 123 |
    • 124 | Extractor 125 | 126 | (TLSmap::App) 127 | 128 |
    • 129 | 130 |
    131 |
132 | 133 | 134 |
    135 |
  • S
  • 136 |
      137 | 138 |
    • 139 | SsllabsScan 140 | 141 | (TLSmap::App::Extractor) 142 | 143 |
    • 144 | 145 |
    • 146 | Sslscan2 147 | 148 | (TLSmap::App::Extractor) 149 | 150 |
    • 151 | 152 |
    • 153 | Sslyze 154 | 155 | (TLSmap::App::Extractor) 156 | 157 |
    • 158 | 159 |
    160 |
161 | 162 | 163 |
    164 |
  • T
  • 165 |
      166 | 167 |
    • 168 | TLSmap 169 | 170 |
    • 171 | 172 |
    • 173 | Testssl 174 | 175 | (TLSmap::App::Extractor) 176 | 177 |
    • 178 | 179 |
    180 |
181 | 182 | 183 |
    184 |
  • U
  • 185 |
      186 | 187 |
    • 188 | Utils 189 | 190 | (TLSmap) 191 | 192 |
    • 193 | 194 |
    195 |
196 | 197 |
200 | 201 |
202 | 203 |
204 | 205 | 210 | 211 |
212 | 213 | -------------------------------------------------------------------------------- /docs/yard/js/full_list.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var $clicked = $(null); 4 | var searchTimeout = null; 5 | var searchCache = []; 6 | var caseSensitiveMatch = false; 7 | var ignoreKeyCodeMin = 8; 8 | var ignoreKeyCodeMax = 46; 9 | var commandKey = 91; 10 | 11 | RegExp.escape = function(text) { 12 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 13 | } 14 | 15 | function escapeShortcut() { 16 | $(document).keydown(function(evt) { 17 | if (evt.which == 27) { 18 | window.parent.postMessage('navEscape', '*'); 19 | } 20 | }); 21 | } 22 | 23 | function navResizer() { 24 | $(window).mousemove(function(e) { 25 | window.parent.postMessage({ 26 | action: 'mousemove', event: {pageX: e.pageX, which: e.which} 27 | }, '*'); 28 | }).mouseup(function(e) { 29 | window.parent.postMessage({action: 'mouseup'}, '*'); 30 | }); 31 | window.parent.postMessage("navReady", "*"); 32 | } 33 | 34 | function clearSearchTimeout() { 35 | clearTimeout(searchTimeout); 36 | searchTimeout = null; 37 | } 38 | 39 | function enableLinks() { 40 | // load the target page in the parent window 41 | $('#full_list li').on('click', function(evt) { 42 | $('#full_list li').removeClass('clicked'); 43 | $clicked = $(this); 44 | $clicked.addClass('clicked'); 45 | evt.stopPropagation(); 46 | 47 | if (evt.target.tagName === 'A') return true; 48 | 49 | var elem = $clicked.find('> .item .object_link a')[0]; 50 | var e = evt.originalEvent; 51 | var newEvent = new MouseEvent(evt.originalEvent.type); 52 | newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); 53 | elem.dispatchEvent(newEvent); 54 | evt.preventDefault(); 55 | return false; 56 | }); 57 | } 58 | 59 | function enableToggles() { 60 | // show/hide nested classes on toggle click 61 | $('#full_list a.toggle').on('click', function(evt) { 62 | evt.stopPropagation(); 63 | evt.preventDefault(); 64 | $(this).parent().parent().toggleClass('collapsed'); 65 | highlight(); 66 | }); 67 | } 68 | 69 | function populateSearchCache() { 70 | $('#full_list li .item').each(function() { 71 | var $node = $(this); 72 | var $link = $node.find('.object_link a'); 73 | if ($link.length > 0) { 74 | searchCache.push({ 75 | node: $node, 76 | link: $link, 77 | name: $link.text(), 78 | fullName: $link.attr('title').split(' ')[0] 79 | }); 80 | } 81 | }); 82 | } 83 | 84 | function enableSearch() { 85 | $('#search input').keyup(function(event) { 86 | if (ignoredKeyPress(event)) return; 87 | if (this.value === "") { 88 | clearSearch(); 89 | } else { 90 | performSearch(this.value); 91 | } 92 | }); 93 | 94 | $('#full_list').after(""); 95 | } 96 | 97 | function ignoredKeyPress(event) { 98 | if ( 99 | (event.keyCode > ignoreKeyCodeMin && event.keyCode < ignoreKeyCodeMax) || 100 | (event.keyCode == commandKey) 101 | ) { 102 | return true; 103 | } else { 104 | return false; 105 | } 106 | } 107 | 108 | function clearSearch() { 109 | clearSearchTimeout(); 110 | $('#full_list .found').removeClass('found').each(function() { 111 | var $link = $(this).find('.object_link a'); 112 | $link.text($link.text()); 113 | }); 114 | $('#full_list, #content').removeClass('insearch'); 115 | $clicked.parents().removeClass('collapsed'); 116 | highlight(); 117 | } 118 | 119 | function performSearch(searchString) { 120 | clearSearchTimeout(); 121 | $('#full_list, #content').addClass('insearch'); 122 | $('#noresults').text('').hide(); 123 | partialSearch(searchString, 0); 124 | } 125 | 126 | function partialSearch(searchString, offset) { 127 | var lastRowClass = ''; 128 | var i = null; 129 | for (i = offset; i < Math.min(offset + 50, searchCache.length); i++) { 130 | var item = searchCache[i]; 131 | var searchName = (searchString.indexOf('::') != -1 ? item.fullName : item.name); 132 | var matchString = buildMatchString(searchString); 133 | var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); 134 | if (searchName.match(matchRegexp) == null) { 135 | item.node.removeClass('found'); 136 | item.link.text(item.link.text()); 137 | } 138 | else { 139 | item.node.addClass('found'); 140 | item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1'); 141 | lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; 142 | item.link.html(item.name.replace(matchRegexp, "$&")); 143 | } 144 | } 145 | if(i == searchCache.length) { 146 | searchDone(); 147 | } else { 148 | searchTimeout = setTimeout(function() { 149 | partialSearch(searchString, i); 150 | }, 0); 151 | } 152 | } 153 | 154 | function searchDone() { 155 | searchTimeout = null; 156 | highlight(); 157 | if ($('#full_list li:visible').size() === 0) { 158 | $('#noresults').text('No results were found.').hide().fadeIn(); 159 | } else { 160 | $('#noresults').text('').hide(); 161 | } 162 | $('#content').removeClass('insearch'); 163 | } 164 | 165 | function buildMatchString(searchString, event) { 166 | caseSensitiveMatch = searchString.match(/[A-Z]/) != null; 167 | var regexSearchString = RegExp.escape(searchString); 168 | if (caseSensitiveMatch) { 169 | regexSearchString += "|" + 170 | $.map(searchString.split(''), function(e) { return RegExp.escape(e); }). 171 | join('.+?'); 172 | } 173 | return regexSearchString; 174 | } 175 | 176 | function highlight() { 177 | $('#full_list li:visible').each(function(n) { 178 | $(this).removeClass('even odd').addClass(n % 2 == 0 ? 'odd' : 'even'); 179 | }); 180 | } 181 | 182 | /** 183 | * Expands the tree to the target element and its immediate 184 | * children. 185 | */ 186 | function expandTo(path) { 187 | var $target = $(document.getElementById('object_' + path)); 188 | $target.addClass('clicked'); 189 | $target.removeClass('collapsed'); 190 | $target.parentsUntil('#full_list', 'li').removeClass('collapsed'); 191 | if($target[0]) { 192 | window.scrollTo(window.scrollX, $target.offset().top - 250); 193 | highlight(); 194 | } 195 | } 196 | 197 | function windowEvents(event) { 198 | var msg = event.data; 199 | if (msg.action === "expand") { 200 | expandTo(msg.path); 201 | } 202 | return false; 203 | } 204 | 205 | window.addEventListener("message", windowEvents, false); 206 | 207 | $(document).ready(function() { 208 | escapeShortcut(); 209 | navResizer(); 210 | enableLinks(); 211 | enableToggles(); 212 | populateSearchCache(); 213 | enableSearch(); 214 | }); 215 | 216 | })(); 217 | -------------------------------------------------------------------------------- /docs/vendor/plugins/search.min.js: -------------------------------------------------------------------------------- 1 | !function(){var u={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function p(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function h(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function g(i,e,r,o){void 0===e&&(e="");var s,e=window.marked.lexer(e),c=window.Docsify.slugify,d={},l="";return e.forEach(function(e){if("heading"===e.type&&e.depth<=o){var n=function(e){void 0===e&&(e="");var a={};return{str:e=e&&e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(a[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:a}}(e.text),t=n.str,n=n.config;s=n.id?r.toURL(i,{id:c(n.id)}):r.toURL(i,{id:c((n=e.text,a={"&":"&","<":"<",">":">",'"':""","'":"'"},String(n).replace(/[&<>"']/g,function(e){return a[e]})))}),t&&(l=t.replace(//,"").replace(/{docsify-ignore}/,"").replace(//,"").replace(/{docsify-ignore-all}/,"").trim()),d[s]={slug:s,title:l,body:""}}else{if(!s)return;d[s]?d[s].body?(e.text=p(e),e.text=h(e),d[s].body+="\n"+(e.text||"")):(e.text=p(e),e.text=h(e),d[s].body=d[s].body?d[s].body+e.text:e.text):d[s]={slug:s,title:"",body:""}}var a}),c.clear(),d}function f(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function r(i,r){var t,a,n,e,o="auto"===i.paths,s=o?(t=r.router,a=[],Docsify.dom.findAll(".sidebar-nav a:not(.section-link):not([data-nosearch])").forEach(function(e){var n=e.href,e=e.getAttribute("href"),n=t.parse(n).path;n&&-1===a.indexOf(n)&&!Docsify.util.isAbsolutePath(e)&&a.push(n)}),a):i.paths,c="";s.length&&o&&i.pathNamespaces?(n=s[0],Array.isArray(i.pathNamespaces)?c=i.pathNamespaces.filter(function(e){return n.slice(0,e.length)===e})[0]||c:i.pathNamespaces instanceof RegExp&&((d=n.match(i.pathNamespaces))&&(c=d[0])),e=-1===s.indexOf(c+"/"),d=-1===s.indexOf(c+"/README"),e&&d&&s.unshift(c+"/")):-1===s.indexOf("/")&&-1===s.indexOf("/README")&&s.unshift("/");var d,l=((d=i.namespace)?m.EXPIRE_KEY+"/"+d:m.EXPIRE_KEY)+c,p=((d=i.namespace)?m.INDEX_KEY+"/"+d:m.INDEX_KEY)+c,c=localStorage.getItem(l)l.length&&(a=l.length),t="..."+c.substring(n,a).replace(t,function(e){return''+e+""})+"...",o+=t)}),0\n

'+e.title+"

\n

"+e.content+"

\n\n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'

'+s+"

",o.hideOtherSidebarContent&&(i.classList.add("hide"),n.classList.add("hide"))}function d(e){o=e}function l(e,n){var t,a,i=n.router.parse().query.s;d(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n='
\n \n
\n \n \n \n \n \n
\n
\n
\n ',e=Docsify.dom.create("div",n),n=Docsify.dom.find("aside");Docsify.dom.toggleClass(e,"search"),Docsify.dom.before(n,e)}(i),n=Docsify.dom.find("div.search"),a=Docsify.dom.find(n,"input"),e=Docsify.dom.find(n,".input-wrap"),Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(a,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return c(n.target.value.trim())},100)}),Docsify.dom.on(e,"click",function(e){"INPUT"!==e.target.tagName&&(a.value="",c())}),i&&setTimeout(function(e){return c(i)},500)}function y(e,n){var t,a,i,r,o;d(e),t=e.placeholder,a=n.route.path,(r=Docsify.dom.getNode('.search input[type="search"]'))&&("string"==typeof t?r.placeholder=t:(i=Object.keys(t).filter(function(e){return-1 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | sha256WithRSAEncryption 70 | 71 | 72 | 73 | 74 | false 75 | Nov 24 00:00:00 2020 GMT 76 | Dec 25 23:59:59 2021 GMT 77 | false 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/yard/TLSmap/Utils.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: TLSmap::Utils 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: TLSmap::Utils 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
Defined in:
81 |
lib/tls_map/utils.rb
82 |
83 | 84 |
85 | 86 |

Overview

87 |
88 |

Generic utilities

89 | 90 | 91 |
92 |
93 |
94 | 95 | 96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 |

105 | Class Method Summary 106 | collapse 107 |

108 | 109 | 157 | 158 | 159 | 160 | 161 |
162 |

Class Method Details

163 | 164 | 165 |
166 |

167 | 168 | .json_load_file(filespec, opts = {}) ⇒ Object 169 | 170 | 171 | 172 | 173 | 174 |

175 |
176 |

bring JSON.load_file before ruby 3.0.0 177 | https://ruby-doc.org/stdlib-3.0.0/libdoc/json/rdoc/JSON.html#method-i-load_file

178 | 179 | 180 |
181 |
182 |
183 | 184 | 185 |
186 | 187 | 199 | 210 | 211 |
188 |
189 | 
190 | 
191 | 21
192 | 22
193 | 23
194 | 24
195 | 25
196 | 26
197 | 27
198 |
200 |
# File 'lib/tls_map/utils.rb', line 21
201 | 
202 | def self.json_load_file(filespec, opts = {})
203 |   if RUBY_VERSION < '3.0.0'
204 |     JSON.parse(File.read(filespec), opts)
205 |   else
206 |     JSON.load_file(filespec, opts)
207 |   end
208 | end
209 |
212 |
213 | 214 |
215 |

216 | 217 | .tmpfile(name, url) ⇒ Object 218 | 219 | 220 | 221 | 222 | 223 |

224 | 225 | 236 | 246 | 247 |
226 |
227 | 
228 | 
229 | 12
230 | 13
231 | 14
232 | 15
233 | 16
234 | 17
235 |
237 |
# File 'lib/tls_map/utils.rb', line 12
238 | 
239 | def self.tmpfile(name, url)
240 |   tmp = Tempfile.new(name)
241 |   tmp.write(Net::HTTP.get(URI(url)))
242 |   tmp.close
243 |   tmp
244 | end
245 |
248 |
249 | 250 |
251 | 252 |
253 | 254 | 259 | 260 |
261 | 262 | -------------------------------------------------------------------------------- /docs/yard/js/app.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var localStorage = {}, sessionStorage = {}; 4 | try { localStorage = window.localStorage; } catch (e) { } 5 | try { sessionStorage = window.sessionStorage; } catch (e) { } 6 | 7 | function createSourceLinks() { 8 | $('.method_details_list .source_code'). 9 | before("[View source]"); 10 | $('.toggleSource').toggle(function() { 11 | $(this).parent().nextAll('.source_code').slideDown(100); 12 | $(this).text("Hide source"); 13 | }, 14 | function() { 15 | $(this).parent().nextAll('.source_code').slideUp(100); 16 | $(this).text("View source"); 17 | }); 18 | } 19 | 20 | function createDefineLinks() { 21 | var tHeight = 0; 22 | $('.defines').after(" more..."); 23 | $('.toggleDefines').toggle(function() { 24 | tHeight = $(this).parent().prev().height(); 25 | $(this).prev().css('display', 'inline'); 26 | $(this).parent().prev().height($(this).parent().height()); 27 | $(this).text("(less)"); 28 | }, 29 | function() { 30 | $(this).prev().hide(); 31 | $(this).parent().prev().height(tHeight); 32 | $(this).text("more..."); 33 | }); 34 | } 35 | 36 | function createFullTreeLinks() { 37 | var tHeight = 0; 38 | $('.inheritanceTree').toggle(function() { 39 | tHeight = $(this).parent().prev().height(); 40 | $(this).parent().toggleClass('showAll'); 41 | $(this).text("(hide)"); 42 | $(this).parent().prev().height($(this).parent().height()); 43 | }, 44 | function() { 45 | $(this).parent().toggleClass('showAll'); 46 | $(this).parent().prev().height(tHeight); 47 | $(this).text("show all"); 48 | }); 49 | } 50 | 51 | function searchFrameButtons() { 52 | $('.full_list_link').click(function() { 53 | toggleSearchFrame(this, $(this).attr('href')); 54 | return false; 55 | }); 56 | window.addEventListener('message', function(e) { 57 | if (e.data === 'navEscape') { 58 | $('#nav').slideUp(100); 59 | $('#search a').removeClass('active inactive'); 60 | $(window).focus(); 61 | } 62 | }); 63 | 64 | $(window).resize(function() { 65 | if ($('#search:visible').length === 0) { 66 | $('#nav').removeAttr('style'); 67 | $('#search a').removeClass('active inactive'); 68 | $(window).focus(); 69 | } 70 | }); 71 | } 72 | 73 | function toggleSearchFrame(id, link) { 74 | var frame = $('#nav'); 75 | $('#search a').removeClass('active').addClass('inactive'); 76 | if (frame.attr('src') === link && frame.css('display') !== "none") { 77 | frame.slideUp(100); 78 | $('#search a').removeClass('active inactive'); 79 | } 80 | else { 81 | $(id).addClass('active').removeClass('inactive'); 82 | if (frame.attr('src') !== link) frame.attr('src', link); 83 | frame.slideDown(100); 84 | } 85 | } 86 | 87 | function linkSummaries() { 88 | $('.summary_signature').click(function() { 89 | document.location = $(this).find('a').attr('href'); 90 | }); 91 | } 92 | 93 | function summaryToggle() { 94 | $('.summary_toggle').click(function(e) { 95 | e.preventDefault(); 96 | localStorage.summaryCollapsed = $(this).text(); 97 | $('.summary_toggle').each(function() { 98 | $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); 99 | var next = $(this).parent().parent().nextAll('ul.summary').first(); 100 | if (next.hasClass('compact')) { 101 | next.toggle(); 102 | next.nextAll('ul.summary').first().toggle(); 103 | } 104 | else if (next.hasClass('summary')) { 105 | var list = $('
    '); 106 | list.html(next.html()); 107 | list.find('.summary_desc, .note').remove(); 108 | list.find('a').each(function() { 109 | $(this).html($(this).find('strong').html()); 110 | $(this).parent().html($(this)[0].outerHTML); 111 | }); 112 | next.before(list); 113 | next.toggle(); 114 | } 115 | }); 116 | return false; 117 | }); 118 | if (localStorage.summaryCollapsed == "collapse") { 119 | $('.summary_toggle').first().click(); 120 | } else { localStorage.summaryCollapsed = "expand"; } 121 | } 122 | 123 | function constantSummaryToggle() { 124 | $('.constants_summary_toggle').click(function(e) { 125 | e.preventDefault(); 126 | localStorage.summaryCollapsed = $(this).text(); 127 | $('.constants_summary_toggle').each(function() { 128 | $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); 129 | var next = $(this).parent().parent().nextAll('dl.constants').first(); 130 | if (next.hasClass('compact')) { 131 | next.toggle(); 132 | next.nextAll('dl.constants').first().toggle(); 133 | } 134 | else if (next.hasClass('constants')) { 135 | var list = $('
    '); 136 | list.html(next.html()); 137 | list.find('dt').each(function() { 138 | $(this).addClass('summary_signature'); 139 | $(this).text( $(this).text().split('=')[0]); 140 | if ($(this).has(".deprecated").length) { 141 | $(this).addClass('deprecated'); 142 | }; 143 | }); 144 | // Add the value of the constant as "Tooltip" to the summary object 145 | list.find('pre.code').each(function() { 146 | console.log($(this).parent()); 147 | var dt_element = $(this).parent().prev(); 148 | var tooltip = $(this).text(); 149 | if (dt_element.hasClass("deprecated")) { 150 | tooltip = 'Deprecated. ' + tooltip; 151 | }; 152 | dt_element.attr('title', tooltip); 153 | }); 154 | list.find('.docstring, .tags, dd').remove(); 155 | next.before(list); 156 | next.toggle(); 157 | } 158 | }); 159 | return false; 160 | }); 161 | if (localStorage.summaryCollapsed == "collapse") { 162 | $('.constants_summary_toggle').first().click(); 163 | } else { localStorage.summaryCollapsed = "expand"; } 164 | } 165 | 166 | function generateTOC() { 167 | if ($('#filecontents').length === 0) return; 168 | var _toc = $('
      '); 169 | var show = false; 170 | var toc = _toc; 171 | var counter = 0; 172 | var tags = ['h2', 'h3', 'h4', 'h5', 'h6']; 173 | var i; 174 | var curli; 175 | if ($('#filecontents h1').length > 1) tags.unshift('h1'); 176 | for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; } 177 | var lastTag = parseInt(tags[0][1], 10); 178 | $(tags.join(', ')).each(function() { 179 | if ($(this).parents('.method_details .docstring').length != 0) return; 180 | if (this.id == "filecontents") return; 181 | show = true; 182 | var thisTag = parseInt(this.tagName[1], 10); 183 | if (this.id.length === 0) { 184 | var proposedId = $(this).attr('toc-id'); 185 | if (typeof(proposedId) != "undefined") this.id = proposedId; 186 | else { 187 | var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_'); 188 | if ($('#' + proposedId).length > 0) { proposedId += counter; counter++; } 189 | this.id = proposedId; 190 | } 191 | } 192 | if (thisTag > lastTag) { 193 | for (i = 0; i < thisTag - lastTag; i++) { 194 | if ( typeof(curli) == "undefined" ) { 195 | curli = $('
    1. '); 196 | toc.append(curli); 197 | } 198 | toc = $('
        '); 199 | curli.append(toc); 200 | curli = undefined; 201 | } 202 | } 203 | if (thisTag < lastTag) { 204 | for (i = 0; i < lastTag - thisTag; i++) { 205 | toc = toc.parent(); 206 | toc = toc.parent(); 207 | } 208 | } 209 | var title = $(this).attr('toc-title'); 210 | if (typeof(title) == "undefined") title = $(this).text(); 211 | curli =$('
      1. ' + title + '
      2. '); 212 | toc.append(curli); 213 | lastTag = thisTag; 214 | }); 215 | if (!show) return; 216 | html = ''; 217 | $('#content').prepend(html); 218 | $('#toc').append(_toc); 219 | $('#toc .hide_toc').toggle(function() { 220 | $('#toc .top').slideUp('fast'); 221 | $('#toc').toggleClass('hidden'); 222 | $('#toc .title small').toggle(); 223 | }, function() { 224 | $('#toc .top').slideDown('fast'); 225 | $('#toc').toggleClass('hidden'); 226 | $('#toc .title small').toggle(); 227 | }); 228 | } 229 | 230 | function navResizeFn(e) { 231 | if (e.which !== 1) { 232 | navResizeFnStop(); 233 | return; 234 | } 235 | 236 | sessionStorage.navWidth = e.pageX.toString(); 237 | $('.nav_wrap').css('width', e.pageX); 238 | $('.nav_wrap').css('-ms-flex', 'inherit'); 239 | } 240 | 241 | function navResizeFnStop() { 242 | $(window).unbind('mousemove', navResizeFn); 243 | window.removeEventListener('message', navMessageFn, false); 244 | } 245 | 246 | function navMessageFn(e) { 247 | if (e.data.action === 'mousemove') navResizeFn(e.data.event); 248 | if (e.data.action === 'mouseup') navResizeFnStop(); 249 | } 250 | 251 | function navResizer() { 252 | $('#resizer').mousedown(function(e) { 253 | e.preventDefault(); 254 | $(window).mousemove(navResizeFn); 255 | window.addEventListener('message', navMessageFn, false); 256 | }); 257 | $(window).mouseup(navResizeFnStop); 258 | 259 | if (sessionStorage.navWidth) { 260 | navResizeFn({which: 1, pageX: parseInt(sessionStorage.navWidth, 10)}); 261 | } 262 | } 263 | 264 | function navExpander() { 265 | var done = false, timer = setTimeout(postMessage, 500); 266 | function postMessage() { 267 | if (done) return; 268 | clearTimeout(timer); 269 | var opts = { action: 'expand', path: pathId }; 270 | document.getElementById('nav').contentWindow.postMessage(opts, '*'); 271 | done = true; 272 | } 273 | 274 | window.addEventListener('message', function(event) { 275 | if (event.data === 'navReady') postMessage(); 276 | return false; 277 | }, false); 278 | } 279 | 280 | function mainFocus() { 281 | var hash = window.location.hash; 282 | if (hash !== '' && $(hash)[0]) { 283 | $(hash)[0].scrollIntoView(); 284 | } 285 | 286 | setTimeout(function() { $('#main').focus(); }, 10); 287 | } 288 | 289 | function navigationChange() { 290 | // This works around the broken anchor navigation with the YARD template. 291 | window.onpopstate = function() { 292 | var hash = window.location.hash; 293 | if (hash !== '' && $(hash)[0]) { 294 | $(hash)[0].scrollIntoView(); 295 | } 296 | }; 297 | } 298 | 299 | $(document).ready(function() { 300 | navResizer(); 301 | navExpander(); 302 | createSourceLinks(); 303 | createDefineLinks(); 304 | createFullTreeLinks(); 305 | searchFrameButtons(); 306 | linkSummaries(); 307 | summaryToggle(); 308 | constantSummaryToggle(); 309 | generateTOC(); 310 | mainFocus(); 311 | navigationChange(); 312 | }); 313 | 314 | })(); 315 | -------------------------------------------------------------------------------- /docs/yard/TLSmap/CLI.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: TLSmap::CLI 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
        36 | 61 | 62 |

        Class: TLSmap::CLI 63 | 64 | 65 | 66 |

        67 |
        68 | 69 |
        70 |
        Inherits:
        71 |
        72 | App 73 | 74 |
          75 |
        • Object
        • 76 | 77 | 78 | 79 | 80 | 81 |
        82 | show all 83 | 84 |
        85 |
        86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
        98 |
        Defined in:
        99 |
        lib/tls_map/cli.rb
        100 |
        101 | 102 |
        103 | 104 |

        Overview

        105 |
        106 |

        TLS mapping

        107 | 108 | 109 |
        110 |
        111 |
        112 | 113 | 114 |
        115 | 116 |

        117 | Constant Summary 118 | collapse 119 |

        120 | 121 |
        122 | 123 |
        INTEGRITY = 124 |
        125 |
        126 |

        sha2-256

        127 | 128 | 129 |
        130 |
        131 |
        132 | 133 | 134 |
        135 |
        136 |
        '42e44f89550365da2bc8d33d87f88b65d85d6474e90f9edb65e0ea6c78f61a53'
        137 | 138 |
        139 | 140 | 141 | 142 | 143 | 144 | 145 |

        Constants inherited 146 | from App

        147 |

        App::GNUTLS_URL, App::IANA_URL, App::NSS_URL, App::OPENSSL_URL, App::OPENSSL_URL2

        148 | 149 | 150 | 151 | 152 | 153 | 154 |

        155 | Instance Method Summary 156 | collapse 157 |

        158 | 159 |
          160 | 161 |
        • 162 | 163 | 164 | #initialize(force = false) ⇒ CLI 165 | 166 | 167 | 168 | 169 | 170 | 171 | constructor 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 |

          Load and parse data from marshalized hash (data/mapping.marshal).

          181 |
          182 | 183 |
        • 184 | 185 | 186 |
        • 187 | 188 | 189 | #update ⇒ Object 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 |
          204 | 205 |
        • 206 | 207 | 208 |
        209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 |

        Methods inherited from App

        221 |

        #bulk_search, #export, #search

        222 |
        223 |

        Constructor Details

        224 | 225 |
        226 |

        227 | 228 | #initialize(force = false) ⇒ CLI 229 | 230 | 231 | 232 | 233 | 234 |

        235 |
        236 |

        Load and parse data from marshalized hash (data/mapping.marshal). 237 | It must match the integrity check for security purpose.

        238 | 239 | 240 |
        241 |
        242 |
        243 |

        Parameters:

        244 |
          245 | 246 |
        • 247 | 248 | force 249 | 250 | 251 | (Boolean) 252 | 253 | 254 | (defaults to: false) 255 | 256 | 257 | — 258 |

          Force parsing even if intigrity check failed (DANGEROUS, 259 | may result in command execution vulnerability)

          260 |
          261 | 262 |
        • 263 | 264 |
        265 | 266 | 267 |
        268 | 269 | 282 | 294 | 295 |
        270 |
        271 | 
        272 | 
        273 | 16
        274 | 17
        275 | 18
        276 | 19
        277 | 20
        278 | 21
        279 | 22
        280 | 23
        281 |
        283 |
        # File 'lib/tls_map/cli.rb', line 16
        284 | 
        285 | def initialize(force = false) # rubocop:disable Lint/MissingSuper
        286 |   @storage_location = 'data/'
        287 |   @database_name = 'mapping.marshal'
        288 |   @database_path = absolute_db_path
        289 |   database_exists?
        290 |   @tls_map = []
        291 |   parse(force)
        292 | end
        293 |
        296 |
        297 | 298 |
        299 | 300 | 301 |
        302 |

        Instance Method Details

        303 | 304 | 305 |
        306 |

        307 | 308 | #updateObject 309 | 310 | 311 | 312 | 313 | 314 |

        315 | 316 | 325 | 333 | 334 |
        317 |
        318 | 
        319 | 
        320 | 50
        321 | 51
        322 | 52
        323 | 53
        324 |
        326 |
        # File 'lib/tls_map/cli.rb', line 50
        327 | 
        328 | def update
        329 |   tm = TLSmap::App.new
        330 |   tm.export(@database_path, :marshal)
        331 | end
        332 |
        335 |
        336 | 337 |
        338 | 339 |
        340 | 341 | 346 | 347 |
        348 | 349 | -------------------------------------------------------------------------------- /docs/yard/method_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Method List 19 | 20 | 21 | 22 |
        23 |
        24 |

        Method List

        25 |
        26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
        40 | 41 | 42 |
        43 | 44 |
          45 | 46 | 47 |
        • 48 |
          49 | #bulk_search 50 | TLSmap::App 51 |
          52 |
        • 53 | 54 | 55 |
        • 56 |
          57 | #ciphers 58 | TLSmap::App::Extractor 59 |
          60 |
        • 61 | 62 | 63 |
        • 64 |
          65 | #export 66 | TLSmap::App 67 |
          68 |
        • 69 | 70 | 71 |
        • 72 |
          73 | #extend 74 | TLSmap::App::Extended 75 |
          76 |
        • 77 | 78 | 79 |
        • 80 |
          81 | extract_cipher 82 | TLSmap::App::Extractor::Sslyze 83 |
          84 |
        • 85 | 86 | 87 |
        • 88 |
          89 | extract_cipher 90 | TLSmap::App::Extractor::Sslscan2 91 |
          92 |
        • 93 | 94 | 95 |
        • 96 |
          97 | extract_cipher 98 | TLSmap::App::Extractor::Testssl 99 |
          100 |
        • 101 | 102 | 103 |
        • 104 |
          105 | extract_cipher 106 | TLSmap::App::Extractor::SsllabsScan 107 |
          108 |
        • 109 | 110 | 111 |
        • 112 |
          113 | #find_vuln 114 | TLSmap::App::Extended 115 |
          116 |
        • 117 | 118 | 119 |
        • 120 |
          121 | finding2cipher 122 | TLSmap::App::Extractor::Testssl 123 |
          124 |
        • 125 | 126 | 127 |
        • 128 |
          129 | id2prot 130 | TLSmap::App::Extractor::Testssl 131 |
          132 |
        • 133 | 134 | 135 |
        • 136 |
          137 | id2prot 138 | TLSmap::App::Extractor::SsllabsScan 139 |
          140 |
        • 141 | 142 | 143 |
        • 144 |
          145 | #initialize 146 | TLSmap::App 147 |
          148 |
        • 149 | 150 | 151 |
        • 152 |
          153 | #initialize 154 | TLSmap::CLI 155 |
          156 |
        • 157 | 158 | 159 |
        • 160 |
          161 | #initialize 162 | TLSmap::App::Extractor 163 |
          164 |
        • 165 | 166 | 167 |
        • 168 |
          169 | #initialize 170 | TLSmap::App::Extended 171 |
          172 |
        • 173 | 174 | 175 |
        • 176 |
          177 | json_load_file 178 | TLSmap::Utils 179 |
          180 |
        • 181 | 182 | 183 |
        • 184 |
          185 | #parse 186 | TLSmap::App::Extractor 187 |
          188 |
        • 189 | 190 | 191 |
        • 192 |
          193 | parse 194 | TLSmap::App::Extractor::Sslyze 195 |
          196 |
        • 197 | 198 | 199 |
        • 200 |
          201 | parse 202 | TLSmap::App::Extractor::Sslscan2 203 |
          204 |
        • 205 | 206 | 207 |
        • 208 |
          209 | parse 210 | TLSmap::App::Extractor::Testssl 211 |
          212 |
        • 213 | 214 | 215 |
        • 216 |
          217 | parse 218 | TLSmap::App::Extractor::SsllabsScan 219 |
          220 |
        • 221 | 222 | 223 |
        • 224 |
          225 | #search 226 | TLSmap::App 227 |
          228 |
        • 229 | 230 | 231 |
        • 232 |
          233 | #ssl20 234 | TLSmap::App::Extractor 235 |
          236 |
        • 237 | 238 | 239 |
        • 240 |
          241 | #ssl30 242 | TLSmap::App::Extractor 243 |
          244 |
        • 245 | 246 | 247 |
        • 248 |
          249 | #tls10 250 | TLSmap::App::Extractor 251 |
          252 |
        • 253 | 254 | 255 |
        • 256 |
          257 | #tls11 258 | TLSmap::App::Extractor 259 |
          260 |
        • 261 | 262 | 263 |
        • 264 |
          265 | #tls12 266 | TLSmap::App::Extractor 267 |
          268 |
        • 269 | 270 | 271 |
        • 272 |
          273 | #tls13 274 | TLSmap::App::Extractor 275 |
          276 |
        • 277 | 278 | 279 |
        • 280 |
          281 | tmpfile 282 | TLSmap::Utils 283 |
          284 |
        • 285 | 286 | 287 |
        • 288 |
          289 | #translate_acronym 290 | TLSmap::App::Extended 291 |
          292 |
        • 293 | 294 | 295 |
        • 296 |
          297 | #update 298 | TLSmap::CLI 299 |
          300 |
        • 301 | 302 | 303 | 304 |
        305 |
        306 | 307 | 308 | -------------------------------------------------------------------------------- /lib/tls_map/extractor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'json' 5 | # Project internal 6 | require 'tls_map/cli' 7 | # External 8 | require 'rexml/document' 9 | 10 | module TLSmap 11 | class App 12 | # External tools output data extractor 13 | # 14 | # Output files from [SSLyze][1] (JSON), [sslscan2][2] (XML), [testssl.sh][3] (JSON), [ssllabs-scan][4] (JSON) 15 | # 16 | # [1]:https://github.com/nabla-c0d3/sslyze 17 | # [2]:https://github.com/rbsec/sslscan 18 | # [3]:https://github.com/drwetter/testssl.sh 19 | # [4]:https://github.com/ssllabs/ssllabs-scan 20 | # 21 | # Example of commands: 22 | # 23 | # - `sslyze --json_out=example.org.json example.org` 24 | # - `sslscan2 --show-cipher-ids --xml=example.org.xml example.org` 25 | # - `--show-cipher-ids` is mandatory else ciphers are not saved to the output 26 | # - `testssl --jsonfile-pretty example.org.json --mapping no-openssl --cipher-per-proto example.org` 27 | # - json-pretty is the only supported format, default json or csv, html won't work 28 | # - `ssllabs-scan --quiet example.org > example.org.json` 29 | # - The default output is the only supported format, using `-json-flat` won't work 30 | class Extractor 31 | # Get the list of ciphers extracted from the tool output file 32 | # @return [Array] Cipher array (IANA names) 33 | attr_reader :ciphers 34 | 35 | # Initialize {TLSmap::App::Extractor} instance 36 | def initialize 37 | @ciphers = [] 38 | end 39 | 40 | # Return only the SSL 2.0 ciphers 41 | # @return [Array] Cipher array (IANA names) 42 | def ssl20 43 | @ciphers['SSL2.0'] 44 | end 45 | 46 | # Return only the SSL 3.0 ciphers 47 | # @return [Array] Cipher array (IANA names) 48 | def ssl30 49 | @ciphers['SSL3.0'] 50 | end 51 | 52 | # Return only the TLS 1.0 ciphers 53 | # @return [Array] Cipher array (IANA names) 54 | def tls10 55 | @ciphers['TLS1.0'] 56 | end 57 | 58 | # Return only the TLS 1.1 ciphers 59 | # @return [Array] Cipher array (IANA names) 60 | def tls11 61 | @ciphers['TLS1.1'] 62 | end 63 | 64 | # Return only the TLS 1.2 ciphers 65 | # @return [Array] Cipher array (IANA names) 66 | def tls12 67 | @ciphers['TLS1.2'] 68 | end 69 | 70 | # Return only the TLS 1.3 ciphers 71 | # @return [Array] Cipher array (IANA names) 72 | def tls13 73 | @ciphers['TLS1.3'] 74 | end 75 | 76 | # Extract the ciphers from the tool output file 77 | # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan` 78 | # @param file [String] Path of the tool output file, beware of the format expected. See {TLSmap::App::Extractor} 79 | # @return [Array] Cipher array (IANA names) 80 | def parse(tool, file) 81 | # Convert string to class 82 | @ciphers = Object.const_get("TLSmap::App::Extractor::#{normalize(tool)}").parse(file) 83 | rescue StandardError 84 | warn helper(tool) 85 | end 86 | 87 | # Commands for {helper} 88 | CMD = { 89 | 'sslyze' => 'sslyze --json_out=example.org.json example.org', 90 | 'sslscan2' => 'sslscan2 --show-cipher-ids --xml=example.org.xml example.org', 91 | 'testssl' => 'testssl --jsonfile-pretty example.org.json --mapping no-openssl --cipher-per-proto example.org', 92 | 'ssllabs-scan' => 'ssllabs-scan --quiet example.org > example.org.json' 93 | }.freeze 94 | 95 | # Get the external tool command used to generate the expected result format 96 | # @param tool [String] Possible values: `sslyze`, `sslscan2`, `testssl`, `ssllabs-scan` 97 | # @return [String] external tool command used to generate the expected result format used in input of the extract 98 | # command (CLI) / {parse} method (library) 99 | def helper(tool) 100 | intro = 'You may not be provinding the right format.' 101 | outro = 'See https://sec-it.github.io/tls-map/yard/TLSmap/App/Extractor' 102 | "#{intro}\nUse this command: #{CMD[tool]}\n#{outro}" 103 | end 104 | 105 | # Convert cmdline tool name to Class name 106 | def normalize(tool) 107 | tool.split('-').map(&:capitalize).join 108 | end 109 | 110 | protected :normalize, :helper 111 | private_constant :CMD 112 | 113 | # Parsing SSLyze 114 | class Sslyze 115 | class << self 116 | # Extract the ciphers from the sslyze output file 117 | # @param file [String] Path of the sslyze output file, beware of the format expected. 118 | # See {TLSmap::App::Extractor} 119 | # @return [Array] Cipher array (IANA names) 120 | def parse(file) 121 | data = Utils.json_load_file(file) 122 | extract_cipher(data) 123 | end 124 | 125 | # Extract the ciphers from the sslyze output file 126 | # @param json_data [Hash] Ruby hash of the parsed JSON 127 | # @return [Array] Cipher array (IANA names) 128 | def extract_cipher(json_data) 129 | ciphers = json_data['server_scan_results'][0]['scan_commands_results'] 130 | raw = { 131 | 'SSL2.0' => ciphers['ssl_2_0_cipher_suites']['accepted_cipher_suites'], 132 | 'SSL3.0' => ciphers['ssl_3_0_cipher_suites']['accepted_cipher_suites'], 133 | 'TLS1.0' => ciphers['tls_1_0_cipher_suites']['accepted_cipher_suites'], 134 | 'TLS1.1' => ciphers['tls_1_1_cipher_suites']['accepted_cipher_suites'], 135 | 'TLS1.2' => ciphers['tls_1_2_cipher_suites']['accepted_cipher_suites'], 136 | 'TLS1.3' => ciphers['tls_1_3_cipher_suites']['accepted_cipher_suites'] 137 | } 138 | raw.transform_values { |v| v.empty? ? v : v.map { |x| x['cipher_suite']['name'] } } 139 | end 140 | 141 | protected :extract_cipher 142 | end 143 | end 144 | 145 | # Parsing sslscan2 146 | class Sslscan2 147 | class << self 148 | # Extract the ciphers from the sslscan2 output file 149 | # @param file [String] Path of the sslscan2 output file, beware of the format expected. 150 | # See {TLSmap::App::Extractor} 151 | # @return [Array] Cipher array (IANA names) 152 | def parse(file, online = false) 153 | doc = REXML::Document.new(File.new(file)) 154 | extract_cipher(doc, online) 155 | end 156 | 157 | # Extract the ciphers from the sslscan2 output file 158 | # @param xml_doc [REXML::Document] XML document as returned by `REXML::Document` 159 | # @param online By default use the offline mode with {TLSmap::CLI} for better performance. 160 | # Online mode will use {TLSmap::App} and fetch upstream resources to get latest updates but is a lot slower. 161 | # @return [Array] Cipher array (IANA names) 162 | def extract_cipher(xml_doc, online = false) # rubocop:disable Metrics/MethodLength 163 | raw = { 164 | 'SSL2.0' => [], 'SSL3.0' => [], 165 | 'TLS1.0' => [], 'TLS1.1' => [], 'TLS1.2' => [], 'TLS1.3' => [] 166 | } 167 | tm = online ? TLSmap::App.new : TLSmap::CLI.new 168 | xml_doc.root.each_element('//cipher') do |node| 169 | sslv = node.attributes['sslversion'].gsub('v', '') 170 | cipher = tm.search(:codepoint, node.attributes['id'][2..], :iana)[:iana] 171 | raw[sslv].push(cipher) 172 | end 173 | raw 174 | end 175 | 176 | protected :extract_cipher 177 | end 178 | end 179 | 180 | # Parsing testssl.sh 181 | class Testssl 182 | class << self 183 | # Extract the ciphers from the testssl output file 184 | # @param file [String] Path of the testssl output file, beware of the format expected. 185 | # See {TLSmap::App::Extractor} 186 | # @return [Array] Cipher array (IANA names) 187 | def parse(file) 188 | data = Utils.json_load_file(file) 189 | extract_cipher(data) 190 | end 191 | 192 | # Extract the ciphers from the testssl output file 193 | # @param json_data [Hash] Ruby hash of the parsed JSON 194 | # @return [Array] Cipher array (IANA names) 195 | def extract_cipher(json_data) 196 | cipher = json_data['scanResult'][0]['cipherTests'] 197 | raw = { 198 | 'SSL2.0' => [], 'SSL3.0' => [], 199 | 'TLS1.0' => [], 'TLS1.1' => [], 'TLS1.2' => [], 'TLS1.3' => [] 200 | } 201 | cipher.each do |node| 202 | raw[id2prot(node['id'])].push(finding2cipher(node['finding'])) 203 | end 204 | raw 205 | end 206 | 207 | # Convert testssl protocol id to protocol name in TLSmap format 208 | # @param id [String] testssl protocol id 209 | # @return [String] protocol name in TLSmap format 210 | def id2prot(id) 211 | prot = { 212 | 'ssl2' => 'SSL2.0', 'ssl3' => 'SSL3.0', 'tls1' => 'TLS1.0', 213 | 'tls1_1' => 'TLS1.1', 'tls1_2' => 'TLS1.2', 'tls1_3' => 'TLS1.3' 214 | } 215 | protv = id.match(/cipher-(\w+)_x\w+/).captures[0] 216 | prot[protv] 217 | end 218 | 219 | # Extract the cipher name from testssl finding 220 | # @param finding [String] testssl finding 221 | # @return [String] cipher name (IANA names) 222 | def finding2cipher(finding) 223 | /\s(\w+_\w+)\s/.match(finding).captures[0] 224 | end 225 | 226 | protected :extract_cipher, :id2prot, :finding2cipher 227 | end 228 | end 229 | 230 | # Parsing ssllabs-scan 231 | class SsllabsScan 232 | class << self 233 | # Extract the ciphers from the ssllabs-scan output file 234 | # @param file [String] Path of the ssllabs-scan output file, beware of the format expected. 235 | # See {TLSmap::App::Extractor} 236 | # @return [Array] Cipher array (IANA names) 237 | def parse(file) 238 | data = Utils.json_load_file(file) 239 | extract_cipher(data) 240 | end 241 | 242 | # Extract the ciphers from the ssllabs-scan output file 243 | # @param json_data [Hash] Ruby hash of the parsed JSON 244 | # @return [Array] Cipher array (IANA names) 245 | def extract_cipher(json_data) # rubocop:disable Metrics/MethodLength 246 | raw = { 247 | 'SSL2.0' => [], 'SSL3.0' => [], 248 | 'TLS1.0' => [], 'TLS1.1' => [], 'TLS1.2' => [], 'TLS1.3' => [] 249 | } 250 | json_data[0]['endpoints'].each do |endpoint| 251 | endpoint['details']['suites'].each do |suite| 252 | suite['list'].each do |cipher| 253 | raw[id2prot(suite['protocol'])].push(cipher['name']) 254 | end 255 | end 256 | end 257 | raw.transform_values(&:uniq) 258 | end 259 | 260 | # Convert ssllabs-scan protocol id to protocol name in TLSmap format 261 | # @param id [String] ssllabs-scan protocol id 262 | # @return [String] protocol name in TLSmap format 263 | def id2prot(id) 264 | prot = { 265 | 512 => 'SSL2.0', 768 => 'SSL3.0', 769 => 'TLS1.0', 266 | 770 => 'TLS1.1', 771 => 'TLS1.2', 772 => 'TLS1.3' 267 | } 268 | prot[id] 269 | end 270 | 271 | protected :extract_cipher, :id2prot 272 | end 273 | end 274 | end 275 | end 276 | end 277 | -------------------------------------------------------------------------------- /docs/vendor/themes/dark.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready)>nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:1.2rem;vertical-align:middle}.progress{background-color:var(--theme-color,#ea6f5a);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search .search-keyword,.search a:hover{color:var(--theme-color,#ea6f5a)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#c8c8c8;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:var(--theme-color,#ea6f5a)}.app-nav a.active{border-bottom:2px solid var(--theme-color,#ea6f5a)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave .56s ease-in-out;animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#3f3f3f;fill:var(--theme-color,#ea6f5a);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#c8c8c8}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:rgba(63,63,63,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:var(--theme-color,#ea6f5a);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#3f3f3f;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#c8c8c8}.markdown-section p.warn{background:rgba(234,111,90,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:rgba(63,63,63,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{-webkit-animation:none;animation:none}.github-corner .octo-arm{-webkit-animation:octocat-wave .56s ease-in-out;animation:octocat-wave .56s ease-in-out}}@-webkit-keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;width:100vw;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#3f3f3f;opacity:.8;position:absolute;top:0;height:100%;width:100%}section.cover .cover-main{flex:1;margin:-20px 16px 0;text-align:center;position:relative}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid var(--theme-color,#ea6f5a);box-sizing:border-box;color:var(--theme-color,#ea6f5a);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:var(--theme-color,#ea6f5a);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid var(--theme-color,#ea6f5a);transition:color .3s}section.cover blockquote>p>a:hover{color:var(--theme-color,#ea6f5a)}.sidebar,body{background-color:#3f3f3f}.sidebar{color:#c8c8c8}.sidebar li{margin:6px 15px 6px 0}.sidebar ul li a{color:#c8c8c8;font-size:14px;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{color:var(--theme-color,#ea6f5a);font-weight:600}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#657b83;font-weight:600}.markdown-section a{color:var(--theme-color,#ea6f5a);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section ol,.markdown-section p,.markdown-section ul{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid var(--theme-color,#ea6f5a);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code{background-color:#282828;border-radius:2px;color:#657b83;font-family:Roboto Mono,Monaco,courier,monospace;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#282828;font-family:Roboto Mono,Monaco,courier,monospace;line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 1.4rem;position:relative;word-wrap:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:var(--theme-color,#ea6f5a)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:var(--theme-color,#ea6f5a)}.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#282828;border-radius:2px;color:#657b83;display:block;font-family:Roboto Mono,Monaco,courier,monospace;font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:2.2em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.05rem}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto}pre:after{color:#ccc;content:attr(data-lang);font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}.markdown-section p.tip{background-color:#282828;color:#657b83}input[type=search]{background:#4f4f4f;border-color:#4f4f4f;color:#c8c8c8} -------------------------------------------------------------------------------- /docs/pages/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## CLI 4 | 5 | ### Search 6 | 7 | Search for the IANA value of `RSA_ARCFOUR_128_SHA1` (GnuTLS): 8 | 9 | ``` 10 | $ tls-map search gnutls RSA_ARCFOUR_128_SHA1 -o iana 11 | iana: TLS_RSA_WITH_RC4_128_SHA 12 | ``` 13 | 14 | Search for the IANA value of `AES128-SHA` (OpenSSL): 15 | 16 | ``` 17 | $ tls-map search openssl AES128-SHA -o iana 18 | iana: TLS_RSA_WITH_AES_128_CBC_SHA 19 | ``` 20 | 21 | Search for the hexadecimal codepoint of `TLS_DH_RSA_WITH_AES_256_CBC_SHA-SHA` (IANA): 22 | 23 | ``` 24 | $ tls-map search iana TLS_DH_RSA_WITH_AES_256_CBC_SHA -o codepoint 25 | codepoint: 0037 26 | ``` 27 | 28 | Get all values corresponding to codepoint `1303`: 29 | 30 | ``` 31 | $ tls-map search codepoint 1303 32 | codepoint: 1303 33 | iana: TLS_CHACHA20_POLY1305_SHA256 34 | openssl: TLS_CHACHA20_POLY1305_SHA256 35 | gnutls: CHACHA20_POLY1305_SHA256 36 | nss: TLS_CHACHA20_POLY1305_SHA256 37 | ``` 38 | 39 | Get all values corresponding to NSS cipher algorithm `TLS_AES_256_GCM_SHA384`: 40 | 41 | ``` 42 | $ tls-map search nss TLS_AES_256_GCM_SHA384 43 | codepoint: 1302 44 | iana: TLS_AES_256_GCM_SHA384 45 | openssl: TLS_AES_256_GCM_SHA384 46 | gnutls: AES_256_GCM_SHA384 47 | nss: TLS_AES_256_GCM_SHA384 48 | ``` 49 | 50 | Display extended information (online): 51 | 52 | ``` 53 | $ tls-map search -e codepoint 0013 54 | codepoint: 0013 55 | iana: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 56 | openssl: DHE-DSS-DES-CBC3-SHA 57 | gnutls: DHE_DSS_3DES_EDE_CBC_SHA1 58 | nss: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 59 | Protocol: TLS 60 | Key Exchange: DHE 61 | Authentication: DSS 62 | Encryption: 3DES EDE CBC 63 | Hash: SHA 64 | Security: weak 65 | TLS Version(s): TLS1.0, TLS1.1 66 | Vulnerabilities: 67 | - Medium - While Triple-DES is still recognized as a secure symmetric-key encryption, a more and more standardizations bodies and projects decide to deprecate this algorithm. Though not broken, it has been proven to suffer from several vulnerabilities in the past (see [sweet32.info](https://sweet32.info)). 68 | - Medium - 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. 69 | - Medium - The Secure Hash Algorithm 1 has been proven to be insecure as of 2017 (see [shattered.io](https://shattered.io)). 70 | More info: https://ciphersuite.info/cs/TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA/ 71 | ``` 72 | 73 | Display extended information (online) with full acronym name: 74 | 75 | ``` 76 | $ tls-map search -e codepoint 0013 -a 77 | codepoint: 0013 78 | iana: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 79 | openssl: DHE-DSS-DES-CBC3-SHA 80 | gnutls: DHE_DSS_3DES_EDE_CBC_SHA1 81 | nss: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 82 | Protocol: TLS (Transport Layer Security) 83 | Key Exchange: DHE (Diffie-Hellman Ephemeral) 84 | Authentication: DSS (Digital Signature Standard) 85 | Encryption: 3DES EDE CBC (Triple-DES (Encrypt Decrypt Encrypt) in Cipher Block Chaining mode) 86 | Hash: SHA (Secure Hash Algorithm 1) 87 | Security: weak 88 | TLS Version(s): TLS1.0, TLS1.1 89 | Vulnerabilities: 90 | - Medium - While Triple-DES is still recognized as a secure symmetric-key encryption, a more and more standardizations bodies and projects decide to deprecate this algorithm. Though not broken, it has been proven to suffer from several vulnerabilities in the past (see [sweet32.info](https://sweet32.info)). 91 | - Medium - 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. 92 | - Medium - The Secure Hash Algorithm 1 has been proven to be insecure as of 2017 (see [shattered.io](https://shattered.io)). 93 | More info: https://ciphersuite.info/cs/TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA/ 94 | ``` 95 | 96 | ### Export 97 | 98 | Export to minified JSON: 99 | 100 | ``` 101 | $ tls-map export /tmp/map.min.json json_compact 102 | /tmp/map.min.json exported 103 | ``` 104 | 105 | See [Usage](/pages/usage#CLI) for other formats. 106 | 107 | ### Extract 108 | 109 | Extract ciphers from external tools output file. 110 | SSLyze, sslscan2, testssl.sh, ssllabs-scan are supported, see the [library documentation](https://sec-it.github.io/tls-map/yard/TLSmap/App/Extractor) for expected file format. 111 | 112 | ``` 113 | $ tls-map extract newwebsite.json ssllabs-scan 114 | TLS1.2 115 | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 116 | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 117 | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 118 | TLS1.3 119 | TLS_AES_256_GCM_SHA384 120 | TLS_CHACHA20_POLY1305_SHA256 121 | TLS_AES_128_GCM_SHA256 122 | 123 | $ tls-map extract oldwebsite.json ssllabs-scan 124 | SSL2.0 125 | SSL_CK_RC4_128_WITH_MD5 126 | SSL_CK_DES_192_EDE3_CBC_WITH_MD5 127 | SSL3.0 128 | TLS_RSA_WITH_3DES_EDE_CBC_SHA 129 | TLS_RSA_WITH_RC4_128_SHA 130 | TLS_RSA_WITH_RC4_128_MD5 131 | TLS1.0 132 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 133 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 134 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA 135 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA 136 | TLS_RSA_WITH_AES_256_CBC_SHA 137 | TLS_RSA_WITH_AES_128_CBC_SHA 138 | TLS_RSA_WITH_3DES_EDE_CBC_SHA 139 | TLS_RSA_WITH_RC4_128_SHA 140 | TLS_RSA_WITH_RC4_128_MD5 141 | ``` 142 | 143 | ### Update 144 | 145 | The CLI is working with an offline database (Marshaled Ruby hash) to avoid 146 | fetching and parsing all source file at each execution. 147 | If you want up to date values but do not want to wait for an official new 148 | release of TLS map you can use the update command. 149 | Doing so you will override `data/mapping.marshal` but for security purpose 150 | and integrity check is done so if the file is modified the tool will refuse to 151 | word so you have to use the `--force` option every time to bypass the security 152 | check. So it is recommended to not use the update command and wait for official 153 | release. 154 | 155 | ### Bulk search 156 | 157 | Search and translate cipher names between SSL/TLS libraries **in bulk** 158 | 159 | `test/file_sample/bulk_IANA.txt` 160 | 161 | ``` 162 | TLS_DH_RSA_WITH_AES_256_CBC_SHA 163 | TLS_RSA_WITH_RC4_128_SHA 164 | TLS_RSA_WITH_AES_128_CBC_SHA 165 | TLS_INVALID 166 | TLS_CHACHA20_POLY1305_SHA256 167 | TLS_AES_256_GCM_SHA384 168 | ``` 169 | 170 | ``` 171 | $ tls-map bulk iana test/file_sample/bulk_IANA.txt -q openssl 172 | DH-RSA-AES256-SHA 173 | RC4-SHA 174 | AES128-SHA 175 | 176 | TLS_CHACHA20_POLY1305_SHA256 177 | TLS_AES_256_GCM_SHA384 178 | ``` 179 | 180 | ## Library 181 | 182 | Basic usage, searching for cipher name equivalent in other libraries. 183 | 184 | ```ruby 185 | require 'tls_map' 186 | 187 | tm = TLSmap::App.new 188 | 189 | # Translate from one lib to another 190 | tm.search(:gnutls, 'RSA_ARCFOUR_128_SHA1', :iana) #=> {:iana=>"TLS_RSA_WITH_RC4_128_SHA"} 191 | tm.search(:openssl, 'AES128-SHA', :iana) #=> {:iana=>"TLS_RSA_WITH_AES_128_CBC_SHA"} 192 | tm.search(:iana, 'TLS_DH_RSA_WITH_AES_256_CBC_SHA', :codepoint) #=> {:codepoint=>"0037"} 193 | 194 | # Get all 195 | tm.search(:codepoint, '1303') #=> {:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"} 196 | tm.search(:nss, 'TLS_AES_256_GCM_SHA384') #=> {: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"} 197 | ``` 198 | 199 | Usage of the `Extended` class to get advanced information about a cipher 200 | (online feature). 201 | 202 | ```ruby 203 | require 'tls_map' 204 | 205 | # tm = TLSmap::CLI.new # (Offline) 206 | tm = TLSmap::App.new # (Online) 207 | 208 | # Translate from one lib to another 209 | cipher = tm.search(:gnutls, 'RSA_ARCFOUR_128_SHA1', :iana) 210 | # => {:iana=>"TLS_RSA_WITH_RC4_128_SHA"} 211 | 212 | tmext = TLSmap::App::Extended.new 213 | 214 | # Fetch extended info (online 215 | tmext.extend(cipher[:iana]) 216 | # => 217 | # {"protocol_version"=>"TLS", 218 | # "kex_algorithm"=>"RSA", 219 | # "auth_algorithm"=>"RSA", 220 | # "enc_algorithm"=>"RC4 128", 221 | # "hash_algorithm"=>"SHA", 222 | # "security"=>"insecure", 223 | # "tls_version"=>["TLS1.0", "TLS1.1", "TLS1.2"], 224 | # "vulns"=> 225 | # [{:severity=>1, 226 | # :description=> 227 | # "This key exchange algorithm does not support Perfect Forward Secrecy (PFS) which is recommended, so attackers cannot decrypt # the complete communication stream."}, 228 | # {:severity=>2, 229 | # :description=> 230 | # "IETF has officially prohibited RC4 for use in TLS in RFC 7465. Therefore, it can be considered insecure."}, 231 | # {:severity=>1, 232 | # :description=> 233 | # "The Secure Hash Algorithm 1 has been proven to be insecure as of 2017 (see [shattered.io](https://shattered.io))."}], 234 | # "url"=>"https://ciphersuite.info/cs/TLS_RSA_WITH_RC4_128_SHA/"}) 235 | 236 | # Resolve acronyms 237 | tmext.translate_acronym('RSA') 238 | # => "Rivest Shamir Adleman algorithm" 239 | 240 | # Find vulnerabilities related to a technologiy 241 | tmext.find_vuln('MD5') 242 | # => 243 | # [{:severity=>2, 244 | # :description=> 245 | # "The Message Digest 5 algorithm suffers form multiple vulnerabilities and is considered insecure."}] 246 | 247 | tmext.find_vuln('DES CBC') 248 | # => 249 | # [{:severity=>2, 250 | # :description=> 251 | # "DES is considered weak, primarily due to its short key-lengths of 40 or 65-Bit. Furthermore, it has been withdrawn as a # standard by the National Institute of Standards and Technology in 2005."}, 252 | # {:severity=>1, 253 | # :description=> 254 | # "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."}] 255 | ``` 256 | 257 | Extract ciphers from external tools output file. 258 | SSLyze, sslscan2, testssl.sh, ssllabs-scan are supported, see the [library documentation](https://sec-it.github.io/tls-map/yard/TLSmap/App/Extractor). 259 | 260 | ```ruby 261 | require 'tls_map' 262 | 263 | extractor = TLSmap::App::Extractor.new 264 | 265 | # Parse the file 266 | extractor.parse('ssllabs-scan', 'oldwebsite.json') 267 | 268 | # Access to all extracted ciphers 269 | extractor.ciphers 270 | => 271 | # {"SSL2.0"=>["SSL_CK_RC4_128_WITH_MD5", "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"], 272 | # "SSL3.0"=>["TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_RC4_128_MD5"], 273 | # "TLS1.0"=> 274 | # ["TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 275 | # "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 276 | # "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 277 | # "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 278 | # "TLS_RSA_WITH_AES_256_CBC_SHA", 279 | # "TLS_RSA_WITH_AES_128_CBC_SHA", 280 | # "TLS_RSA_WITH_3DES_EDE_CBC_SHA", 281 | # "TLS_RSA_WITH_RC4_128_SHA", 282 | # "TLS_RSA_WITH_RC4_128_MD5"], 283 | # "TLS1.1"=>[], 284 | # "TLS1.2"=>[], 285 | # "TLS1.3"=>[]} 286 | 287 | # Access only SSL 2.0 ciphers 288 | extractor.ssl20 289 | # => ["SSL_CK_RC4_128_WITH_MD5", "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"] 290 | ``` 291 | 292 | Search and translate cipher names between SSL/TLS libraries **in bulk**: 293 | 294 | ```ruby 295 | require 'tls_map' 296 | 297 | tm = TLSmap::App.new 298 | 299 | tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt', :openssl) 300 | # => [{:openssl=>"DH-RSA-AES256-SHA"}, {:openssl=>"RC4-SHA"}, {:openssl=>"AES128-SHA"}, {}, {:openssl=>"TLS_CHACHA20_POLY1305_SHA256"}, {:openssl=>"TLS_AES_256_GCM_SHA384"}] 301 | 302 | tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt', :codepoint) 303 | # => [{:codepoint=>"0037"}, {:codepoint=>"0005"}, {:codepoint=>"002F"}, {}, {:codepoint=>"1303"}, {:codepoint=>"1302"}] 304 | 305 | tm.bulk_search(:iana, 'test/file_sample/bulk_IANA.txt') 306 | # => 307 | # [{:codepoint=>"0037", :iana=>"TLS_DH_RSA_WITH_AES_256_CBC_SHA", :openssl=>"DH-RSA-AES256-SHA", :gnutls=>nil, # :nss=>"TLS_DH_RSA_WITH_AES_256_CBC_SHA"}, 308 | # {:codepoint=>"0005", :iana=>"TLS_RSA_WITH_RC4_128_SHA", :openssl=>"RC4-SHA", :gnutls=>"RSA_ARCFOUR_128_SHA1", # :nss=>"TLS_RSA_WITH_RC4_128_SHA"}, 309 | # {:codepoint=>"002F", :iana=>"TLS_RSA_WITH_AES_128_CBC_SHA", :openssl=>"AES128-SHA", :gnutls=>"RSA_AES_128_CBC_SHA1", # :nss=>"TLS_RSA_WITH_AES_128_CBC_SHA"}, 310 | # {}, 311 | # {:codepoint=>"1303", :iana=>"TLS_CHACHA20_POLY1305_SHA256", :openssl=>"TLS_CHACHA20_POLY1305_SHA256", # :gnutls=>"CHACHA20_POLY1305_SHA256", :nss=>"TLS_CHACHA20_POLY1305_SHA256"}, 312 | # {: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"}] 313 | ``` 314 | -------------------------------------------------------------------------------- /docs/yard/TLSmap/App/Extractor/Sslyze.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: TLSmap::App::Extractor::Sslyze 8 | 9 | — Documentation by YARD 0.9.26 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
        36 | 61 | 62 |

        Class: TLSmap::App::Extractor::Sslyze 63 | 64 | 65 | 66 |

        67 |
        68 | 69 |
        70 |
        Inherits:
        71 |
        72 | Object 73 | 74 |
          75 |
        • Object
        • 76 | 77 | 78 | 79 |
        80 | show all 81 | 82 |
        83 |
        84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
        96 |
        Defined in:
        97 |
        lib/tls_map/extractor.rb
        98 |
        99 | 100 |
        101 | 102 |

        Overview

        103 |
        104 |

        Parsing SSLyze

        105 | 106 | 107 |
        108 |
        109 |
        110 | 111 | 112 |
        113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |

        121 | Class Method Summary 122 | collapse 123 |

        124 | 125 |
          126 | 127 |
        • 128 | 129 | 130 | .extract_cipher(json_data) ⇒ Array<String> 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 |

          Extract the ciphers from the sslyze output file.

          145 |
          146 | 147 |
        • 148 | 149 | 150 |
        • 151 | 152 | 153 | .parse(file) ⇒ Array<String> 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 |

          Extract the ciphers from the sslyze output file.

          168 |
          169 | 170 |
        • 171 | 172 | 173 |
        174 | 175 | 176 | 177 | 178 |
        179 |

        Class Method Details

        180 | 181 | 182 |
        183 |

        184 | 185 | .extract_cipher(json_data) ⇒ Array<String> 186 | 187 | 188 | 189 | 190 | 191 |

        192 |
        193 |

        Extract the ciphers from the sslyze output file

        194 | 195 | 196 |
        197 |
        198 |
        199 |

        Parameters:

        200 |
          201 | 202 |
        • 203 | 204 | json_data 205 | 206 | 207 | (Hash) 208 | 209 | 210 | 211 | — 212 |

          Ruby hash of the parsed JSON

          213 |
          214 | 215 |
        • 216 | 217 |
        218 | 219 |

        Returns:

        220 |
          221 | 222 |
        • 223 | 224 | 225 | (Array<String>) 226 | 227 | 228 | 229 | — 230 |

          Cipher array (IANA names)

          231 |
          232 | 233 |
        • 234 | 235 |
        236 | 237 |
        238 | 239 | 256 | 272 | 273 |
        240 |
        241 | 
        242 | 
        243 | 128
        244 | 129
        245 | 130
        246 | 131
        247 | 132
        248 | 133
        249 | 134
        250 | 135
        251 | 136
        252 | 137
        253 | 138
        254 | 139
        255 |
        257 |
        # File 'lib/tls_map/extractor.rb', line 128
        258 | 
        259 | def extract_cipher(json_data)
        260 |   ciphers = json_data['server_scan_results'][0]['scan_commands_results']
        261 |   raw = {
        262 |     'SSL2.0' => ciphers['ssl_2_0_cipher_suites']['accepted_cipher_suites'],
        263 |     'SSL3.0' => ciphers['ssl_3_0_cipher_suites']['accepted_cipher_suites'],
        264 |     'TLS1.0' => ciphers['tls_1_0_cipher_suites']['accepted_cipher_suites'],
        265 |     'TLS1.1' => ciphers['tls_1_1_cipher_suites']['accepted_cipher_suites'],
        266 |     'TLS1.2' => ciphers['tls_1_2_cipher_suites']['accepted_cipher_suites'],
        267 |     'TLS1.3' => ciphers['tls_1_3_cipher_suites']['accepted_cipher_suites']
        268 |   }
        269 |   raw.transform_values { |v| v.empty? ? v : v.map { |x| x['cipher_suite']['name'] } }
        270 | end
        271 |
        274 |
        275 | 276 |
        277 |

        278 | 279 | .parse(file) ⇒ Array<String> 280 | 281 | 282 | 283 | 284 | 285 |

        286 |
        287 |

        Extract the ciphers from the sslyze output file

        288 | 289 | 290 |
        291 |
        292 |
        293 |

        Parameters:

        294 |
          295 | 296 |
        • 297 | 298 | file 299 | 300 | 301 | (String) 302 | 303 | 304 | 305 | — 306 |

          Path of the sslyze output file, beware of the format expected. 307 | See TLSmap::App::Extractor

          308 |
          309 | 310 |
        • 311 | 312 |
        313 | 314 |

        Returns:

        315 |
          316 | 317 |
        • 318 | 319 | 320 | (Array<String>) 321 | 322 | 323 | 324 | — 325 |

          Cipher array (IANA names)

          326 |
          327 | 328 |
        • 329 | 330 |
        331 | 332 |
        333 | 334 | 343 | 351 | 352 |
        335 |
        336 | 
        337 | 
        338 | 120
        339 | 121
        340 | 122
        341 | 123
        342 |
        344 |
        # File 'lib/tls_map/extractor.rb', line 120
        345 | 
        346 | def parse(file)
        347 |   data = Utils.json_load_file(file)
        348 |   extract_cipher(data)
        349 | end
        350 |
        353 |
        354 | 355 |
        356 | 357 |
        358 | 359 | 364 | 365 |
        366 | 367 | --------------------------------------------------------------------------------