safety_net_attestation 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c755feae396958cb6524bbfa08481ee56eeb51c882a517f5c460996d49b5623
4
- data.tar.gz: 61185703482ff164ec66d09717b842e68284f7593f65b6130e11383b79134950
3
+ metadata.gz: 6ccbadd15213737c97c7380d54fbf0b742f33aec05897ae6e7c2f51fe114f487
4
+ data.tar.gz: e0fe5abd1f16f7b084b53431108defbc1d534d8061ec7d0363674b0ad207fd08
5
5
  SHA512:
6
- metadata.gz: 5244cb19acd724bdd9f769ba608a7554b3bdef8df761d8d56715bb1fc8556510c39d465a895d54a0fae5603e2ca20f26e454ac194555a893c021ede762e49f63
7
- data.tar.gz: afd1d3e03b7faedce4f68b9450e182fc4beb54ca7737773b313c6146b55d401387e7d8064e838fe657b30995b3e0c586b7681ecb96f55c5f1ee7c858ffa6b2fb
6
+ metadata.gz: d2f0413cb1b611f2bb0319da23002edb5f695119badb401fdef6af4e225e9a5cd778af31e0cf4af4ab228fca8c322763eb806d35ef21fa29cd7080edddbc318c
7
+ data.tar.gz: 6327628183000d2110361284af325cc210f7d45da9af7da755cde2b108e9ac4858e40b6028b71f46c864be58b3bb72736dab8a5cf0bdc1f1a6235745f44b187b
data/.travis.yml CHANGED
@@ -6,6 +6,8 @@ rvm:
6
6
  - 2.5.7
7
7
  - 2.4.9
8
8
  - 2.3.8
9
+ before_install:
10
+ - gem install bundler
9
11
  script:
10
12
  - bin/rspec
11
13
  jobs:
data/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2019-12-29
10
+ ### Added
11
+ - `Statement#certificates` exposes the certificate chain used during verification
12
+ - `Statement#verify` takes an optional `time` argument, defaulting to the current time. This can be used for testing
13
+ captured statements from real devices without needing stubbing.
14
+
9
15
  ## [0.2.0] - 2019-12-28
10
16
  ### Fixed
11
17
  - Fixed loading bundled root certificates
@@ -14,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
14
20
  ### Added
15
21
  - Extracted from [webauthn-ruby](https://github.com/cedarcode/webauthn-ruby) after discussion with the maintainers. Thanks for the feedback @grzuy and @brauliomartinezlm!
16
22
 
17
- [Unreleased]: https://github.com/bdewater/fido_metadata/compare/v0.1.0...HEAD
18
- [0.2.0]: https://github.com/bdewater/fido_metadata/compare/v0.1.0...v0.2.0
19
- [0.1.0]: https://github.com/bdewater/fido_metadata/releases/tag/v0.1.0
23
+ [Unreleased]: https://github.com/bdewater/safety_net_attestation/compare/v0.1.0...HEAD
24
+ [0.3.0]: https://github.com/bdewater/safety_net_attestation/compare/v0.2.0...v0.3.0
25
+ [0.2.0]: https://github.com/bdewater/safety_net_attestation/compare/v0.1.0...v0.2.0
26
+ [0.1.0]: https://github.com/bdewater/safety_net_attestation/releases/tag/v0.1.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- safety_net_attestation (0.2.0)
4
+ safety_net_attestation (0.3.0)
5
5
  jwt (~> 2.0)
6
6
 
7
7
  GEM
@@ -24,21 +24,23 @@ module SafetyNetAttestation
24
24
  @jws_result = jws_result
25
25
  end
26
26
 
27
- def verify(nonce, timestamp_leeway: 60, trusted_certificates: GOOGLE_ROOT_CERTIFICATES)
27
+ def verify(nonce, timestamp_leeway: 60, trusted_certificates: GOOGLE_ROOT_CERTIFICATES, time: Time.now)
28
28
  certificates = nil
29
29
  response, _ = JWT.decode(@jws_result, nil, true, algorithms: ["ES256", "RS256"]) do |headers|
30
- certificates = headers["x5c"].map do |encoded|
30
+ x5c_certificates = headers["x5c"].map do |encoded|
31
31
  OpenSSL::X509::Certificate.new(Base64.strict_decode64(encoded))
32
32
  end
33
33
 
34
- X5cKeyFinder.from(certificates, trusted_certificates)
34
+ certificates = X5cKeyFinder.from(x5c_certificates, trusted_certificates, time: time)
35
+ certificates.first.public_key
35
36
  end
36
37
 
37
38
  verify_certificate_subject(certificates.first)
38
39
  verify_nonce(response, nonce)
39
- verify_timestamp(response, timestamp_leeway)
40
+ verify_timestamp(response, timestamp_leeway, time)
40
41
 
41
42
  @json = response
43
+ @certificates = certificates
42
44
  self
43
45
  end
44
46
 
@@ -78,6 +80,12 @@ module SafetyNetAttestation
78
80
  json["advice"]&.split(",")
79
81
  end
80
82
 
83
+ def certificates
84
+ raise NotVerifiedError unless json
85
+
86
+ @certificates
87
+ end
88
+
81
89
  private
82
90
 
83
91
  def verify_certificate_subject(certificate)
@@ -94,8 +102,8 @@ module SafetyNetAttestation
94
102
  end
95
103
  end
96
104
 
97
- def verify_timestamp(response, leeway)
98
- now = Time.now.to_f
105
+ def verify_timestamp(response, leeway, time)
106
+ now = time.to_f
99
107
  response_time = response["timestampMs"] / 1000.0
100
108
  unless response_time.between?(now - leeway, now + leeway)
101
109
  raise TimestampError, "not within #{leeway}s leeway"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SafetyNetAttestation
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -7,15 +7,16 @@ module SafetyNetAttestation
7
7
  class SignatureError < Error; end
8
8
 
9
9
  class X5cKeyFinder
10
- def self.from(x5c_certificates, trusted_certificates)
10
+ def self.from(x5c_certificates, trusted_certificates, time: Time.now)
11
11
  store = OpenSSL::X509::Store.new
12
12
  trusted_certificates.each { |certificate| store.add_cert(certificate) }
13
13
 
14
14
  signing_certificate, *certificate_chain = x5c_certificates
15
15
  store_context = OpenSSL::X509::StoreContext.new(store, signing_certificate, certificate_chain)
16
+ store_context.time = time
16
17
 
17
18
  if store_context.verify
18
- signing_certificate.public_key
19
+ store_context.chain
19
20
  else
20
21
  error = "Certificate verification failed: #{store_context.error_string}."
21
22
  error = "#{error} Certificate subject: #{store_context.current_cert.subject}." if store_context.current_cert
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safety_net_attestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart de Water