Class: SafetyNetAttestation::Statement

Inherits:
Object
  • Object
show all
Defined in:
lib/safety_net_attestation/statement.rb

Constant Summary collapse

GOOGLE_ROOT_CERTIFICATES =
Dir.glob(
  File.join(SafetyNetAttestation::GEM_ROOT, "safety_net_attestation", "certificates", "*.*")
).map do |path|
  file = File.binread(path)
  OpenSSL::X509::Certificate.new(file)
end.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(jws_result) ⇒ Statement

Returns a new instance of Statement.



23
24
25
# File 'lib/safety_net_attestation/statement.rb', line 23

def initialize(jws_result)
  @jws_result = jws_result
end

Instance Attribute Details

#jsonObject (readonly)

Returns the value of attribute json.



21
22
23
# File 'lib/safety_net_attestation/statement.rb', line 21

def json
  @json
end

Instance Method Details

#adviceObject

Raises:



77
78
79
80
81
# File 'lib/safety_net_attestation/statement.rb', line 77

def advice
  raise NotVerifiedError unless json

  json["advice"]&.split(",")
end

#apk_certificate_digest_sha256Object

Raises:



65
66
67
68
69
# File 'lib/safety_net_attestation/statement.rb', line 65

def apk_certificate_digest_sha256
  raise NotVerifiedError unless json

  json["apkCertificateDigestSha256"]
end

#apk_package_nameObject

Raises:



59
60
61
62
63
# File 'lib/safety_net_attestation/statement.rb', line 59

def apk_package_name
  raise NotVerifiedError unless json

  json["apkPackageName"]
end

#basic_integrity?Boolean

Returns:

  • (Boolean)

Raises:



53
54
55
56
57
# File 'lib/safety_net_attestation/statement.rb', line 53

def basic_integrity?
  raise NotVerifiedError unless json

  json["basicIntegrity"]
end

#certificate_chainObject

Raises:



83
84
85
86
87
# File 'lib/safety_net_attestation/statement.rb', line 83

def certificate_chain
  raise NotVerifiedError unless json

  @certificate_chain
end

#cts_profile_match?Boolean

Returns:

  • (Boolean)

Raises:



47
48
49
50
51
# File 'lib/safety_net_attestation/statement.rb', line 47

def cts_profile_match?
  raise NotVerifiedError unless json

  json["ctsProfileMatch"]
end

#errorObject

Raises:



71
72
73
74
75
# 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) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 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