Skip to content

Commit

Permalink
feat: parse metadata statements
Browse files Browse the repository at this point in the history
  • Loading branch information
bdewater committed Jul 1, 2019
1 parent 64e39bc commit ae0e21e
Show file tree
Hide file tree
Showing 22 changed files with 793 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/webauthn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "webauthn/credential_creation_options"
require "webauthn/credential_request_options"
require "webauthn/metadata/client"
require "webauthn/metadata/statement"
require "webauthn/metadata/table_of_contents"
require "webauthn/public_key_credential"
require "webauthn/version"
17 changes: 17 additions & 0 deletions lib/webauthn/metadata/biometric_accuracy_descriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require "webauthn/metadata/attributes"

module WebAuthn
module Metadata
class BiometricAccuracyDescriptor
extend Attributes

json_accessor("selfAttestedFRR")
json_accessor("selfAttestedFAR")
json_accessor("maxTemplates")
json_accessor("maxRetries")
json_accessor("blockSlowdown")
end
end
end
16 changes: 16 additions & 0 deletions lib/webauthn/metadata/code_accuracy_descriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

require "webauthn/metadata/attributes"

module WebAuthn
module Metadata
class CodeAccuracyDescriptor
extend Attributes

json_accessor("base")
json_accessor("minLength")
json_accessor("maxRetries")
json_accessor("blockSlowdown")
end
end
end
21 changes: 21 additions & 0 deletions lib/webauthn/metadata/coercer/assumed_value.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module WebAuthn
module Metadata
module Coercer
class AssumedValue
def initialize(assume)
@assume = assume
end

def coerce(value)
if value.nil?
@assume
else
value
end
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/webauthn/metadata/coercer/bit_field.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module WebAuthn
module Metadata
module Coercer
class BitField
def initialize(mapping, single_value: false)
@mapping = mapping
@single_value = single_value
end

def coerce(value)
results = @mapping.reject { |flag, _constant| flag & value == 0 }.values

if @single_value
results.first
else
results
end
end
end
end
end
end
18 changes: 18 additions & 0 deletions lib/webauthn/metadata/coercer/certificates.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

require "openssl/x509"

module WebAuthn
module Metadata
module Coercer
module Certificates
def self.coerce(values)
return unless values.is_a?(Array)
return values if values.all? { |value| value.is_a?(OpenSSL::X509::Certificate) }

values.map { |value| OpenSSL::X509::Certificate.new(Base64.decode64(value)) }
end
end
end
end
end
26 changes: 26 additions & 0 deletions lib/webauthn/metadata/coercer/magic_number.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module WebAuthn
module Metadata
module Coercer
class MagicNumber
def initialize(mapping, array: false)
@mapping = mapping
@array = array
end

def coerce(values)
if @array
return values unless values.all? { |value| value.is_a?(Integer) }

values.map { |value| @mapping[value] }.compact
else
return values unless values.is_a?(Integer)

@mapping[values]
end
end
end
end
end
end
38 changes: 38 additions & 0 deletions lib/webauthn/metadata/coercer/user_verification_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require "webauthn/metadata/verification_method_descriptor"

module WebAuthn
module Metadata
module Coercer
class UserVerificationDetails
def self.coerce(values)
return unless values.is_a?(Array)
return values if values.all? do |array|
array.all? do |object|
object.is_a?(VerificationMethodDescriptor)
end
end

values.map do |array|
array.map do |hash|
object = WebAuthn::Metadata::VerificationMethodDescriptor.from_json(hash)

if hash["baDesc"]
object.ba_desc = WebAuthn::Metadata::BiometricAccuracyDescriptor.from_json(hash["baDesc"])
end
if hash["caDesc"]
object.ca_desc = WebAuthn::Metadata::CodeAccuracyDescriptor.from_json(hash["caDesc"])
end
if hash["paDesc"]
object.pa_desc = WebAuthn::Metadata::PatternAccuracyDescriptor.from_json(hash["paDesc"])
end

object
end
end
end
end
end
end
end
93 changes: 93 additions & 0 deletions lib/webauthn/metadata/constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

module WebAuthn
module Metadata
module Constants
# https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-registry-v2.0-rd-20180702.html

ATTACHMENT_HINTS = {
0x0001 => "ATTACHMENT_HINT_INTERNAL",
0x0002 => "ATTACHMENT_HINT_EXTERNAL",
0x0004 => "ATTACHMENT_HINT_WIRED",
0x0008 => "ATTACHMENT_HINT_WIRELESS",
0x0010 => "ATTACHMENT_HINT_NFC",
0x0020 => "ATTACHMENT_HINT_BLUETOOTH",
0x0040 => "ATTACHMENT_HINT_NETWORK",
0x0080 => "ATTACHMENT_HINT_READY",
0x0100 => "ATTACHMENT_HINT_WIFI_DIRECT",
}.freeze

ATTESTATION_TYPES = {
0x3E07 => "ATTESTATION_BASIC_FULL",
0x3E08 => "ATTESTATION_BASIC_SURROGATE",
0x3E09 => "ATTESTATION_ECDAA",
0x3E0A => "ATTESTATION_ATTCA",
}.freeze

AUTHENTICATION_ALGORITHMS = {
0x0001 => "ALG_SIGN_SECP256R1_ECDSA_SHA256_RAW",
0x0002 => "ALG_SIGN_SECP256R1_ECDSA_SHA256_DER",
0x0003 => "ALG_SIGN_RSASSA_PSS_SHA256_RAW",
0x0004 => "ALG_SIGN_RSASSA_PSS_SHA256_DER",
0x0005 => "ALG_SIGN_SECP256K1_ECDSA_SHA256_RAW",
0x0006 => "ALG_SIGN_SECP256K1_ECDSA_SHA256_DER",
0x0007 => "ALG_SIGN_SM2_SM3_RAW",
0x0008 => "ALG_SIGN_RSA_EMSA_PKCS1_SHA256_RAW",
0x0009 => "ALG_SIGN_RSA_EMSA_PKCS1_SHA256_DER",
0x000A => "ALG_SIGN_RSASSA_PSS_SHA384_RAW",
0x000B => "ALG_SIGN_RSASSA_PSS_SHA512_RAW",
0x000C => "ALG_SIGN_RSASSA_PKCSV15_SHA256_RAW",
0x000D => "ALG_SIGN_RSASSA_PKCSV15_SHA384_RAW",
0x000E => "ALG_SIGN_RSASSA_PKCSV15_SHA512_RAW",
0x000F => "ALG_SIGN_RSASSA_PKCSV15_SHA1_RAW",
0x0010 => "ALG_SIGN_SECP384R1_ECDSA_SHA384_RAW",
0x0011 => "ALG_SIGN_SECP521R1_ECDSA_SHA512_RAW",
0x0012 => "ALG_SIGN_ED25519_EDDSA_SHA256_RAW",
}.freeze

KEY_PROTECTION_TYPES = {
0x0001 => "KEY_PROTECTION_SOFTWARE",
0x0002 => "KEY_PROTECTION_HARDWARE",
0x0004 => "KEY_PROTECTION_TEE",
0x0008 => "KEY_PROTECTION_SECURE_ELEMENT",
0x0010 => "KEY_PROTECTION_REMOTE_HANDLE",
}.freeze

MATCHER_PROTECTION_TYPES = {
0x0001 => "MATCHER_PROTECTION_SOFTWARE",
0x0002 => "MATCHER_PROTECTION_TEE",
0x0004 => "MATCHER_PROTECTION_ON_CHIP",
}.freeze

PUBLIC_KEY_FORMATS = {
0x0100 => "ALG_KEY_ECC_X962_RAW",
0x0101 => "ALG_KEY_ECC_X962_DER",
0x0102 => "ALG_KEY_RSA_2048_RAW",
0x0103 => "ALG_KEY_RSA_2048_DER",
0x0104 => "ALG_KEY_COSE",
}.freeze

TRANSACTION_CONFIRMATION_DISPLAY_TYPES = {
0x0001 => "TRANSACTION_CONFIRMATION_DISPLAY_ANY",
0x0002 => "TRANSACTION_CONFIRMATION_DISPLAY_PRIVILEGED_SOFTWARE",
0x0004 => "TRANSACTION_CONFIRMATION_DISPLAY_TEE",
0x0008 => "TRANSACTION_CONFIRMATION_DISPLAY_HARDWARE",
0x0010 => "TRANSACTION_CONFIRMATION_DISPLAY_REMOTE",
}.freeze

USER_VERIFICATION_METHODS = {
0x00000001 => "USER_VERIFY_PRESENCE",
0x00000002 => "USER_VERIFY_FINGERPRINT",
0x00000004 => "USER_VERIFY_PASSCODE",
0x00000008 => "USER_VERIFY_VOICEPRINT",
0x00000010 => "USER_VERIFY_FACEPRINT",
0x00000020 => "USER_VERIFY_LOCATION",
0x00000040 => "USER_VERIFY_EYEPRINT",
0x00000080 => "USER_VERIFY_PATTERN",
0x00000100 => "USER_VERIFY_HANDPRINT",
0x00000200 => "USER_VERIFY_NONE",
0x00000400 => "USER_VERIFY_ALL",
}.freeze
end
end
end
15 changes: 15 additions & 0 deletions lib/webauthn/metadata/pattern_accuracy_descriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require "webauthn/metadata/attributes"

module WebAuthn
module Metadata
class PatternAccuracyDescriptor
extend Attributes

json_accessor("minComplexity")
json_accessor("maxRetries")
json_accessor("blockSlowdown")
end
end
end
53 changes: 53 additions & 0 deletions lib/webauthn/metadata/statement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

require "webauthn/metadata/attributes"
require "webauthn/metadata/constants"
require "webauthn/metadata/verification_method_descriptor"
require "webauthn/metadata/coercer/assumed_value"
require "webauthn/metadata/coercer/bit_field"
require "webauthn/metadata/coercer/certificates"
require "webauthn/metadata/coercer/magic_number"
require "webauthn/metadata/coercer/user_verification_details"

module WebAuthn
module Metadata
class Statement
extend Attributes

json_accessor("legalHeader")
json_accessor("aaid")
json_accessor("aaguid")
json_accessor("attestationCertificateKeyIdentifiers")
json_accessor("description")
json_accessor("alternativeDescriptions")
json_accessor("authenticatorVersion")
json_accessor("protocolFamily", Coercer::AssumedValue.new("uaf"))
json_accessor("upv")
json_accessor("assertionScheme")
json_accessor("authenticationAlgorithm", Coercer::MagicNumber.new(Constants::AUTHENTICATION_ALGORITHMS))
json_accessor("authenticationAlgorithms",
Coercer::MagicNumber.new(Constants::AUTHENTICATION_ALGORITHMS, array: true))
json_accessor("publicKeyAlgAndEncoding", Coercer::MagicNumber.new(Constants::PUBLIC_KEY_FORMATS))
json_accessor("publicKeyAlgAndEncodings",
Coercer::MagicNumber.new(Constants::PUBLIC_KEY_FORMATS, array: true))
json_accessor("attestationTypes", Coercer::MagicNumber.new(Constants::ATTESTATION_TYPES, array: true))
json_accessor("userVerificationDetails", Coercer::UserVerificationDetails)
json_accessor("keyProtection", Coercer::BitField.new(Constants::KEY_PROTECTION_TYPES))
json_accessor("isKeyRestricted", Coercer::AssumedValue.new(true))
json_accessor("isFreshUserVerificationRequired", Coercer::AssumedValue.new(true))
json_accessor("matcherProtection",
Coercer::BitField.new(Constants::MATCHER_PROTECTION_TYPES, single_value: true))
json_accessor("cryptoStrength")
json_accessor("operatingEnv")
json_accessor("attachmentHint", Coercer::BitField.new(Constants::ATTACHMENT_HINTS))
json_accessor("isSecondFactorOnly")
json_accessor("tcDisplay", Coercer::BitField.new(Constants::TRANSACTION_CONFIRMATION_DISPLAY_TYPES))
json_accessor("tcDisplayContentType")
json_accessor("tcDisplayPNGCharacteristics")
json_accessor("attestationRootCertificates", Coercer::Certificates)
json_accessor("ecdaaTrustAnchors")
json_accessor("icon")
json_accessor("supportedExtensions")
end
end
end
22 changes: 22 additions & 0 deletions lib/webauthn/metadata/verification_method_descriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require "webauthn/metadata/attributes"
require "webauthn/metadata/biometric_accuracy_descriptor"
require "webauthn/metadata/constants"
require "webauthn/metadata/code_accuracy_descriptor"
require "webauthn/metadata/pattern_accuracy_descriptor"
require "webauthn/metadata/coercer/magic_number"
require "webauthn/metadata/coercer/objects"

module WebAuthn
module Metadata
class VerificationMethodDescriptor
extend Attributes

json_accessor("userVerification", Coercer::MagicNumber.new(Constants::USER_VERIFICATION_METHODS))
json_accessor("caDesc")
json_accessor("baDesc")
json_accessor("paDesc")
end
end
end
Loading

0 comments on commit ae0e21e

Please sign in to comment.