web_authn 0.3.0 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ba07fe60ce73457f0f61ddc7c53dbf2b07886d93
4
- data.tar.gz: a9d76ab96805dd91c619551c09e0701a2a7b0795
2
+ SHA256:
3
+ metadata.gz: ed4c84df02f2d9399a21ea886d8b2850ed5ba1f68a6aee3d1f97aba2978ccf05
4
+ data.tar.gz: ea5b30178c0b070324f99be63a7ecdfc617fd2453319333abae3bf443c16dc3f
5
5
  SHA512:
6
- metadata.gz: 4550a5b91a35c2c5e302b58072b2a063b203370a8128d03cc851d7866e8f6bee92eab6d86dda0a41dcc366b47f9c86bfc9a0eef1e6f4a7df24bba18bbf61e32f
7
- data.tar.gz: 5aa59a73d18cfd24b6bd86431676c4c570ee6e5ff0e7af5c83fc70767a134ec87a577d1a7ebe0aab187dd92d9e467987b0e0adb085fe244aa57be6d4ac6f9849
6
+ metadata.gz: c3d70d2a36b1a5dd0c5f2ea27379593f195a130d5a09f2a667c2bcf7be619639794cddf36432e7c51aea0fed9d41cc148d4572b120aa12fd0f85fe0b82a1955c
7
+ data.tar.gz: d855274d4a256b9b0b50f3be4b8296be7be9c3b35056be6ab45f8bb3fb6989111c95eef0a47825b766e794e588a573e91a8cfb49c2d53b5cf853080fc503aa25
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.6.1
@@ -16,7 +16,11 @@ module WebAuthn
16
16
  nil
17
17
  when 'android-safetynet'
18
18
  AttestationStatement::AndroidSafetynet.decode att_stmt
19
- when 'packed', 'tpm', 'android-key', 'fido-u2f'
19
+ when 'packed'
20
+ AttestationStatement::Packed.decode att_stmt
21
+ when 'apple'
22
+ AttestationStatement::Apple.decode att_stmt
23
+ when 'tpm', 'android-key', 'fido-u2f'
20
24
  raise NotImplementedError, "Unsupported Attestation Format: #{format}"
21
25
  else
22
26
  raise InvalidContext, 'Unknown Attestation Format'
@@ -4,3 +4,5 @@ module WebAuthn
4
4
  end
5
5
 
6
6
  require 'web_authn/attestation_statement/android_safetynet'
7
+ require 'web_authn/attestation_statement/apple'
8
+ require 'web_authn/attestation_statement/packed'
@@ -18,7 +18,6 @@ module WebAuthn
18
18
  verify_signature!
19
19
  verify_certificate!
20
20
 
21
- # TODO: put more ref.) https://www.w3.org/TR/webauthn/#android-safetynet-attestation
22
21
  unless response[:ctsProfileMatch]
23
22
  raise InvalidAttestation, 'Invalid Android Safetynet Response: ctsProfileMatch'
24
23
  end
@@ -0,0 +1,86 @@
1
+ module WebAuthn
2
+ class AttestationStatement
3
+ class Apple < AttestationStatement
4
+ CERTIFICATE_EXTENSION_OID = '1.2.840.113635.100.8.2'
5
+ ROOT_CERTIFICATE = <<~PEM
6
+ -----BEGIN CERTIFICATE-----
7
+ MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
8
+ HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
9
+ bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
10
+ NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
11
+ A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
12
+ AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
13
+ xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
14
+ pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
15
+ 2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
16
+ MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
17
+ jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
18
+ 1bWeT0vT
19
+ -----END CERTIFICATE-----
20
+ PEM
21
+
22
+ attr_accessor :x5c, :certs
23
+
24
+ def initialize(x5c:)
25
+ self.x5c = Array(x5c)
26
+ self.certs = self.x5c.collect do |x5c|
27
+ OpenSSL::X509::Certificate.new x5c
28
+ end
29
+ end
30
+
31
+ def verify!(authenticator_data, client_data_json)
32
+ verify_nonce! authenticator_data, client_data_json
33
+ verify_certificate! authenticator_data.attested_credential_data
34
+ end
35
+
36
+ private
37
+
38
+ def verify_nonce!(authenticator_data, client_data_json)
39
+ nonce = OpenSSL::Digest::SHA256.digest [
40
+ authenticator_data.raw,
41
+ OpenSSL::Digest::SHA256.digest(client_data_json.raw)
42
+ ].join
43
+
44
+ extension = certs.first.find_extension(CERTIFICATE_EXTENSION_OID)
45
+ expected_nonce = OpenSSL::ASN1.decode(extension.value_der).first.value.first.value
46
+
47
+ unless expected_nonce == nonce
48
+ raise InvalidAttestation, 'Invalid Apple Response: nonce'
49
+ end
50
+ end
51
+
52
+ def verify_certificate!(attested_credential_data)
53
+ attested_cert = certs.first
54
+ remaining_chain = certs[1..-1]
55
+
56
+ store = OpenSSL::X509::Store.new
57
+ store.add_cert OpenSSL::X509::Certificate.new ROOT_CERTIFICATE
58
+ valid_chain = store.verify(attested_cert, remaining_chain)
59
+
60
+ valid_timestamp = (
61
+ attested_cert.not_after > Time.now &&
62
+ attested_cert.not_before < Time.now
63
+ )
64
+
65
+ valid_attested_public_key = (
66
+ attested_credential_data.public_key.to_pem ==
67
+ attested_cert.public_key.to_pem
68
+ )
69
+
70
+ # TODO: do we need CRL check?
71
+
72
+ unless valid_chain && valid_attested_public_key && valid_timestamp
73
+ raise InvalidAttestation, 'Invalid Apple Response: certificate'
74
+ end
75
+ end
76
+
77
+ class << self
78
+ def decode(att_stmt)
79
+ new(
80
+ x5c: att_stmt[:x5c]
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,71 @@
1
+ module WebAuthn
2
+ class AttestationStatement
3
+ class Packed < AttestationStatement
4
+ attr_accessor :alg, :sig, :x5c, :ecdaa_key_id
5
+
6
+ def initialize(alg:, sig:, x5c:, ecdaa_key_id:)
7
+ self.alg = alg
8
+ self.sig = sig
9
+ self.x5c = Array(x5c)
10
+ self.ecdaa_key_id = ecdaa_key_id
11
+ end
12
+
13
+ def verify!(authenticator_data, client_data_json)
14
+ verify_signature! authenticator_data, client_data_json
15
+ verify_certificate! unless self_issued?
16
+ end
17
+
18
+ private
19
+
20
+ def self_issued?
21
+ [x5c, ecdaa_key_id].all?(&:blank?)
22
+ end
23
+
24
+ def verify_signature!(authenticator_data, client_data_json)
25
+ signature_base_string = [
26
+ authenticator_data.raw,
27
+ OpenSSL::Digest::SHA256.digest(client_data_json.raw)
28
+ ].join
29
+
30
+ if self_issued? && authenticator_data.attested_credential_data.anonymous?
31
+ public_cose_key = authenticator_data.attested_credential_data.public_cose_key
32
+ unless alg == public_cose_key.alg
33
+ raise InvalidAttestation, 'Invalid Packed Self Attestation: alg'
34
+ end
35
+ unless public_cose_key.verify sig, signature_base_string
36
+ raise InvalidAttestation, 'Invalid Packed Self Attestation: signature'
37
+ end
38
+ else
39
+ attestation_certificate = OpenSSL::X509::Certificate.new x5c.first
40
+ public_key = attestation_certificate.public_key
41
+ digest = case public_key
42
+ when OpenSSL::PKey::EC
43
+ COSE::Key::EC2
44
+ when OpenSSL::PKey::RSA
45
+ COSE::Key::RSA
46
+ end.new.tap do |k|
47
+ k.alg = alg
48
+ end.digest
49
+ unless public_key.verify digest, sig, signature_base_string
50
+ raise InvalidAttestation, 'Invalid Packed Attestation: signature'
51
+ end
52
+ end
53
+ end
54
+
55
+ def verify_certificate!
56
+ raise NotImplementedError, 'Certificate Chain Verification Not Implemented Yet: packed'
57
+ end
58
+
59
+ class << self
60
+ def decode(att_stmt)
61
+ new(
62
+ alg: att_stmt[:alg],
63
+ sig: att_stmt[:sig],
64
+ x5c: att_stmt[:x5c],
65
+ ecdaa_key_id: att_stmt[:ecdaaKeyId]
66
+ )
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -9,6 +9,10 @@ module WebAuthn
9
9
  self.public_cose_key = public_cose_key
10
10
  end
11
11
 
12
+ def anonymous?
13
+ aaguid == 'AAAAAAAAAAAAAAAAAAAAAA' # NOTE: equals to `Base64.urlsafe_encode64("\0" * 16, padding: false)``
14
+ end
15
+
12
16
  class << self
13
17
  def decode(attested_credential_data)
14
18
  length = (
@@ -44,6 +44,59 @@ RSpec.describe WebAuthn::Context::Registration do
44
44
  end
45
45
  its(:sign_count) { should == sign_count }
46
46
 
47
+ context 'when packed attestation given' do
48
+ let(:context) do
49
+ {
50
+ origin: 'https://web-authn.self-issued.app',
51
+ challenge: 'random-string-generated-by-rp-server'
52
+ }
53
+ end
54
+ let(:client_data_json) do
55
+ 'eyJjaGFsbGVuZ2UiOiJjbUZ1Wkc5dExYTjBjbWx1WnkxblpXNWxjbUYwWldRdFlua3RjbkF0YzJWeWRtVnkiLCJvcmlnaW4iOiJodHRwczovL3dlYi1hdXRobi5zZWxmLWlzc3VlZC5hcHAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0'
56
+ end
57
+
58
+ context 'when self-attestation' do
59
+ let(:attestation_object) do
60
+ 'o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEYwRAIgOprGUE_GZMIbRBAPLPw6IiNdSk4dxFb4cRbqDgVfFXQCIHnRdm64FfnShyIhq1Z2qfn3ygp0auT32gy-eL35Uo6YaGF1dGhEYXRhWMQyy4DcrMPDUkYssB87_jAt5vNxLzD9IOzRnDuluFiUlUVb2_sTAAAAAAAAAAAAAAAAAAAAAABAAKUVEhUfjXl7S9MbcWXRfXltc39Spl6yuLxOuUtQJ-y-5DkR61Ge8riwY7dRXZFNSaWhsw9LfsknL57eZEB1gKUBAgMmIAEhWCCfkZcOMoafdVwFi4cNNPQlJS1JNUkq34sJ5fKhDODsfyJYIKD89fXxjNhcX6gDxsTwH3VL_TG7HAHdKFgUjAFumfmr'
61
+ end
62
+
63
+ it do
64
+ expect do
65
+ subject
66
+ end.not_to raise_error
67
+ end
68
+
69
+ context 'when client_data_json is invalid' do
70
+ let(:client_data_json) do
71
+ Base64.urlsafe_encode64({
72
+ type: "webauthn.create",
73
+ challenge: "cmFuZG9tLXN0cmluZy1nZW5lcmF0ZWQtYnktcnAtc2VydmVy",
74
+ origin: "https://web-authn.self-issued.app",
75
+ malformed: 'malformed'
76
+ }.to_json, padding: false)
77
+ end
78
+
79
+ it do
80
+ expect do
81
+ subject
82
+ end.to raise_error WebAuthn::InvalidAttestation, 'Invalid Packed Self Attestation: signature'
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'otherwise' do
88
+ let(:attestation_object) do
89
+ 'o2NmbXRmcGFja2VkZ2F0dFN0bXSjY2FsZyZjc2lnWEgwRgIhANsy4jAv4_BLPmM1pua45Pqo1gfIMA3KDgG-22P0eSH1AiEA3vRxM21j1nKLYyWTdgigzjZHG81IU3JXt2hh0Hr-P_tjeDVjgVkCwjCCAr4wggGmoAMCAQICBHSG_cIwDQYJKoZIhvcNAQELBQAwLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEwIBcNMTQwODAxMDAwMDAwWhgPMjA1MDA5MDQwMDAwMDBaMG8xCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlZdWJpY28gQUIxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xKDAmBgNVBAMMH1l1YmljbyBVMkYgRUUgU2VyaWFsIDE5NTUwMDM4NDIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASVXfOt9yR9MXXv_ZzE8xpOh4664YEJVmFQ-ziLLl9lJ79XQJqlgaUNCsUvGERcChNUihNTyKTlmnBOUjvATevto2wwajAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLlHAIBAQQEAwIFIDAhBgsrBgEEAYLlHAEBBAQSBBD4oBHzjApNFYAGFxEfntx9MAwGA1UdEwEB_wQCMAAwDQYJKoZIhvcNAQELBQADggEBADFcSIDmmlJ-OGaJvWn9CqhvSeueToVFQVVvqtALOgCKHdwB-Wx29mg2GpHiMsgQp5xjB0ybbnpG6x212FxESJ-GinZD0ipchi7APwPlhIvjgH16zVX44a4e4hOsc6tLIOP71SaMsHuHgCcdH0vg5d2sc006WJe9TXO6fzV-ogjJnYpNKQLmCXoAXE3JBNwKGBIOCvfQDPyWmiiG5bGxYfPty8Z3pnjX-1MDnM2hhr40ulMxlSNDnX_ZSnDyMGIbk8TOQmjTF02UO8auP8k3wt5D1rROIRU9-FCSX5WQYi68RuDrGMZB8P5-byoJqbKQdxn2LmE1oZAyohPAmLcoPO5oYXV0aERhdGFYxDLLgNysw8NSRiywHzv-MC3m83EvMP0g7NGcO6W4WJSVQQAAAAv4oBHzjApNFYAGFxEfntx9AEA02xXaLwowZrcHlY4sjukQfJOcMH6ulShKwJM5F4ScjEZHw5pzBzgX2Us_FsAqBP4D3f7rnJ3khIHK7bwY6vtYpQECAyYgASFYIJCdNP17MO609HucLCpQWeeCqIDtipNu2yK0PZHMPh1KIlggRfqxNbCUPKGPZn_NLUdXP2Jsf2ErcCoLEq9O7yEpZvQ'
90
+ end
91
+
92
+ it do
93
+ expect do
94
+ subject
95
+ end.to raise_error WebAuthn::NotImplementedError, 'Certificate Chain Verification Not Implemented Yet: packed'
96
+ end
97
+ end
98
+ end
99
+
47
100
  context 'when android-safetynet attestation given' do
48
101
  let(:context) do
49
102
  {
@@ -58,11 +111,12 @@ RSpec.describe WebAuthn::Context::Registration do
58
111
  'o2NmbXRxYW5kcm9pZC1zYWZldHluZXRnYXR0U3RtdKJjdmVyaDEyODc0MDQxaHJlc3BvbnNlWRMHZXlKaGJHY2lPaUpTVXpJMU5pSXNJbmcxWXlJNld5Sk5TVWxGYVdwRFEwRXpTMmRCZDBsQ1FXZEpTVmxyV1c4MVJqQm5PRFpyZDBSUldVcExiMXBKYUhaalRrRlJSVXhDVVVGM1ZrUkZURTFCYTBkQk1WVkZRbWhOUTFaV1RYaElha0ZqUW1kT1ZrSkJiMVJHVldSMllqSmtjMXBUUWxWamJsWjZaRU5DVkZwWVNqSmhWMDVzWTNwRmJFMURUVWRCTVZWRlFYaE5ZMUl5T1haYU1uaHNTVVZzZFdSSFZubGliVll3U1VWR01XUkhhSFpqYld3d1pWTkNTRTE2UVdWR2R6QjRUbnBGZVUxRVVYaE5la1UwVGtST1lVWjNNSGhQUkVWNVRVUk5kMDFFUVhkTlJFSmhUVWQzZUVONlFVcENaMDVXUWtGWlZFRnNWbFJOVWsxM1JWRlpSRlpSVVVsRVFYQkVXVmQ0Y0ZwdE9YbGliV3hvVFZKWmQwWkJXVVJXVVZGSVJFRXhUbUl6Vm5Wa1IwWndZbWxDVjJGWFZqTk5VazEzUlZGWlJGWlJVVXRFUVhCSVlqSTVibUpIVldkVFZ6VnFUVkp6ZDBkUldVUldVVkZFUkVKS2FHUklVbXhqTTFGMVdWYzFhMk50T1hCYVF6VnFZakl3ZDJkblJXbE5RVEJIUTFOeFIxTkpZak5FVVVWQ1FWRlZRVUUwU1VKRWQwRjNaMmRGUzBGdlNVSkJVVU5WYWpoM1dXOVFhWGhMWW1KV09ITm5XV2QyVFZSbVdDdGtTWE5HVkU5clowdFBiR2hVTUdrd1ltTkVSbHBMTW5KUGVFcGFNblZUVEZOV2FGbDJhWEJhVGtVelNFcFJXWFYxV1hkR2FtbDVLM2xyWm1GMFFVZFRhbEo2UmpGaU16RjFORE12TjI5SE5XcE5hRE5UTXpkaGJIZHFWV0k0UTFkcFZIaHZhWEJXVDFsM1MwdDZkVlY1YTNGRlEzUnFiR2hLTkVGclYyRkVVeXRhZUV0RmNVOWhaVGwwYmtOblpVaHNiRnBGTDA5U1oyVk5ZWGd5V0U1RGIwZzJjM0pVUlZKamEzTnFlbHBhY2tGWGVFdHpaR1oyVm5KWVRucERVamxFZUZaQlUzVkpOa3g2ZDJnNFJGTnNNa1ZQYjJ0aWMyRnVXaXNyTDBweFRXVkJRa1ptVUhkcWVYZHlZakJ3Y2tWVmVUQndZV1ZXYzNWa0t6QndaV1Y0U3k4MUswVTJhM0JaUjBzMFdrc3libXR2Vmt4MVowVTFkR0ZJY2tGcU9ETlJLMUJQWW1KMlQzcFhZMFpyY0c1V1MzbHFielpMVVVGdFdEWlhTa0ZuVFVKQlFVZHFaMmRHUjAxSlNVSlJha0ZVUW1kT1ZraFRWVVZFUkVGTFFtZG5ja0puUlVaQ1VXTkVRVlJCWkVKblRsWklVa1ZGUm1wQlZXZG9TbWhrU0ZKc1l6TlJkVmxYTld0amJUbHdXa00xYW1JeU1IZGhRVmxKUzNkWlFrSlJWVWhCVVVWRldFUkNZVTFETUVkRFEzTkhRVkZWUmtKNlFVTm9hVVp2WkVoU2QwOXBPSFpqUjNSd1RHMWtkbUl5WTNaYU0wNTVUV2s1U0ZaR1RraFRWVVpJVFhrMWFtTnVVWGRMVVZsSlMzZFpRa0pSVlVoTlFVZEhTRmRvTUdSSVFUWk1lVGwyV1ROT2QweHVRbkpoVXpWdVlqSTVia3d3WkZWVk1HUktVVlZqZWsxQ01FZEJNVlZrUkdkUlYwSkNVVWM0U1hKUmRFWlNOa05WVTJ0cGEySXpZV2x0YzIweU5tTkNWRUZOUW1kT1ZraFNUVUpCWmpoRlFXcEJRVTFDT0VkQk1WVmtTWGRSV1UxQ1lVRkdTR1pEZFVaRFlWb3pXakp6VXpORGFIUkRSRzlJTm0xbWNuQk1UVU5GUjBFeFZXUkpRVkZoVFVKbmQwUkJXVXRMZDFsQ1FrRklWMlZSU1VaQmVrRkpRbWRhYm1kUmQwSkJaMGwzVFZGWlJGWlNNR1pDUTI5M1MwUkJiVzlEVTJkSmIxbG5ZVWhTTUdORWIzWk1NazU1WWtNMWQyRXlhM1ZhTWpsMlduazVTRlpHVGtoVFZVWklUWGsxYW1OdGQzZEVVVmxLUzI5YVNXaDJZMDVCVVVWTVFsRkJSR2RuUlVKQlJpOVNlazV1UXpWRWVrSlZRblJ1YURKdWRFcE1WMFZSYURsNlJXVkdXbVpRVERsUmIydHliRUZ2V0dkcVYyZE9PSEJUVWxVeGJGWkhTWEIwZWsxNFIyaDVNeTlQVWxKYVZHRTJSREpFZVRob2RrTkVja1pKTXl0c1Exa3dNVTFNTlZFMldFNUZOVkp6TW1ReFVtbGFjRTF6ZWtRMFMxRmFUa2N6YUZvd1FrWk9VUzlqYW5KRGJVeENUMGRMYTBWVk1XUnRRVmh6UmtwWVNtbFBjakpEVGxSQ1QxUjFPVVZpVEZkb1VXWmtRMFl4WW5kNmVYVXJWelppVVZOMk9GRkVialZQWkUxVEwxQnhSVEZrUldkbGRDODJSVWxTUWpjMk1VdG1XbEVyTDBSRk5reHdNMVJ5V2xSd1QwWkVSR2RZYUN0TVowZFBjM2RvUld4cU9XTXpkbHBJUjBwdWFHcHdkRGh5YTJKcGNpOHlkVXhIWm5oc1ZsbzBTekY0TlVSU1RqQlFWVXhrT1hsUVUyMXFaeXRoYWpFcmRFaDNTVEZ0VVcxYVZsazNjWFpQTlVSbmFFOTRhRXBOUjJ4Nk5teE1hVnB0ZW05blBTSXNJazFKU1VWWVJFTkRRVEJUWjBGM1NVSkJaMGxPUVdWUGNFMUNlamhqWjFrMFVEVndWRWhVUVU1Q1oydHhhR3RwUnpsM01FSkJVWE5HUVVSQ1RVMVRRWGRJWjFsRVZsRlJURVY0WkVoaVJ6bHBXVmQ0VkdGWFpIVkpSa3AyWWpOUloxRXdSV2RNVTBKVFRXcEZWRTFDUlVkQk1WVkZRMmhOUzFJeWVIWlpiVVp6VlRKc2JtSnFSVlJOUWtWSFFURlZSVUY0VFV0U01uaDJXVzFHYzFVeWJHNWlha0ZsUm5jd2VFNTZRVEpOVkZWM1RVUkJkMDVFU21GR2R6QjVUVlJGZVUxVVZYZE5SRUYzVGtSS1lVMUdVWGhEZWtGS1FtZE9Wa0pCV1ZSQmJGWlVUVkkwZDBoQldVUldVVkZMUlhoV1NHSXlPVzVpUjFWblZraEtNV016VVdkVk1sWjVaRzFzYWxwWVRYaEtWRUZxUW1kT1ZrSkJUVlJJUldSMllqSmtjMXBUUWtwaWJsSnNZMjAxYkdSRFFrSmtXRkp2WWpOS2NHUklhMmRTZWsxM1oyZEZhVTFCTUVkRFUzRkhVMGxpTTBSUlJVSkJVVlZCUVRSSlFrUjNRWGRuWjBWTFFXOUpRa0ZSUkV0VmEzWnhTSFl2VDBwSGRXOHlia2xaWVU1V1YxaFJOVWxYYVRBeFExaGFZWG8yVkVsSVRFZHdMMnhQU2lzMk1EQXZOR2hpYmpkMmJqWkJRVUl6UkZaNlpGRlBkSE0zUnpWd1NEQnlTbTV1VDBaVlFVczNNVWMwYm5wTFRXWklRMGRWYTNOWEwyMXZibUVyV1RKbGJVcFJNazRyWVdsamQwcExaWFJRUzFKVFNXZEJkVkJQUWpaQllXaG9PRWhpTWxoUE0yZzVVbFZyTWxRd1NFNXZkVUl5Vm5wNGIwMVliR3Q1VnpkWVZWSTFiWGMyU210TVNHNUJOVEpZUkZadlVsUlhhMDUwZVRWdlEwbE9USFpIYlc1U2Mwb3hlbTkxUVhGWlIxWlJUV012TjNONUt5OUZXV2hCVEhKV1NrVkJPRXRpZEhsWUszSTRjMjUzVlRWRE1XaFZjbmRoVnpaTlYwOUJVbUU0Y1VKd1RsRmpWMVJyWVVsbGIxbDJlUzl6UjBsS1JXMXFVakIyUmtWM1NHUndNV05UWVZkSmNqWXZOR2MzTW00M1QzRllkMlpwYm5VM1dsbFhPVGRGWm05UFUxRktaVUY2UVdkTlFrRkJSMnBuWjBWNlRVbEpRa3g2UVU5Q1owNVdTRkU0UWtGbU9FVkNRVTFEUVZsWmQwaFJXVVJXVWpCc1FrSlpkMFpCV1VsTGQxbENRbEZWU0VGM1JVZERRM05IUVZGVlJrSjNUVU5OUWtsSFFURlZaRVYzUlVJdmQxRkpUVUZaUWtGbU9FTkJVVUYzU0ZGWlJGWlNNRTlDUWxsRlJraG1RM1ZHUTJGYU0xb3ljMU16UTJoMFEwUnZTRFp0Wm5Kd1RFMUNPRWRCTVZWa1NYZFJXVTFDWVVGR1NuWnBRakZrYmtoQ04wRmhaMkpsVjJKVFlVeGtMMk5IV1ZsMVRVUlZSME5EYzBkQlVWVkdRbmRGUWtKRGEzZEtla0ZzUW1kbmNrSm5SVVpDVVdOM1FWbFpXbUZJVWpCalJHOTJUREk1YW1NelFYVmpSM1J3VEcxa2RtSXlZM1phTTA1NVRXcEJlVUpuVGxaSVVqaEZTM3BCY0UxRFpXZEtZVUZxYUdsR2IyUklVbmRQYVRoMldUTktjMHh1UW5KaFV6VnVZakk1Ymt3eVpIcGpha2wyV2pOT2VVMXBOV3BqYlhkM1VIZFpSRlpTTUdkQ1JHZDNUbXBCTUVKbldtNW5VWGRDUVdkSmQwdHFRVzlDWjJkeVFtZEZSa0pSWTBOQlVsbGpZVWhTTUdOSVRUWk1lVGwzWVRKcmRWb3lPWFphZVRsNVdsaENkbU15YkRCaU0wbzFUSHBCVGtKbmEzRm9hMmxIT1hjd1FrRlJjMFpCUVU5RFFWRkZRVWhNWlVwc2RWSlVOMkoyY3pJMlozbEJXamh6YnpneGRISlZTVk5rTjA4ME5YTnJSRlZ0UVdkbE1XTnVlR2hITVZBeVkwNXRVM2hpVjNOdmFVTjBNbVYxZURsTVUwUXJVRUZxTWt4SldWSkdTRmN6TVM4MmVHOXBZekZyTkhSaVYxaHJSRU5xYVhJek4zaFVWRTV4VWtGTlVGVjVSbEpYVTJSMmRDdHViRkJ4ZDI1aU9FOWhNa2t2YldGVFNuVnJZM2hFYWs1VFpuQkVhQzlDWkRGc1drNW5aR1F2T0dOTVpITkZNeXQzZVhCMVprbzVkVmhQTVdsUmNHNW9PWHBpZFVaSmQzTkpUMDVIYkRGd00wRTRRMmQ0YTNGSkwxVkJhV2d6U21GSFQzRmpjR05rWVVOSmVtdENZVkk1ZFZsUk1WZzBhekpXWnpWQlVGSk1iM1Y2Vm5rM1lUaEpWbXMyZDNWNU5uQnRLMVEzU0ZRMFRGazRhV0pUTlVaRldteG1RVVpNVTFjNFRuZHpWbm81VTBKTE1sWnhiakZPTUZCSlRXNDFlRUUyVGxwV1l6ZHZPRE0xUkV4QlJuTm9SVmRtUXpkVVNXVXpaejA5SWwxOS5leUp1YjI1alpTSTZJaTlYVG1SVFZXOHpiRUl4ZWt0Mk5UVlpNV1EyY2psR1pXdFJkbE5rZERjNWNHaDRjMmhuTjNsMVIxazlJaXdpZEdsdFpYTjBZVzF3VFhNaU9qRTFNelUyT1Rjd056TTFOVEFzSW1Gd2ExQmhZMnRoWjJWT1lXMWxJam9pWTI5dExtZHZiMmRzWlM1aGJtUnliMmxrTG1kdGN5SXNJbUZ3YTBScFoyVnpkRk5vWVRJMU5pSTZJako1TXpBNFJ6Y3hMM2RaUmtZMk9XRnVSVzlKT1VGYWNrTmFPREZFV0dSMk1YaEhNMjg0UVZkUlNITTlJaXdpWTNSelVISnZabWxzWlUxaGRHTm9JanAwY25WbExDSmhjR3REWlhKMGFXWnBZMkYwWlVScFoyVnpkRk5vWVRJMU5pSTZXeUk0VURGelZ6QkZVRXBqYzJ4M04xVjZVbk5wV0V3Mk5IY3JUelV3UldRclVrSkpRM1JoZVRGbk1qUk5QU0pkTENKaVlYTnBZMGx1ZEdWbmNtbDBlU0k2ZEhKMVpYMC5QVW9fT0h0dW96SWUxZGZFNlctSUVlYkZtN0R0Qll6M2NmZ0UzRlB5X3dVQlFCMjUwUE1WWjNVbk1NVjYwb0Q2U3d0ajZtQ0lQYnNYZnBULXFuY184eHlTUURndXZQUmp1b191b1JtUWF4aV9FSEZVaTZrZFV0akhaNkY1bWpYcVF4LWRiaFlONU00dG01WlM2bUxaMkdlbGlVcE1UVG9nU2FQUVZiVnl1Y3g0aGpfT1VDLWVPM1lCRmRldmw0d0pmSy15QVJxaGtmOHN6NEgwa1E5TU9IT2U0N0x2a0h3RnI2MElQSjNaQ3QwSklKYnJWVDZnMHJJal9iSlo3aXFrTDFOWUhrbURvNUhnSkgyTXA3QnYtZlJfMHcydzJyWkIzZk5zVGhxRm9UbUI4RU5XUmJjQ3lWQXBncVdIbFU5bUh5SlJGWVVsbnVDcGRGSEwwUjFaX1FoYXV0aERhdGFYxTLLgNysw8NSRiywHzv-MC3m83EvMP0g7NGcO6W4WJSVRAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEBKg96NvDCk5gmyyLqM0zXE0ZZnSkTarHzUfYU2PHWwdQhjjWLXayf0-jYLazWjpSr-N8DM1Zhls4jfmQCqa50X6UBAgMmIAEhWCAGD72C5VXE3mwMjzc_X0_7wUgIOA6kt2KoDIn1-1PHdSJYIAoZmBXyEJkjvlu251BDb8VoOtIketAD1VvYc3WUJJrZ'
59
112
  end
60
113
 
61
- it do
62
- expect do
63
- subject
64
- end.not_to raise_error
65
- end
114
+ # it do
115
+ # expect do
116
+ # subject
117
+ # end.not_to raise_error
118
+ # end
119
+ it 'TODO: handle time-dependent certificate verification error (timecop can\'t modify time in openssl world)'
66
120
 
67
121
  context 'when client_data_json is invalid' do
68
122
  let(:client_data_json) do
@@ -12,11 +12,12 @@ Gem::Specification.new do |gem|
12
12
  gem.executables = `git ls-files -- exe/*`.split("\n").map{ |f| File.basename(f) }
13
13
  gem.require_paths = ['lib']
14
14
  gem.required_ruby_version = '>= 2.3'
15
+ gem.add_runtime_dependency 'openssl', '>= 2.2.0'
15
16
  gem.add_runtime_dependency 'activesupport'
16
17
  gem.add_runtime_dependency 'cbor'
17
- gem.add_runtime_dependency 'cose-key'
18
+ gem.add_runtime_dependency 'cose-key', '>= 0.2.0'
18
19
  gem.add_runtime_dependency 'json-jwt'
19
- gem.add_development_dependency 'rake', '~> 10.0'
20
+ gem.add_development_dependency 'rake'
20
21
  gem.add_development_dependency 'simplecov'
21
22
  gem.add_development_dependency 'rspec'
22
23
  gem.add_development_dependency 'rspec-its'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_authn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.6.1
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-12 00:00:00.000000000 Z
11
+ date: 2020-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: openssl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activesupport
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +58,14 @@ dependencies:
44
58
  requirements:
45
59
  - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '0'
61
+ version: 0.2.0
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '0'
68
+ version: 0.2.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: json-jwt
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -70,16 +84,16 @@ dependencies:
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - "~>"
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: '10.0'
89
+ version: '0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - "~>"
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: '10.0'
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: simplecov
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -144,6 +158,8 @@ files:
144
158
  - lib/web_authn/attestation_object.rb
145
159
  - lib/web_authn/attestation_statement.rb
146
160
  - lib/web_authn/attestation_statement/android_safetynet.rb
161
+ - lib/web_authn/attestation_statement/apple.rb
162
+ - lib/web_authn/attestation_statement/packed.rb
147
163
  - lib/web_authn/attested_credential_data.rb
148
164
  - lib/web_authn/authenticator_data.rb
149
165
  - lib/web_authn/authenticator_data/flags.rb
@@ -180,8 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
196
  - !ruby/object:Gem::Version
181
197
  version: '0'
182
198
  requirements: []
183
- rubyforge_project:
184
- rubygems_version: 2.5.2
199
+ rubygems_version: 3.0.3
185
200
  signing_key:
186
201
  specification_version: 4
187
202
  summary: WebAuthn RP library