# = Action Pack WebAuthn Attestation # # Decodes and represents the attestation object returned by an authenticator # during registration. The attestation object is CBOR-encoded and contains # the authenticator data along with an optional attestation statement. # # == Usage # # attestation = ActionPack::WebAuthn::Authenticator::Attestation.decode( # attestation_object_bytes # ) # # attestation.credential_id # => "abc123..." # attestation.public_key # => OpenSSL::PKey::EC # attestation.sign_count # => 0 # # == Attributes # # [+authenticator_data+] # The parsed Data containing credential information. # # [+format+] # The attestation statement format (e.g., "none", "packed", "fido-u2f"). # # [+attestation_statement+] # The attestation statement, which may contain a signature from the # authenticator manufacturer. Empty for "none" format. # # == Delegated Methods # # The following methods are delegated to +authenticator_data+: # # * +credential_id+ - Base64URL-encoded credential identifier # * +public_key+ - OpenSSL public key object # * +public_key_bytes+ - Raw COSE key bytes # * +sign_count+ - Signature counter for replay detection # class ActionPack::WebAuthn::Authenticator::Attestation attr_reader :authenticator_data, :format, :attestation_statement delegate :credential_id, :public_key, :public_key_bytes, :sign_count, :aaguid, :backed_up?, to: :authenticator_data # Wraps raw attestation data into an Attestation instance. Accepts an # existing Attestation object (returned as-is), a Base64URL-encoded string, # or raw binary. def self.wrap(data) if data.is_a?(self) data else data = Base64.urlsafe_decode64(data) unless data.encoding == Encoding::BINARY decode(data) end rescue ArgumentError raise ActionPack::WebAuthn::InvalidResponseError, "Invalid base64 encoding in attestation object" end # Decodes a CBOR-encoded attestation object into an Attestation instance. def self.decode(bytes) cbor = ActionPack::WebAuthn::CborDecoder.decode(bytes) new( authenticator_data: ActionPack::WebAuthn::Authenticator::Data.decode(cbor["authData"]), format: cbor["fmt"], attestation_statement: cbor["attStmt"] ) end def initialize(authenticator_data:, format:, attestation_statement:) @authenticator_data = authenticator_data @format = format @attestation_statement = attestation_statement end end