class WebAuthn::AttestationStatement::Base

def algorithm

def algorithm
  statement["alg"]
end

def attestation_certificate

def attestation_certificate
  certificates&.first
end

def attestation_certificate_key_id

def attestation_certificate_key_id
  attestation_certificate.subject_key_identifier&.unpack("H*")&.[](0)
end

def attestation_root_certificates_store(aaguid: nil, attestation_certificate_key_id: nil)

def attestation_root_certificates_store(aaguid: nil, attestation_certificate_key_id: nil)
  OpenSSL::X509::Store.new.tap do |store|
    root_certificates(
      aaguid: aaguid,
      attestation_certificate_key_id: attestation_certificate_key_id
    ).each do |cert|
      store.add_cert(cert)
    end
  end
end

def attestation_trust_path

def attestation_trust_path
  if certificates&.any?
    certificates
  end
end

def certificates

def certificates
  @certificates ||=
    raw_certificates&.map do |raw_certificate|
      OpenSSL::X509::Certificate.new(raw_certificate)
    end
end

def cose_algorithm

def cose_algorithm
  @cose_algorithm ||=
    COSE::Algorithm.find(algorithm).tap do |alg|
      alg && relying_party.algorithms.include?(alg.name) ||
        raise(UnsupportedAlgorithm, "Unsupported algorithm #{algorithm}")
    end
end

def format

def format
  WebAuthn::AttestationStatement::FORMAT_TO_CLASS.key(self.class)
end

def initialize(statement, relying_party = WebAuthn.configuration.relying_party)

def initialize(statement, relying_party = WebAuthn.configuration.relying_party)
  @statement = statement
  @relying_party = relying_party
end

def matching_aaguid?(attested_credential_data_aaguid)

def matching_aaguid?(attested_credential_data_aaguid)
  extension = attestation_certificate&.find_extension(AAGUID_EXTENSION_OID)
  if extension
    aaguid_value = OpenSSL::ASN1.decode(extension.value_der).value
    aaguid_value == attested_credential_data_aaguid
  else
    true
  end
end

def matching_public_key?(authenticator_data)

def matching_public_key?(authenticator_data)
  attestation_certificate.public_key.to_der == authenticator_data.credential.public_key_object.to_der
end

def raw_certificates

def raw_certificates
  statement["x5c"]
end

def root_certificates(aaguid: nil, attestation_certificate_key_id: nil)

def root_certificates(aaguid: nil, attestation_certificate_key_id: nil)
  root_certificates =
    relying_party.attestation_root_certificates_finders.reduce([]) do |certs, finder|
      if certs.empty?
        finder.find(
          attestation_format: format,
          aaguid: aaguid,
          attestation_certificate_key_id: attestation_certificate_key_id
        ) || []
      else
        certs
      end
    end
  if root_certificates.empty? && respond_to?(:default_root_certificates, true)
    default_root_certificates
  else
    root_certificates
  end
end

def signature

def signature
  statement["sig"]
end

def trustworthy?(aaguid: nil, attestation_certificate_key_id: nil)

def trustworthy?(aaguid: nil, attestation_certificate_key_id: nil)
  if ATTESTATION_TYPES_WITH_ROOT.include?(attestation_type)
    relying_party.acceptable_attestation_types.include?(attestation_type) &&
      valid_certificate_chain?(aaguid: aaguid, attestation_certificate_key_id: attestation_certificate_key_id)
  else
    relying_party.acceptable_attestation_types.include?(attestation_type)
  end
end

def valid?(_authenticator_data, _client_data_hash)

def valid?(_authenticator_data, _client_data_hash)
  raise NotImplementedError
end

def valid_certificate_chain?(aaguid: nil, attestation_certificate_key_id: nil)

def valid_certificate_chain?(aaguid: nil, attestation_certificate_key_id: nil)
  root_certificates = root_certificates(
    aaguid: aaguid,
    attestation_certificate_key_id: attestation_certificate_key_id
  )
  if certificates&.one? && root_certificates.include?(attestation_certificate)
    return true
  end
  attestation_root_certificates_store(
    aaguid: aaguid,
    attestation_certificate_key_id: attestation_certificate_key_id
  ).verify(attestation_certificate, attestation_trust_path)
end

def valid_signature?(authenticator_data, client_data_hash, public_key = attestation_certificate.public_key)

def valid_signature?(authenticator_data, client_data_hash, public_key = attestation_certificate.public_key)
  raise("Incompatible algorithm and key") unless cose_algorithm.compatible_key?(public_key)
  cose_algorithm.verify(
    public_key,
    signature,
    verification_data(authenticator_data, client_data_hash)
  )
rescue COSE::Error
  false
end

def verification_data(authenticator_data, client_data_hash)

def verification_data(authenticator_data, client_data_hash)
  authenticator_data.data + client_data_hash
end