class WebAuthn::AttestationStatement::AndroidSafetynet
Attributes
certs[RW]
response[RW]
ver[RW]
Public Class Methods
new(ver:, response:)
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 6 def initialize(ver:, response:) self.ver = ver self.response = response self.certs = response.x5c.collect do |x5c| OpenSSL::X509::Certificate.new( Base64.decode64 x5c ) end end
Private Class Methods
decode(att_stmt)
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 71 def decode(att_stmt) new( ver: att_stmt[:ver], response: JSON::JWT.decode(att_stmt[:response], :skip_verification) ) end
Public Instance Methods
verify!(authenticator_data, client_data_json)
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 16 def verify!(authenticator_data, client_data_json) verify_nonce! authenticator_data, client_data_json verify_signature! verify_certificate! unless response[:ctsProfileMatch] raise InvalidAttestation, 'Invalid Android Safetynet Response: ctsProfileMatch' end end
Private Instance Methods
verify_certificate!()
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 46 def verify_certificate! signing_cert = certs.first remaining_chain = certs[1..-1] store = OpenSSL::X509::Store.new store.set_default_paths valid_chain = store.verify(signing_cert, remaining_chain) valid_subject = signing_cert.subject.to_a.detect do |key, value, type| key == 'CN' end.second == 'attest.android.com' valid_timestamp = ( signing_cert.not_after > Time.now && signing_cert.not_before < Time.now ) # TODO: do we need CRL check? unless valid_chain && valid_subject && valid_timestamp raise InvalidAttestation, 'Invalid Android Safetynet Response: certificate' end end
verify_nonce!(authenticator_data, client_data_json)
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 28 def verify_nonce!(authenticator_data, client_data_json) nonce = Base64.encode64( OpenSSL::Digest::SHA256.digest [ authenticator_data.raw, OpenSSL::Digest::SHA256.digest(client_data_json.raw) ].join ).strip unless response[:nonce] == nonce raise InvalidAttestation, 'Invalid Android Safetynet Response: nonce' end end
verify_signature!()
click to toggle source
# File lib/web_authn/attestation_statement/android_safetynet.rb, line 40 def verify_signature! response.verify! certs.first.public_key rescue JSON::JWS::VerificationFailed => e raise InvalidAttestation, 'Invalid Android Safetynet Response: signature' end