lib/webauthn/attestation_statement/fido_u2f.rb
# frozen_string_literal: true require "cose" require "openssl" require "webauthn/attestation_statement/base" require "webauthn/attestation_statement/fido_u2f/public_key" module WebAuthn module AttestationStatement class FidoU2f < Base VALID_ATTESTATION_CERTIFICATE_COUNT = 1 VALID_ATTESTATION_CERTIFICATE_ALGORITHM = COSE::Algorithm.by_name("ES256") VALID_ATTESTATION_CERTIFICATE_KEY_CURVE = COSE::Key::Curve.by_name("P-256") def valid?(authenticator_data, client_data_hash) valid_format? && valid_certificate_public_key? && valid_credential_public_key?(authenticator_data.credential.public_key) && valid_aaguid?(authenticator_data.attested_credential_data.raw_aaguid) && valid_signature?(authenticator_data, client_data_hash) && trustworthy?(attestation_certificate_key_id: attestation_certificate_key_id) && [attestation_type, attestation_trust_path] end private def valid_format? !!(raw_certificates && signature) && raw_certificates.length == VALID_ATTESTATION_CERTIFICATE_COUNT end def valid_certificate_public_key? certificate_public_key.is_a?(OpenSSL::PKey::EC) && certificate_public_key.group.curve_name == VALID_ATTESTATION_CERTIFICATE_KEY_CURVE.pkey_name && certificate_public_key.check_key end def valid_credential_public_key?(public_key_bytes) public_key_u2f(public_key_bytes).valid? end def certificate_public_key attestation_certificate.public_key end def valid_aaguid?(attested_credential_data_aaguid) attested_credential_data_aaguid == WebAuthn::AuthenticatorData::AttestedCredentialData::ZEROED_AAGUID end def algorithm VALID_ATTESTATION_CERTIFICATE_ALGORITHM.id end def verification_data(authenticator_data, client_data_hash) "\x00" + authenticator_data.rp_id_hash + client_data_hash + authenticator_data.credential.id + public_key_u2f(authenticator_data.credential.public_key).to_uncompressed_point end def public_key_u2f(cose_key_data) PublicKey.new(cose_key_data) end def attestation_type WebAuthn::AttestationStatement::ATTESTATION_TYPE_BASIC_OR_ATTCA end end end end