Class: EchSpec::Spec::Spec9
- Inherits:
-
Object
- Object
- EchSpec::Spec::Spec9
- Defined in:
- lib/echspec/spec/9.rb
Class Attribute Summary collapse
-
.description ⇒ Object
readonly
Returns the value of attribute description.
-
.section ⇒ Object
readonly
Returns the value of attribute section.
Class Method Summary collapse
- .parse_pem(pem) ⇒ EchSpec::Ok<Array of ECHConfig> | Err
- .resolve_ech_configs(hostname) ⇒ EchSpec::Ok<Array of ECHConfig> | Err
- .try_get_ech_config(fpath, hostname, force_compliant) ⇒ EchSpec::Ok<ECHConfig> | Err
- .validate_compliant_ech_configs(ech_configs) ⇒ EchSpec::Ok<ECHConfig> | Err
Class Attribute Details
.description ⇒ Object (readonly)
Returns the value of attribute description.
16 17 18 |
# File 'lib/echspec/spec/9.rb', line 16 def description @description end |
.section ⇒ Object (readonly)
Returns the value of attribute section.
16 17 18 |
# File 'lib/echspec/spec/9.rb', line 16 def section @section end |
Class Method Details
.parse_pem(pem) ⇒ EchSpec::Ok<Array of ECHConfig> | Err
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/echspec/spec/9.rb', line 89 def parse_pem(pem) s = pem.scan(/-----BEGIN ECHCONFIG-----(.*)-----END ECHCONFIG-----/m) .first .first .gsub("\n", '') b = Base64.decode64(s) ech_configs = ECHConfig.decode_vectors(b.slice(2..)) Ok.new(ech_configs) rescue StandardError # https://datatracker.ietf.org/doc/html/draft-farrell-tls-pemesni-08#section-3 example = <<~PEM -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V -----END PRIVATE KEY----- -----BEGIN ECHCONFIG----- AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEA AQALZXhhbXBsZS5jb20AAA== -----END ECHCONFIG----- PEM Err.new("Failed to parse ECHConfig PEM file, expected ECHConfig PEM like following: \n\n#{example}", nil) end |
.resolve_ech_configs(hostname) ⇒ EchSpec::Ok<Array of ECHConfig> | Err
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/echspec/spec/9.rb', line 65 def resolve_ech_configs(hostname) begin rr = Resolv::DNS.new.getresource( hostname, Resolv::DNS::Resource::IN::HTTPS ) rescue Resolv::ResolvError => e return Err.new(e., nil) end # https://datatracker.ietf.org/doc/html/draft-ietf-tls-svcb-ech-01#section-6 ech = 5 return Err.new("HTTPS resource record for #{hostname} does NOT have ech SvcParams.", nil) if rr.params[ech].nil? octet = rr.params[ech].value Err.new('Failed to parse ECHConfig on HTTPS resource record.', nil) \ unless octet.length == octet.slice(0, 2).unpack1('n') + 2 Ok.new(ECHConfig.decode_vectors(octet.slice(2..))) end |
.try_get_ech_config(fpath, hostname, force_compliant) ⇒ EchSpec::Ok<ECHConfig> | Err
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/echspec/spec/9.rb', line 23 def try_get_ech_config(fpath, hostname, force_compliant) result = if fpath.nil? resolve_ech_configs(hostname) else parse_pem(File.open(fpath).read) end ech_configs = case result in Ok(obj) obj in Err return result end if force_compliant validate_compliant_ech_configs(ech_configs) else Ok.new(ech_configs.first) end end |
.validate_compliant_ech_configs(ech_configs) ⇒ EchSpec::Ok<ECHConfig> | Err
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/echspec/spec/9.rb', line 47 def validate_compliant_ech_configs(ech_configs) ech_config = ech_configs.find do |c| kconfig = c.echconfig_contents.key_config valid_kem_id = kconfig.kem_id.uint16 == 0x0020 valid_cipher_suite = kconfig.cipher_suites.any? do |cs| cs.kdf_id.uint16 == 0x0001 && cs.aead_id.uint16 == 0x0001 end valid_kem_id && valid_cipher_suite end return Ok.new(ech_config) unless ech_config.nil? Err.new('ECHConfigs does NOT include HPKE cipher suite: KEM: DHKEM(X25519, HKDF-SHA256), KDF: HKDF-SHA256 and AEAD: AES-128-GCM.', nil) end |