Module: EchSpec::Spec

Defined in:
lib/echspec/spec.rb,
lib/echspec/spec.rb,
lib/echspec/spec/9.rb,
lib/echspec/spec/7-5.rb,
lib/echspec/spec/5.1-9.rb,
lib/echspec/spec/5.1-10.rb,
lib/echspec/spec/7.1-11.rb,
lib/echspec/spec/7.1.1-2.rb,
lib/echspec/spec/7.1.1-5.rb,
lib/echspec/spec/7.1-14.2.1.rb

Defined Under Namespace

Classes: ResultDesc, Spec5_1_10, Spec5_1_9, Spec7_1_11, Spec7_1_14_2_1, Spec7_1_1_2, Spec7_1_1_5, Spec7_5, Spec9, WithSocket

Class Method Summary collapse

Class Method Details

.do_run(port, hostname, ech_config, targets, verbose) ⇒ Object

Parameters:

  • port (Integer)
  • hostname (String)
  • ech_config (ECHConfig)
  • targets (Array of EchSpec::SpecGroup)
  • verbose (Boolean)


124
125
126
127
128
129
130
131
132
133
134
# File 'lib/echspec/spec.rb', line 124

def do_run(port, hostname, ech_config, targets, verbose)
  rds = targets.flat_map do |g|
    g.spec_cases.map do |sc|
      r = sc.method.call(hostname, port, ech_config)
      d = "#{sc.description} [#{g.section}]"
      ResultDesc.new(result: r, desc: d)
    end
  end

  print_results(rds, verbose)
end

.expect_alert(msg, desc) ⇒ Boolean

Parameters:

  • msg (TTTLS13::Message::Record)
  • desc (Symbol)

Returns:

  • (Boolean)


10
11
12
13
# File 'lib/echspec/spec.rb', line 10

def expect_alert(msg, desc)
  msg.is_a?(TTTLS13::Message::Alert) &&
    msg.description == TTTLS13::Message::ALERT_DESCRIPTION[desc]
end

Parameters:

  • err (EchSpec::Err)
  • idx (Integer)
  • desc (String)
  • verbose (Boolean)


50
51
52
53
54
55
# File 'lib/echspec/spec.rb', line 50

def print_err_details(err, idx, desc, verbose)
  puts "\t#{idx + 1}) #{desc}"
  puts "\t\t#{err.details}"
  warn err.message_stack if verbose && !err.message_stack.nil?
  puts
end

Parameters:

  • rds (Array of ResultDesc)

    result: EchSpec::Ok | Err, desc: String

  • verbose (Boolean)


19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/echspec/spec.rb', line 19

def print_results(rds, verbose)
  rds.each { |rd| print_summary(rd.result, rd.desc) }
  failures = rds.filter { |rd| rd.result.is_a? Err }
  return if failures.empty?

  puts
  puts 'Failures:'
  puts
  failures.each
          .with_index { |rd, idx| print_err_details(rd.result, idx, rd.desc, verbose) }
  puts "#{failures.length} failure".red
end

Parameters:



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/echspec/spec.rb', line 34

def print_summary(result, desc)
  check = "\u2714"
  cross = "\u0078"
  summary = case result
            in Ok
              "\t#{check} #{desc}".green
            in Err
              "\t#{cross} #{desc}".red
            end
  puts summary
end

.run(fpath, port, hostname, force_compliant, verbose) ⇒ Object

Parameters:

  • fpath (String | NilClass)
  • port (Integer)
  • hostname (String)
  • force_compliant (Boolean)
  • verbose (Boolean)


95
96
97
98
99
100
101
# File 'lib/echspec/spec.rb', line 95

def run(fpath, port, hostname, force_compliant, verbose)
  TTTLS13::Logging.logger.level = Logger::WARN
  puts 'TLS Encrypted Client Hello Server'
  ech_config = try_get_ech_config(fpath, hostname, force_compliant)

  do_run(port, hostname, ech_config, spec_groups, verbose)
end

.run_only(fpath, port, hostname, sections, verbose) ⇒ Object

Parameters:

  • fpath (String | NilClass)
  • port (Integer)
  • hostname (String)
  • sections (Array of String)
  • verbose (Boolean)


108
109
110
111
112
113
114
115
116
117
# File 'lib/echspec/spec.rb', line 108

def run_only(fpath, port, hostname, sections, verbose)
  targets = spec_groups.filter { |g| sections.include?(g.section) }
  force_compliant = sections.include?(Spec9.section)

  TTTLS13::Logging.logger.level = Logger::WARN
  puts 'TLS Encrypted Client Hello Server'
  ech_config = try_get_ech_config(fpath, hostname, force_compliant)

  do_run(port, hostname, ech_config, targets, verbose)
end

.sectionsObject



165
166
167
# File 'lib/echspec/spec.rb', line 165

def sections
  (spec_groups + [Spec9]).map(&:section)
end

.spec_groupsObject



155
156
157
158
159
160
161
162
163
# File 'lib/echspec/spec.rb', line 155

def spec_groups
  # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-22#section-5
  groups = [Spec5_1_9, Spec5_1_10]

  # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-22#section-7
  groups += [Spec7_5, Spec7_1_11, Spec7_1_14_2_1, Spec7_1_1_2, Spec7_1_1_5]

  groups.map(&:spec_group)
end

.try_get_ech_config(fpath, hostname, force_compliant) ⇒ ECHConfig

Parameters:

  • fpath (String | NilClass)
  • hostname (String)
  • force_compliant (Boolean)

Returns:

  • (ECHConfig)


141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/echspec/spec.rb', line 141

def try_get_ech_config(fpath, hostname, force_compliant)
  # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-22#section-9
  case result = Spec9.try_get_ech_config(fpath, hostname, force_compliant)
  in Ok(obj) if force_compliant
    result.tap { |r| print_summary(r, "#{Spec9.description} [#{Spec9.section}]") }
    obj
  in Ok(obj)
    obj
  in Err(details, _)
    puts "\t#{details}".red
    exit 1
  end
end