class U2F::FakeU2F
Constants
- CURVE_NAME
Attributes
Public Class Methods
Initialize a new FakeU2F
device for use in tests.
app_id
- The appId/origin this is being tested against. options - A Hash of optional parameters (optional).
:counter - The initial counter for this device. :key_handle - The raw key-handle this device should use. :cert_subject - The subject field for the certificate generated for this device.
Returns nothing.
# File lib/u2f/fake_u2f.rb, line 16 def initialize(app_id, options = {}) @app_id = app_id @counter = options.fetch(:counter, 0) @key_handle_raw = options.fetch(:key_handle, SecureRandom.random_bytes(32)) @cert_subject = options.fetch(:cert_subject, "/CN=U2FTest") end
Public Instance Methods
The raw device attestation certificate as returned in the registrationData field of a RegisterResponse Hash.
Returns a DER formatted certificate String.
# File lib/u2f/fake_u2f.rb, line 67 def cert_raw cert.to_der end
The appId specific public key as returned in the registrationData field of a RegisterResponse Hash.
Returns a binary formatted EC public key String.
# File lib/u2f/fake_u2f.rb, line 59 def origin_public_key_raw [origin_key.public_key.to_bn.to_s(16)].pack('H*') end
A registerResponse hash as returned by the u2f.register JavaScript API.
challenge - The challenge to sign. error - Boolean. Whether to return an error response (optional).
Returns a JSON encoded Hash String.
# File lib/u2f/fake_u2f.rb, line 29 def register_response(challenge, error = false) if error JSON.dump(:errorCode => 4) else client_data_json = client_data(U2F::ClientData::REGISTRATION_TYP, challenge) JSON.dump( :registrationData => reg_registration_data(client_data_json), :clientData => U2F.urlsafe_encode64(client_data_json) ) end end
A SignResponse hash as returned by the u2f.sign JavaScript API.
challenge - The challenge to sign.
Returns a JSON encoded Hash String.
# File lib/u2f/fake_u2f.rb, line 46 def sign_response(challenge) client_data_json = client_data(U2F::ClientData::AUTHENTICATION_TYP, challenge) JSON.dump( :clientData => U2F.urlsafe_encode64(client_data_json), :keyHandle => U2F.urlsafe_encode64(key_handle_raw), :signatureData => auth_signature_data(client_data_json) ) end
Private Instance Methods
The signature field of a signatureData field of a SignResponse Hash.
client_data_json - The JSON encoded clientData String.
Returns an ECDSA signature String.
# File lib/u2f/fake_u2f.rb, line 127 def auth_signature(client_data_json) data = [ U2F::DIGEST.digest(app_id), 1, # User present counter, U2F::DIGEST.digest(client_data_json) ].pack("A32CNA32") origin_key.sign(U2F::DIGEST.new, data) end
The signatureData field of a SignResponse Hash.
client_data_json - The JSON encoded clientData String.
Returns a url-safe base64 encoded binary String.
# File lib/u2f/fake_u2f.rb, line 112 def auth_signature_data(client_data_json) ::U2F.urlsafe_encode64( [ 1, # User present self.counter += 1, auth_signature(client_data_json) ].pack("CNA*") ) end
The self-signed device attestation certificate.
Returns a OpenSSL::X509::Certificate instance.
# File lib/u2f/fake_u2f.rb, line 163 def cert @cert ||= OpenSSL::X509::Certificate.new.tap do |c| c.subject = c.issuer = OpenSSL::X509::Name.parse(cert_subject) c.not_before = Time.now c.not_after = Time.now + 365 * 24 * 60 * 60 c.public_key = cert_key c.serial = 0x1 c.version = 0x0 c.sign cert_key, U2F::DIGEST.new end end
The public key used for signing the device certificate.
Returns a OpenSSL::PKey::EC instance.
# File lib/u2f/fake_u2f.rb, line 178 def cert_key @cert_key ||= generate_ec_key end
The clientData hash as returned by registration and authentication responses.
typ - The String value for the 'typ' field. challenge - The String url-safe base64 encoded challenge parameter.
Returns a JSON encoded Hash String.
# File lib/u2f/fake_u2f.rb, line 145 def client_data(typ, challenge) JSON.dump( :challenge => challenge, :origin => app_id, :typ => typ ) end
Generate an eliptic curve public/private key.
Returns a OpenSSL::PKey::EC instance.
# File lib/u2f/fake_u2f.rb, line 185 def generate_ec_key OpenSSL::PKey::EC.new().tap do |ec| ec.group = OpenSSL::PKey::EC::Group.new(CURVE_NAME) ec.generate_key # https://bugs.ruby-lang.org/issues/8177 ec.define_singleton_method(:private?) { private_key? } ec.define_singleton_method(:public?) { public_key? } end end
The appId-specific public/private key.
Returns a OpenSSL::PKey::EC instance.
# File lib/u2f/fake_u2f.rb, line 156 def origin_key @origin_key ||= generate_ec_key end
The registrationData field returns in a RegisterResponse Hash.
client_data_json - The JSON encoded clientData String.
Returns a url-safe base64 encoded binary String.
# File lib/u2f/fake_u2f.rb, line 78 def reg_registration_data(client_data_json) U2F.urlsafe_encode64( [ 5, origin_public_key_raw, key_handle_raw.bytesize, key_handle_raw, cert_raw, reg_signature(client_data_json) ].pack("CA65CA#{key_handle_raw.bytesize}A#{cert_raw.bytesize}A*") ) end
The signature field of a registrationData field of a RegisterResponse.
client_data_json - The JSON encoded clientData String.
Returns an ECDSA signature String.
# File lib/u2f/fake_u2f.rb, line 96 def reg_signature(client_data_json) payload = [ "\x00", U2F::DIGEST.digest(app_id), U2F::DIGEST.digest(client_data_json), key_handle_raw, origin_public_key_raw ].join cert_key.sign(U2F::DIGEST.new, payload) end