File: authenticator_assertion_response.rb

package info (click to toggle)
ruby-webauthn 2.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 384 kB
  • sloc: ruby: 2,138; sh: 4; makefile: 4
file content (72 lines) | stat: -rw-r--r-- 2,139 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# frozen_string_literal: true

require "webauthn/authenticator_data"
require "webauthn/authenticator_response"
require "webauthn/encoder"
require "webauthn/public_key"

module WebAuthn
  class SignatureVerificationError < VerificationError; end
  class SignCountVerificationError < VerificationError; end

  class AuthenticatorAssertionResponse < AuthenticatorResponse
    def self.from_client(response)
      encoder = WebAuthn.configuration.encoder

      user_handle =
        if response["userHandle"]
          encoder.decode(response["userHandle"])
        end

      new(
        authenticator_data: encoder.decode(response["authenticatorData"]),
        client_data_json: encoder.decode(response["clientDataJSON"]),
        signature: encoder.decode(response["signature"]),
        user_handle: user_handle
      )
    end

    attr_reader :user_handle

    def initialize(authenticator_data:, signature:, user_handle: nil, **options)
      super(**options)

      @authenticator_data_bytes = authenticator_data
      @signature = signature
      @user_handle = user_handle
    end

    def verify(expected_challenge, expected_origin = nil, public_key:, sign_count:, user_verification: nil, rp_id: nil)
      super(expected_challenge, expected_origin, user_verification: user_verification, rp_id: rp_id)
      verify_item(:signature, WebAuthn::PublicKey.deserialize(public_key))
      verify_item(:sign_count, sign_count)

      true
    end

    def authenticator_data
      @authenticator_data ||= WebAuthn::AuthenticatorData.deserialize(authenticator_data_bytes)
    end

    private

    attr_reader :authenticator_data_bytes, :signature

    def valid_signature?(webauthn_public_key)
      webauthn_public_key.verify(signature, authenticator_data_bytes + client_data.hash)
    end

    def valid_sign_count?(stored_sign_count)
      normalized_sign_count = stored_sign_count || 0
      if authenticator_data.sign_count.nonzero? || normalized_sign_count.nonzero?
        authenticator_data.sign_count > normalized_sign_count
      else
        true
      end
    end

    def type
      WebAuthn::TYPES[:get]
    end
  end
end