class SafetyNetAttestation::Statement
Constants
- GOOGLE_ROOT_CERTIFICATES
Attributes
json[R]
Public Class Methods
new(jws_result)
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 23 def initialize(jws_result) @jws_result = jws_result end
Public Instance Methods
advice()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 77 def advice raise NotVerifiedError unless json json["advice"]&.split(",") end
apk_certificate_digest_sha256()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 65 def apk_certificate_digest_sha256 raise NotVerifiedError unless json json["apkCertificateDigestSha256"] end
apk_package_name()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 59 def apk_package_name raise NotVerifiedError unless json json["apkPackageName"] end
basic_integrity?()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 53 def basic_integrity? raise NotVerifiedError unless json json["basicIntegrity"] end
certificate_chain()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 83 def certificate_chain raise NotVerifiedError unless json @certificate_chain end
cts_profile_match?()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 47 def cts_profile_match? raise NotVerifiedError unless json json["ctsProfileMatch"] end
error()
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 71 def error raise NotVerifiedError unless json json["error"] end
verify(nonce, timestamp_leeway: 60, trusted_certificates: GOOGLE_ROOT_CERTIFICATES, time: Time.now)
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 27 def verify(nonce, timestamp_leeway: 60, trusted_certificates: GOOGLE_ROOT_CERTIFICATES, time: Time.now) certificate_chain = nil response, _ = JWT.decode(@jws_result, nil, true, algorithms: ["ES256", "RS256"]) do |headers| x5c_certificates = headers["x5c"].map do |encoded| OpenSSL::X509::Certificate.new(Base64.strict_decode64(encoded)) end certificate_chain = X5cKeyFinder.from(x5c_certificates, trusted_certificates, time: time) certificate_chain.first.public_key end verify_certificate_subject(certificate_chain.first) verify_nonce(response, nonce) verify_timestamp(response, timestamp_leeway, time) @json = response @certificate_chain = certificate_chain self end
Private Instance Methods
verify_certificate_subject(certificate)
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 91 def verify_certificate_subject(certificate) common_name = certificate.subject.to_a.assoc("CN") unless common_name[1] == "attest.android.com" raise CertificateSubjectError end end
verify_nonce(response, nonce)
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 99 def verify_nonce(response, nonce) unless OpenSSL.fixed_length_secure_compare(nonce, response["nonce"]) raise NonceMismatchError end end
verify_timestamp(response, leeway, time)
click to toggle source
# File lib/safety_net_attestation/statement.rb, line 105 def verify_timestamp(response, leeway, time) now = time.to_f response_time = response["timestampMs"] / 1000.0 unless response_time.between?(now - leeway, now + leeway) raise TimestampError, "not within #{leeway}s leeway" end end