web_authn 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89d25f455fdd1323936c0c32072be162f888df15e7ddd86fb65549e9f37736fb
4
- data.tar.gz: ecb31a66853aeaca039da91aeb66ca5a24b5ee9f103153ed76ae6593fc1071ea
3
+ metadata.gz: 07b7a1b06a7ad5f04c3d303de0f8f099c0ce71038e78934268bf99243600d86c
4
+ data.tar.gz: 60a474a75148dff57396fc3e939fc94a83a58496ef95bca71f5a29747674651b
5
5
  SHA512:
6
- metadata.gz: dee33babaf79b1ba80f86321223206c56e59c7c3e5adc113bb8a4f51d8d9c185d5eb1b62219a408e98130265d75e9ee1fa648794d3db8f60ab32551cbd5c83bb
7
- data.tar.gz: 70fdbe9c79f25a5044eea4ac2b06815d6f5c128e0db61c03f930577cba78dc2d5e6fcf46324823fefa9dcefab2b76ccd648e3e769a12020f123f7f0d128b7798
6
+ metadata.gz: 5876b9449153f9309057f48632121f0302b3a7fb663d968b441a374b40c09f9b88447b64101d44e92c2b1be6287e2f11c0373b44ca2c2532aa96d1b658d7899d
7
+ data.tar.gz: b598691bcb6d42ef76f72ae650931d47888cf573f5ad45759d2d834c3174256f69521f9496a101caf206386d366b9f476efe99864100e8bc9ad78cee7d4be7ae
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -5,7 +5,7 @@ module WebAuthn
5
5
  alias_method :att_stmt, :attestation_statement
6
6
  alias_method :auth_data, :authenticator_data
7
7
 
8
- %i(credential_id rp_id_hash flags public_key sign_count).each do |method|
8
+ %i(credential_id rp_id_hash flags public_key public_cose_key sign_count).each do |method|
9
9
  delegate method, to: :authenticator_data
10
10
  end
11
11
 
@@ -1,11 +1,12 @@
1
1
  module WebAuthn
2
2
  class AttestedCredentialData
3
- attr_accessor :aaguid, :credential_id, :public_key
3
+ attr_accessor :aaguid, :credential_id, :public_key, :public_cose_key
4
4
 
5
- def initialize(aaguid:, credential_id:, public_key:)
5
+ def initialize(aaguid:, credential_id:, public_key:, public_cose_key:)
6
6
  self.aaguid = aaguid
7
7
  self.credential_id = credential_id
8
8
  self.public_key = public_key
9
+ self.public_cose_key = public_cose_key
9
10
  end
10
11
 
11
12
  class << self
@@ -21,10 +22,12 @@ module WebAuthn
21
22
  attested_credential_data.byteslice(18...(18 + length)),
22
23
  attested_credential_data.byteslice((18 + length)..-1),
23
24
  ]
25
+ cose_key = COSE::Key.decode(cose_key_cbor)
24
26
  new(
25
27
  aaguid: Base64.urlsafe_encode64(aaguid, padding: false),
26
28
  credential_id: Base64.urlsafe_encode64(credential_id, padding: false),
27
- public_key: COSE::Key.decode(cose_key_cbor).to_key
29
+ public_key: cose_key.to_key,
30
+ public_cose_key: cose_key
28
31
  )
29
32
  end
30
33
  end
@@ -2,7 +2,7 @@ module WebAuthn
2
2
  class AuthenticatorData
3
3
  attr_accessor :rp_id_hash, :flags, :sign_count, :attested_credential_data, :raw
4
4
 
5
- %i(credential_id public_key).each do |method|
5
+ %i(credential_id public_key public_cose_key).each do |method|
6
6
  delegate method, to: :attested_credential_data, allow_nil: true
7
7
  end
8
8
 
@@ -12,13 +12,17 @@ module WebAuthn
12
12
  true
13
13
  end
14
14
 
15
- def verify!(encoded_authenticator_data, public_key:, sign_count:, signature:)
15
+ def verify!(encoded_authenticator_data, sign_count:, signature:, public_key: nil, public_cose_key: nil, digest: OpenSSL::Digest::SHA256.new)
16
+ unless public_key || public_cose_key
17
+ raise ArgumentError, 'missing keyword: public_key or public_cose_key'
18
+ end
19
+
16
20
  self.authenticator_data = AuthenticatorData.decode(
17
21
  Base64.urlsafe_decode64 encoded_authenticator_data
18
22
  )
19
23
  verify_flags!
20
24
  verify_sign_count!(sign_count)
21
- verify_signature!(public_key, signature)
25
+ verify_signature!(public_key, public_cose_key, signature, digest)
22
26
  self
23
27
  end
24
28
 
@@ -39,16 +43,23 @@ module WebAuthn
39
43
  end
40
44
  end
41
45
 
42
- def verify_signature!(public_key, signature)
43
- # TODO:
44
- # needs to handle digest size based on COSE key algorithm.
45
- # how to get COSE key alg header at this point?
46
+ def verify_signature!(public_key, public_cose_key, signature, digest)
46
47
  signature_base_string = [
47
48
  authenticator_data.raw,
48
49
  OpenSSL::Digest::SHA256.digest(client_data_json.raw)
49
50
  ].join
50
- result = public_key.verify(
51
- OpenSSL::Digest::SHA256.new,
51
+ if public_cose_key
52
+ public_key, digest = [public_cose_key, public_cose_key.digest]
53
+ end
54
+ verification_method = case public_key
55
+ when OpenSSL::PKey::RSA
56
+ :verify_pss
57
+ when OpenSSL::PKey::EC
58
+ :verify
59
+ end
60
+ result = public_key.send(
61
+ verification_method,
62
+ digest,
52
63
  Base64.urlsafe_decode64(signature),
53
64
  signature_base_string
54
65
  )
@@ -4,7 +4,7 @@ module WebAuthn
4
4
  attr_accessor :attestation_object
5
5
 
6
6
  # TODO: will need more methods, or let developers access deep methods by themselves.
7
- %i(credential_id rp_id_hash flags public_key sign_count).each do |method|
7
+ %i(credential_id rp_id_hash flags public_key public_cose_key sign_count).each do |method|
8
8
  delegate method, to: :attestation_object
9
9
  end
10
10
 
@@ -30,7 +30,12 @@ raise unless context.authentication?
30
30
 
31
31
  context.verify!(
32
32
  authenticator_data,
33
+ # NOTE:
34
+ # either 'public_key' or 'public_cose_key' is required.
35
+ # if `public_key` is given, you can also specify `digest` (default: `OpenSSL::Digest::SHA256.new`).
36
+ # if `public_cose_key` is given, it includes digest size information, so no `digest` is required.
33
37
  public_key: public_key,
38
+ # public_cose_key: public_cose_key,
34
39
  sign_count: sign_count,
35
40
  signature: signature
36
41
  )
@@ -36,6 +36,9 @@ ex: #{context.flags.ex}
36
36
  # Public Key
37
37
  #{context.public_key.to_pem}
38
38
 
39
+ # Public COSE Key
40
+ #{context.public_cose_key.raw}
41
+
39
42
  # Sign Count
40
43
  #{context.sign_count}
41
44
  OUT
@@ -38,6 +38,7 @@ RSpec.describe WebAuthn::Context::Registration do
38
38
  its(:rp_id_hash) { should == rp_id_hash }
39
39
  its(:flags) { should == flags }
40
40
  its(:public_key) { should be_instance_of OpenSSL::PKey::EC }
41
+ its(:public_cose_key) { should be_instance_of COSE::Key::EC2 }
41
42
  its(:public_key_pem) do
42
43
  subject.public_key.to_pem.should == public_key_pem
43
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_authn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nov matake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-08 00:00:00.000000000 Z
11
+ date: 2018-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport