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

tls_map[R]

Get the mapping of all TLS cipher suites @return [Hash] mapping of all TLS cipher suites

Public Class Methods

new() click to toggle source

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

Public Instance Methods

export(filename, format) click to toggle source

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

Protected Instance Methods

markdown(table) click to toggle source
# 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
output_json_compact(filename) click to toggle source
# File lib/tls_map/app/output.rb, line 28
def output_json_compact(filename)
  File.write(filename, JSON.generate(@tls_map))
end
output_json_pretty(filename) click to toggle source
# File lib/tls_map/app/output.rb, line 24
def output_json_pretty(filename)
  File.write(filename, JSON.pretty_generate(@tls_map))
end
output_markdown(filename) click to toggle source
# File lib/tls_map/app/output.rb, line 20
def output_markdown(filename)
  File.write(filename, markdown(@tls_map))
end
output_marshal(filename) click to toggle source
# File lib/tls_map/app/output.rb, line 32
def output_marshal(filename)
  File.write(filename, Marshal.dump(@tls_map))
end
parse() click to toggle source
# File lib/tls_map.rb, line 37
def parse
  parse_iana # must be first
  parse_openssl
  parse_gnutls
  parse_nss
end

Private Instance Methods

clean_raw_data_openssl() click to toggle source
# 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
codepoint_iana(raw_cp) click to toggle source

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
data_openssl() click to toggle source
# 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
desc_iana(desc) click to toggle source

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
parse_gnutls() click to toggle source
# 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
parse_iana() click to toggle source
# 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
parse_nss() click to toggle source
# 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
parse_openssl() click to toggle source
# 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
raw_data_openssl() click to toggle source
# 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