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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
# frozen_string_literal: true
require "cose/key"
require "cbor"
require "securerandom"
module WebAuthn
class FakeAuthenticator
class AuthenticatorData
AAGUID = SecureRandom.random_bytes(16)
attr_reader :sign_count
def initialize(
rp_id_hash:,
credential: {
id: SecureRandom.random_bytes(16),
public_key: OpenSSL::PKey::EC.generate("prime256v1").public_key
},
sign_count: 0,
user_present: true,
user_verified: !user_present,
aaguid: AAGUID,
extensions: { "fakeExtension" => "fakeExtensionValue" }
)
@rp_id_hash = rp_id_hash
@credential = credential
@sign_count = sign_count
@user_present = user_present
@user_verified = user_verified
@aaguid = aaguid
@extensions = extensions
end
def serialize
rp_id_hash + flags + serialized_sign_count + attested_credential_data + extension_data
end
private
attr_reader :rp_id_hash, :credential, :user_present, :user_verified, :extensions
def flags
[
[
bit(:user_present),
reserved_for_future_use_bit,
bit(:user_verified),
reserved_for_future_use_bit,
reserved_for_future_use_bit,
reserved_for_future_use_bit,
attested_credential_data_included_bit,
extension_data_included_bit
].join
].pack("b*")
end
def serialized_sign_count
[sign_count].pack('L>')
end
def attested_credential_data
@attested_credential_data ||=
if credential
@aaguid +
[credential[:id].length].pack("n*") +
credential[:id] +
cose_credential_public_key
else
""
end
end
def extension_data
if extensions
CBOR.encode(extensions)
else
""
end
end
def bit(flag)
if context[flag]
"1"
else
"0"
end
end
def attested_credential_data_included_bit
if attested_credential_data.empty?
"0"
else
"1"
end
end
def extension_data_included_bit
if extension_data.empty?
"0"
else
"1"
end
end
def reserved_for_future_use_bit
"0"
end
def context
{ user_present: user_present, user_verified: user_verified }
end
def cose_credential_public_key
case credential[:public_key]
when OpenSSL::PKey::RSA
key = COSE::Key::RSA.from_pkey(credential[:public_key])
key.alg = -257
when OpenSSL::PKey::EC::Point
alg = {
COSE::Key::Curve.by_name("P-256").id => -7,
COSE::Key::Curve.by_name("P-384").id => -35,
COSE::Key::Curve.by_name("P-521").id => -36
}
key = COSE::Key::EC2.from_pkey(credential[:public_key])
key.alg = alg[key.crv]
end
key.serialize
end
def key_bytes(public_key)
public_key.to_bn.to_s(2)
end
end
end
end
|