Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: avoid attestation response knowing about different attestation stmt formats #23

Merged
merged 1 commit into from
May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
refactor: avoid attestation response knowing about different attestat…
…ion formats
  • Loading branch information
grzuy committed May 24, 2018
commit fb45c141c1627305696838679f0a935901847092
21 changes: 21 additions & 0 deletions lib/webauthn/attestation_statement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module WebAuthn
module AttestationStatement
ATTESTATION_FORMAT_NONE = "none"
ATTESTATION_FORMAT_FIDO_U2F = "fido-u2f"

def self.from(format, statement)
case format
when ATTESTATION_FORMAT_NONE
require "webauthn/attestation_statement/none"
WebAuthn::AttestationStatement::None.new(statement)
when ATTESTATION_FORMAT_FIDO_U2F
require "webauthn/attestation_statement/fido_u2f"
WebAuthn::AttestationStatement::FidoU2f.new(statement)
else
raise "Unsupported attestation format '#{attestation_format}'"
end
end
end
end
19 changes: 19 additions & 0 deletions lib/webauthn/attestation_statement/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module WebAuthn
module AttestationStatement
class Base
def initialize(statement)
@statement = statement
end

def valid?(*args)
raise NotImpelementedError
end

private

attr_reader :statement
end
end
end
61 changes: 61 additions & 0 deletions lib/webauthn/attestation_statement/fido_u2f.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

require "openssl"
require "webauthn/attestation_statement/base"

module WebAuthn
module AttestationStatement
class FidoU2f < Base
VALID_ATTESTATION_CERTIFICATE_COUNT = 1

def valid?(authenticator_data, client_data_hash)
valid_format? &&
valid_certificate_public_key? &&
valid_signature?(authenticator_data, client_data_hash)
end

private

def signature
statement["sig"]
end

def valid_format?
!!(raw_attestation_certificates && signature) &&
raw_attestation_certificates.length == VALID_ATTESTATION_CERTIFICATE_COUNT
end

def valid_certificate_public_key?
certificate_public_key.is_a?(OpenSSL::PKey::EC) && certificate_public_key.check_key
end

def certificate_public_key
attestation_certificate.public_key
end

def attestation_certificate
@attestation_certificate ||= OpenSSL::X509::Certificate.new(raw_attestation_certificates[0])
end

def raw_attestation_certificates
statement["x5c"]
end

def valid_signature?(authenticator_data, client_data_hash)
certificate_public_key.verify(
"SHA256",
signature,
verification_data(authenticator_data, client_data_hash)
)
end

def verification_data(authenticator_data, client_data_hash)
"\x00" +
authenticator_data.rp_id_hash +
client_data_hash +
authenticator_data.credential_id +
authenticator_data.credential_public_key
end
end
end
end
13 changes: 13 additions & 0 deletions lib/webauthn/attestation_statement/none.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require "webauthn/attestation_statement/base"

module WebAuthn
module AttestationStatement
class None < Base
def valid?(*args)
true
end
end
end
end
26 changes: 5 additions & 21 deletions lib/webauthn/authenticator_attestation_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@
require "cbor"

require "webauthn/authenticator_data"
require "webauthn/fido_u2f_attestation_statement"
require "webauthn/fido_u2f_attestation_statement_verification"
require "webauthn/attestation_statement"
require "webauthn/client_data"

module WebAuthn
class AuthenticatorAttestationResponse
ATTESTATION_FORMAT_NONE = "none"
ATTESTATION_FORMAT_FIDO_U2F = "fido-u2f"

def initialize(attestation_object:, client_data_json:)
@attestation_object = attestation_object
@client_data_json = client_data_json
Expand All @@ -23,7 +19,7 @@ def valid?(original_challenge, original_origin)
valid_origin?(original_origin) &&
authenticator_data.valid? &&
user_present? &&
valid_attestation_statement?
attestation_statement.valid?(authenticator_data, client_data.hash)
end

private
Expand All @@ -42,21 +38,9 @@ def valid_origin?(original_origin)
client_data.origin == original_origin
end

def valid_attestation_statement?
case attestation_format
when ATTESTATION_FORMAT_NONE
true
when ATTESTATION_FORMAT_FIDO_U2F
verification = WebAuthn::FidoU2fAttestationStatementVerification.new(
attestation_statement: WebAuthn::FidoU2fAttestationStatement.new(attestation["attStmt"]),
authenticator_data: authenticator_data,
client_data_hash: client_data.hash
)

verification.successful?
else
raise "Unsupported attestation format '#{attestation_format}'"
end
def attestation_statement
@attestation_statement ||=
WebAuthn::AttestationStatement.from(attestation["fmt"], attestation["attStmt"])
end

def user_present?
Expand Down
4 changes: 3 additions & 1 deletion lib/webauthn/client_data.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "openssl"

module WebAuthn
class ClientData
def initialize(client_data_json)
Expand All @@ -19,7 +21,7 @@ def origin
end

def hash
Digest::SHA256.digest(decoded_client_data_json)
OpenSSL::Digest::SHA256.digest(decoded_client_data_json)
end

private
Expand Down
46 changes: 0 additions & 46 deletions lib/webauthn/fido_u2f_attestation_statement.rb

This file was deleted.

38 changes: 0 additions & 38 deletions lib/webauthn/fido_u2f_attestation_statement_verification.rb

This file was deleted.