class TLSmap::App
TLS mapping
TLS mapping
TLS mapping
TLS mapping
TLS mapping
TLS mapping
TLS mapping
Constants
- GNUTLS_URL
- IANA_URL
- NSS_URL
Timeout hg.mozilla.org/projects/nss/raw-file/tip/lib/ssl/sslproto.h so use github RO mirror instead.
- OPENSSL_URL
- OPENSSL_URL2
Attributes
Get the mapping of all TLS cipher suites @return [Hash] mapping of all TLS cipher suites
Public Class Methods
Will automatically fetch source files and parse them.
# File lib/tls_map.rb, line 26 def initialize @iana_file = Utils.tmpfile('iana', IANA_URL) @openssl_file = Utils.tmpfile('openssl', OPENSSL_URL) @openssl_file2 = Utils.tmpfile('openssl', OPENSSL_URL2) @gnutls_file = Utils.tmpfile('gnutls', GNUTLS_URL) @nss_file = Utils.tmpfile('nss', NSS_URL) @tls_map = [] parse end
Stateless version of {App#search}. @param tls_map
[Hash] mapping of all TLS cipher suites returned by {tls_map}. @param criteria [Symbol] Same as `criteria` from {TLSmap::App#search} @param term [String] Same as `term` from {TLSmap::App#search} @param output [Symbol] Same as `output` from {TLSmap::App#search} @see App#search
@example
tm = TLSmap::App.new TLSmap::App.search(tm.tls_map, :iana, 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256') # => {:codepoint=>"CCA9", :iana=>"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", :openssl=>"ECDHE-ECDSA-CHACHA20-POLY1305", :gnutls=>"ECDHE_ECDSA_CHACHA20_POLY1305", :nss=>"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"} # or to use with the Cipher class ci = TLSmap::App::Cipher.new(:iana, 'TLS_DH_anon_WITH_RC4_128_MD5', tm.tls_map)
# File lib/tls_map.rb, line 77 def self.search(tls_map, criteria, term, output = :all) tls_map.each do |alg| term = term.upcase if criteria == :codepoint next unless alg[criteria] == term return alg if output == :all return { output => alg[output] } end {} end
Public Instance Methods
Search for corresponding cipher algorithms in other libraries in bulk @param criteria [Symbol] The type of `term`.
Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
@param file [String] File containing the cipher algorithm names, one per line. @param output [Symbol] The corresponding type to be included in the return value.
Accepted values: `:all` (default), `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
@return [Array<Hash>] The corresponding type, same as {search} return value
but one per line stored in an array.
# File lib/tls_map.rb, line 97 def bulk_search(criteria, file, output = :all) res = [] File.foreach(file) do |line| res.push(search(criteria, line.chomp, output)) end res end
Export the mapping to a file, supporting various formats. @param filename [String] The output file name to write to. @param format [Symbol] Supported formats: `:markdown` (a markdown table),
`:json_pretty` (expanded JSON), `:json_compact` (minified JSON), `:marshal` (Ruby marshalized hash).
# File lib/tls_map/app/output.rb, line 41 def export(filename, format) case format when :markdown then output_markdown(filename) when :json_pretty then output_json_pretty(filename) when :json_compact then output_json_compact(filename) when :marshal then output_marshal(filename) else raise "Wrong format: #{format}" end end
Search for corresponding cipher algorithms in other libraries @param criteria [Symbol] The type of `term`.
Accepted values: `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
@param term [String] The cipher algorithm name. @param output [Symbol] The corresponding type to be included in the return value.
Accepted values: `:all` (default), `:codepoint`, `:iana`, `:openssl`, `:gnutls`, `:nss`.
@return [Hash] The corresponding type matching `term`.
# File lib/tls_map.rb, line 52 def search(criteria, term, output = :all) @tls_map.each do |alg| term = term.upcase if criteria == :codepoint next unless alg[criteria] == term return alg if output == :all return { output => alg[output] } end {} end
Protected Instance Methods
# File lib/tls_map/app/output.rb, line 10 def markdown(table) output = "Codepoint | IANA | OpenSSL | GnuTLS | NSS\n" output += "--- | --- | --- | --- | ---\n" table.each do |alg| values = alg.values.map { |x| x.nil? ? '-' : x } output += "#{values.join(' | ')}\n" end output end
# File lib/tls_map/app/output.rb, line 28 def output_json_compact(filename) File.write(filename, JSON.generate(@tls_map)) end
# File lib/tls_map/app/output.rb, line 24 def output_json_pretty(filename) File.write(filename, JSON.pretty_generate(@tls_map)) end
# File lib/tls_map/app/output.rb, line 20 def output_markdown(filename) File.write(filename, markdown(@tls_map)) end
# File lib/tls_map/app/output.rb, line 32 def output_marshal(filename) File.write(filename, Marshal.dump(@tls_map)) end
# File lib/tls_map.rb, line 37 def parse parse_iana # must be first parse_openssl parse_gnutls parse_nss end
Private Instance Methods
# File lib/tls_map/app/openssl.rb, line 23 def clean_raw_data_openssl ck1, txt1, ck2, rfc2, ck3, txt3 = raw_data_openssl.values ck1.map! { |e| [e[0][8..], e[1]] } txt1.map! { |e| [e[0][9..], e[1]] } ck2.map! { |e| [e[0][10..], e[1]] } rfc2.map! { |e| [e[0][11..], e[1]] } ck3.map! { |e| [e[0][8..], e[1]] } txt3.map! { |e| [e[0][9..], e[1]] } { ck1: ck1, txt1: txt1, ck2: ck2, rfc2: rfc2, ck3: ck3, txt3: txt3 } end
remove Reserved, Unassigned codepoints (those with a range: X-X or *) also works with gnutls
# File lib/tls_map/app/iana.rb, line 14 def codepoint_iana(raw_cp) c1, c2 = raw_cp.split(',') c2.strip! return nil unless c2.size == 4 "#{c1[2..3]}#{c2[2..3]}" end
# File lib/tls_map/app/openssl.rb, line 36 def data_openssl # rubocop:disable Metrics/CyclomaticComplexity ck1, txt1, ck2, rfc2, ck3, txt3 = clean_raw_data_openssl.values data = ck1.map { |e| [e[1], txt1.select { |x| x[0] == e[0] }[0][1]] } data += ck2.map { |e| [e[1], rfc2.select { |x| x[0] == e[0] }[0][1]] } data += ck3.map do |e| candidate = txt3.select { |x| x[0] == e[0] } [e[1], candidate.empty? ? nil : candidate[0][1]] end data end
remove remaining Reserved, Unassigned codepoints
# File lib/tls_map/app/iana.rb, line 23 def desc_iana(desc) return nil if /Reserved|Unassigned/.match?(desc) desc end
# File lib/tls_map/app/gnutls.rb, line 11 def parse_gnutls reg = /(GNUTLS_[a-zA-Z0-9_]+)\s+{\s?(0x[[:xdigit:]]{2},\s?0x[[:xdigit:]]{2})\s?}/ File.read(@gnutls_file.path).scan(reg).each do |alg| codepoint = codepoint_iana(alg[1]) name = alg[0][7..] @tls_map.each do |h| h[:gnutls] ||= h[:codepoint] == codepoint.upcase ? name : nil end end end
# File lib/tls_map/app/iana.rb, line 29 def parse_iana CSV.foreach(@iana_file.path, **{ headers: true, header_converters: :symbol }) do |alg| codepoint = codepoint_iana(alg[:value]) description = desc_iana(alg[:description]) @tls_map << { codepoint: codepoint, iana: description } unless codepoint.nil? || description.nil? end end
# File lib/tls_map/app/nss.rb, line 13 def parse_nss File.read(@nss_file.path).scan(/(TLS_[a-zA-Z0-9_]+)\s+0x([[:xdigit:]]{4})/) do |alg| @tls_map.each do |h| h[:nss] ||= h[:codepoint] == alg[1].upcase ? alg[0] : nil end end end
# File lib/tls_map/app/openssl.rb, line 47 def parse_openssl data_openssl.each do |alg| @tls_map.each do |h| h[:openssl] ||= h[:codepoint] == alg[0].upcase ? alg[1] : nil end end end
# File lib/tls_map/app/openssl.rb, line 10 def raw_data_openssl openssl_h = File.read(@openssl_file.path) openssl_h2 = File.read(@openssl_file2.path) ck1 = openssl_h.scan(/(TLS1_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) txt1 = openssl_h.scan(/(TLS1_TXT_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9-]+)"/) ck2 = openssl_h.scan(/(TLS1_3_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) rfc2 = openssl_h.scan(/(TLS1_3_RFC_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9_]+)"/) ck3 = openssl_h2.scan(/(SSL3_CK_[a-zA-Z0-9_]+)\s+0x0300([[:xdigit:]]{4})/) txt3 = openssl_h2.scan(/(SSL3_TXT_[a-zA-Z0-9_]+)\s+"([a-zA-Z0-9-]+)"/) { ck1: ck1, txt1: txt1, ck2: ck2, rfc2: rfc2, ck3: ck3, txt3: txt3 } end