class Sqreen::SqreenSignedVerifier

Normalize and verify a rule

Constants

PUBLIC_KEY
REQUIRED_SIGNED_KEYS
SIGNATURE_KEY
SIGNATURE_VALUE_KEY
SIGNATURE_VERSION
SIGNED_KEYS_KEY

Attributes

digest[RW]
pub_key[RW]
required_signed_keys[RW]
use_oj[RW]

Public Class Methods

new(required_keys = REQUIRED_SIGNED_KEYS, public_key = PUBLIC_KEY, digest = OpenSSL::Digest::SHA512.new, use_oj_gem = nil) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 47
def initialize(required_keys = REQUIRED_SIGNED_KEYS,
               public_key    = PUBLIC_KEY,
               digest        = OpenSSL::Digest::SHA512.new, use_oj_gem = nil)
  @required_signed_keys = required_keys
  @signature_verifier   = SignatureVerifier.new(public_key, digest)
  @use_oj = use_oj_gem.nil? ? OJ_LOADED : use_oj_gem
end

Public Instance Methods

get_sig_infos_or_fail(hash_rule) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 121
def get_sig_infos_or_fail(hash_rule)
  raise Sqreen::Exception, 'non hash argument' unless hash_rule.is_a?(Hash)

  sigs = hash_rule[SIGNATURE_KEY]
  raise Sqreen::Exception, 'no signature found' unless sigs

  sig = sigs[SIGNATURE_VERSION]
  msg = "signature #{SIGNATURE_VERSION} not found (#{sigs})"
  raise Sqreen::Exception, msg unless sig

  sig_value = sig[SIGNATURE_VALUE_KEY]
  raise Sqreen::Exception, 'no signature value found' unless sig_value

  signed_keys = sig[SIGNED_KEYS_KEY]
  raise Sqreen::Exception, "no signed keys found (#{sig})" unless signed_keys

  inc = Set.new(signed_keys).superset?(Set.new(@required_signed_keys))
  raise Sqreen::Exception, 'signed keys miss equired keys' unless inc

  [signed_keys, sig_value]
end
normalize(hash_rule, signed_keys = nil, level = 20) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 94
def normalize(hash_rule, signed_keys = nil, level = 20)
  # Normalize the provided hash to a string:
  #  - sort keys lexicographically, recursively
  #  - convert each scalar to its JSON representation
  #  - convert hash to '{key:value}'
  #  - convert array [v1,v2] to '[v1,v2]' and [] to '[]'
  # Two hash with different key ordering should have the same normalized
  # value.

  raise Sqreen::Exception, 'recursion level too deep' if level == 0
  unless hash_rule.is_a?(Hash)
    raise Sqreen::Exception, "wrong hash type #{hash_rule.class}"
  end

  res = []
  hash_rule.sort.each do |k, v|
    # Only keep signed keys
    next if signed_keys && !signed_keys.include?(k)

    k = normalize_key(k)
    v = normalize_val(v, level - 1)

    res << "#{k}:#{v}"
  end
  "{#{res.join(',')}}"
end
normalize_key(key) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 79
def normalize_key(key)
  case key
  when String, Integer
    return Oj.dump(key, :mode => :compat, :escape_mode => :json) if use_oj
    begin
      JSON.dump(key)
    rescue JSON::GeneratorError
      JSON.generate(key, :quirks_mode => true)
    end
  else
    msg = "JSON hash parsing error (wrong key type: #{key.class})"
    raise Sqreen::Exception, msg
  end
end
normalize_val(val, level) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 55
def normalize_val(val, level)
  raise Sqreen::Exception, 'recursion level too deep' if level == 0

  case val
  when Hash
    normalize(val, nil, level - 1)
  when Array
    ary = val.map do |i|
      normalize_val(i, level - 1)
    end
    "[#{ary.join(',')}]"
  when String, Integer
    return Oj.dump(val, :mode => :compat, :escape_mode => :json) if use_oj
    begin
      JSON.dump(val)
    rescue JSON::GeneratorError
      JSON.generate(val, :quirks_mode => true)
    end
  else
    msg = "JSON hash parsing error (wrong value type: #{val.class})"
    raise Sqreen::Exception.new, msg
  end
end
verify(hash_rule) click to toggle source
# File lib/sqreen/sqreen_signed_verifier.rb, line 143
def verify(hash_rule)
  # Return true if rule signature is correct, else false

  signed_keys, sig_value = get_sig_infos_or_fail(hash_rule)

  norm_str = normalize(hash_rule, signed_keys)
  bin_sig = Base64.decode64(sig_value)
  @signature_verifier.verify(bin_sig, norm_str)
rescue OpenSSL::PKey::ECError
  false
end