simplicity_client 0.2.0 → 0.2.1

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fido2_client.rb +91 -0
  3. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35ccb4c05970e3765687119f1761b0c1ff47965ab6311f5e86e5fb321b8e87fd
4
- data.tar.gz: dfc4d51cf8d179a2901c62aaa576828193ddf6ef87a9aba6793da75da6825737
3
+ metadata.gz: 3283578b786c0a520eeaee6b46290f1459e9075925f8fdf172534ac533270e33
4
+ data.tar.gz: cee5f3f5ac077c4cea0bc246d7f1a4b2ea03a23db7ad21795485730685ba3959
5
5
  SHA512:
6
- metadata.gz: 6ef0ea4b00d2ae9ae5deaaf317759fe595e7221fbfe46175c48747355e388ab4faaf4f0b272ccd6c57ec7c11fc7f06037dd35b6f9e76998c8258d36a6c406dfb
7
- data.tar.gz: 6c7618d98c48fc47adfa19931cb68a1fe67d612cc17e1e51c0a6cfdd7d708cffedf7dffd3ff96e425a890990c2b56d629541184edb033de49e2634d49f1e5be4
6
+ metadata.gz: 2ddd8ee90c05b00ba4ed232846f5c2e546e087c93c7e2c3a58965c74480640fe04823bea6d94c9b3b0f58e64f41cd738b8b157420b71d5864846cb74e0600185
7
+ data.tar.gz: fbf5d020b63bae7fd804154b34513d95e9991afa39023877905072e69df66879b4afd3e7028251204e314720c4ca472860dc9e81d86d4a90e521202791dd7bbe
@@ -0,0 +1,91 @@
1
+ require "json"
2
+ require "digest"
3
+ require "openssl"
4
+ require "base64"
5
+
6
+ module Fido2Client
7
+ Passkey = Data.define(:credentialId, :keyAlgorithm, :keyCurve, :keyValue, :userHandle)
8
+ Assertion = Data.define(:authenticator_data, :client_data_json, :credential_id, :user_handle, :signature)
9
+
10
+ class Client
11
+ def initialize
12
+ @origin = "https://app.simplicity.kiwi"
13
+ @rp_id = "simplicity.kiwi"
14
+ end
15
+
16
+ def get_assertion(passkey, challenge)
17
+ collected_client_data = {
18
+ type: "webauthn.get",
19
+ challenge: challenge,
20
+ origin: @origin,
21
+ crossOrigin: false,
22
+ }
23
+ client_data_json = JSON.dump(collected_client_data)
24
+ client_data_hash = Digest::SHA256.digest(client_data_json)
25
+
26
+ # Assertion
27
+ auth_data = generate_auth_data
28
+ private_key = parse_private_key(passkey.keyAlgorithm, passkey.keyCurve, passkey.keyValue)
29
+ signature = generate_signature(auth_data, client_data_hash, private_key)
30
+
31
+ Assertion.new(
32
+ authenticator_data: Base64.urlsafe_encode64(auth_data.pack("c*"), padding: false),
33
+ client_data_json: Base64.urlsafe_encode64(client_data_json, padding: false),
34
+ credential_id: Base64.urlsafe_encode64(guid_to_raw_format(passkey.credentialId), padding: false),
35
+ user_handle: passkey.userHandle,
36
+ signature: Base64.urlsafe_encode64(signature, padding: false),
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def box(tag, lines)
43
+ lines.unshift "-----BEGIN #{tag}-----"
44
+ lines.push "-----END #{tag}-----"
45
+ lines.join("\n")
46
+ end
47
+
48
+ def der_to_pem(tag, der)
49
+ box tag, Base64.strict_encode64(der).scan(/.{1,64}/)
50
+ end
51
+
52
+ def parse_private_key(key_algorithm, key_curve, key_value)
53
+ raise "Unsupported key algorithm: #{key_algorithm}" unless key_algorithm == "ECDSA"
54
+ raise "Unsupported key curve: #{key_curve}" unless key_curve == "P-256"
55
+
56
+ # Decode the Base64 key value
57
+ key_value_bin = Base64.urlsafe_decode64(key_value)
58
+
59
+ pem = der_to_pem("PRIVATE KEY", key_value_bin)
60
+ OpenSSL::PKey::EC.new(pem)
61
+ end
62
+
63
+ def generate_signature(auth_data, client_data_hash, private_key)
64
+ sig_base = [*auth_data, *client_data_hash.bytes]
65
+ digest = OpenSSL::Digest.new("SHA256")
66
+ private_key.sign(digest, sig_base.pack("c*"))
67
+ end
68
+
69
+ def generate_auth_data
70
+ auth_data = []
71
+ rp_id_hash = Digest::SHA256.digest(@rp_id)
72
+ auth_data += rp_id_hash.bytes
73
+
74
+ # Flags asserted: Backup eligibility, Backup State, User Verification, User Presence
75
+ flags = 0x1D
76
+ auth_data.push(flags)
77
+
78
+ # Counter
79
+ auth_data += [0, 0, 0, 0]
80
+
81
+ auth_data
82
+ end
83
+
84
+ def guid_to_raw_format(guid)
85
+ raise TypeError, "GUID parameter is invalid" unless guid.match?(/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/)
86
+
87
+ # Remove the hyphens and pack the string into raw binary
88
+ [guid.delete("-")].pack("H*")
89
+ end
90
+ end
91
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplicity_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Dewar
@@ -101,6 +101,7 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - lib/fido2_client.rb
104
105
  - lib/simplicity_client.rb
105
106
  homepage: https://github.com/GeorgeDewar/simplicity_client
106
107
  licenses: