webauthn 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +156 -0
- data/CHANGELOG.md +14 -2
- data/README.md +20 -4
- data/Rakefile +1 -1
- data/lib/cose/ecdsa.rb +7 -0
- data/lib/webauthn.rb +2 -2
- data/lib/webauthn/authenticator_assertion_response.rb +15 -5
- data/lib/webauthn/authenticator_data.rb +1 -1
- data/lib/webauthn/authenticator_data/attested_credential_data.rb +1 -4
- data/lib/webauthn/authenticator_data/attested_credential_data/public_key_u2f.rb +3 -3
- data/lib/webauthn/version.rb +1 -1
- data/webauthn.gemspec +3 -2
- metadata +18 -5
- data/lib/webauthn/cose/ecdsa.rb +0 -9
- data/lib/webauthn/cose/key/ec2.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 004107dfab888cb866245f75d634764ffb859974f12e5d70b30304a6d8c25ce1
|
4
|
+
data.tar.gz: 2cdfacf2e938a030f494717d644ae394f1f55a759e5eff125face25f7eda16d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3080d2ca2560908ff75ab0a100226c9526e3909cdbadc6d166050fbea710b0f48f52f56ea315ff7e2e98d4a877ad5da1e85a12cb9f3f57784b99f5a8416e76a
|
7
|
+
data.tar.gz: e1d08103e408ec0e9b4561d1b24b886a013392ddf13044cf62b13046ea8754aec2ff184f75d48ec1710d4c53bb841f87289e8bbe5c2d5c496f40b683a1b353be
|
data/.rubocop.yml
CHANGED
@@ -28,8 +28,164 @@ Performance:
|
|
28
28
|
Security:
|
29
29
|
Enabled: true
|
30
30
|
|
31
|
+
Style/BlockComments:
|
32
|
+
Enabled: true
|
33
|
+
|
34
|
+
Style/BracesAroundHashParameters:
|
35
|
+
Enabled: true
|
36
|
+
|
37
|
+
Style/CaseEquality:
|
38
|
+
Enabled: true
|
39
|
+
|
40
|
+
Style/ClassAndModuleChildren:
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
Style/ClassMethods:
|
44
|
+
Enabled: true
|
45
|
+
|
46
|
+
Style/ClassVars:
|
47
|
+
Enabled: true
|
48
|
+
|
49
|
+
Style/CommentAnnotation:
|
50
|
+
Enabled: true
|
51
|
+
|
52
|
+
Style/ConditionalAssignment:
|
53
|
+
Enabled: true
|
54
|
+
|
55
|
+
Style/DefWithParentheses:
|
56
|
+
Enabled: true
|
57
|
+
|
58
|
+
Style/Dir:
|
59
|
+
Enabled: true
|
60
|
+
|
61
|
+
Style/EachForSimpleLoop:
|
62
|
+
Enabled: true
|
63
|
+
|
64
|
+
Style/EachWithObject:
|
65
|
+
Enabled: true
|
66
|
+
|
67
|
+
Style/EmptyBlockParameter:
|
68
|
+
Enabled: true
|
69
|
+
|
70
|
+
Style/EmptyCaseCondition:
|
71
|
+
Enabled: true
|
72
|
+
|
73
|
+
Style/EmptyElse:
|
74
|
+
Enabled: true
|
75
|
+
|
76
|
+
Style/EmptyLambdaParameter:
|
77
|
+
Enabled: true
|
78
|
+
|
79
|
+
Style/EmptyLiteral:
|
80
|
+
Enabled: true
|
81
|
+
|
82
|
+
Style/EvenOdd:
|
83
|
+
Enabled: true
|
84
|
+
|
85
|
+
Style/ExpandPathArguments:
|
86
|
+
Enabled: true
|
87
|
+
|
88
|
+
Style/For:
|
89
|
+
Enabled: true
|
90
|
+
|
31
91
|
Style/FrozenStringLiteralComment:
|
32
92
|
Enabled: true
|
33
93
|
|
94
|
+
Style/GlobalVars:
|
95
|
+
Enabled: true
|
96
|
+
|
97
|
+
Style/HashSyntax:
|
98
|
+
Enabled: true
|
99
|
+
|
100
|
+
Style/IdenticalConditionalBranches:
|
101
|
+
Enabled: true
|
102
|
+
|
103
|
+
Style/IfInsideElse:
|
104
|
+
Enabled: true
|
105
|
+
|
106
|
+
Style/InverseMethods:
|
107
|
+
Enabled: true
|
108
|
+
|
109
|
+
Style/MethodCallWithoutArgsParentheses:
|
110
|
+
Enabled: true
|
111
|
+
|
112
|
+
Style/MethodDefParentheses:
|
113
|
+
Enabled: true
|
114
|
+
|
115
|
+
Style/MultilineMemoization:
|
116
|
+
Enabled: true
|
117
|
+
|
118
|
+
Style/MutableConstant:
|
119
|
+
Enabled: true
|
120
|
+
|
121
|
+
Style/NestedParenthesizedCalls:
|
122
|
+
Enabled: true
|
123
|
+
|
124
|
+
Style/OptionalArguments:
|
125
|
+
Enabled: true
|
126
|
+
|
127
|
+
Style/ParenthesesAroundCondition:
|
128
|
+
Enabled: true
|
129
|
+
|
130
|
+
Style/RedundantBegin:
|
131
|
+
Enabled: true
|
132
|
+
|
133
|
+
Style/RedundantConditional:
|
134
|
+
Enabled: true
|
135
|
+
|
136
|
+
Style/RedundantException:
|
137
|
+
Enabled: true
|
138
|
+
|
34
139
|
Style/RedundantFreeze:
|
35
140
|
Enabled: true
|
141
|
+
|
142
|
+
Style/RedundantParentheses:
|
143
|
+
Enabled: true
|
144
|
+
|
145
|
+
Style/RedundantReturn:
|
146
|
+
Enabled: true
|
147
|
+
|
148
|
+
Style/RedundantSelf:
|
149
|
+
Enabled: true
|
150
|
+
|
151
|
+
Style/Semicolon:
|
152
|
+
Enabled: true
|
153
|
+
|
154
|
+
Style/SingleLineMethods:
|
155
|
+
Enabled: true
|
156
|
+
|
157
|
+
Style/SpecialGlobalVars:
|
158
|
+
Enabled: true
|
159
|
+
|
160
|
+
Style/SymbolLiteral:
|
161
|
+
Enabled: true
|
162
|
+
|
163
|
+
Style/TrailingBodyOnClass:
|
164
|
+
Enabled: true
|
165
|
+
|
166
|
+
Style/TrailingBodyOnMethodDefinition:
|
167
|
+
Enabled: true
|
168
|
+
|
169
|
+
Style/TrailingBodyOnModule:
|
170
|
+
Enabled: true
|
171
|
+
|
172
|
+
Style/TrailingMethodEndStatement:
|
173
|
+
Enabled: true
|
174
|
+
|
175
|
+
Style/TrivialAccessors:
|
176
|
+
Enabled: true
|
177
|
+
|
178
|
+
Style/UnneededInterpolation:
|
179
|
+
Enabled: true
|
180
|
+
|
181
|
+
Style/UnneededPercentQ:
|
182
|
+
Enabled: true
|
183
|
+
|
184
|
+
Style/UnpackFirst:
|
185
|
+
Enabled: true
|
186
|
+
|
187
|
+
Style/YodaCondition:
|
188
|
+
Enabled: true
|
189
|
+
|
190
|
+
Style/ZeroLengthPredicate:
|
191
|
+
Enabled: true
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [v1.0.0] - 2018-09-07
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- _Authentication_ ceremony
|
8
|
+
- Support multiple credentials per user by letting `WebAuthn::AuthenticatorAssertionResponse.valid?` receive multiple allowed credentials
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- _Registration_ ceremony
|
13
|
+
- Use 32-byte challenge instead of 16-byte
|
14
|
+
- _Authentication_ ceremony
|
15
|
+
- Use 32-byte challenge instead of 16-byte
|
4
16
|
|
5
17
|
## [v0.2.0] - 2018-06-08
|
6
18
|
|
@@ -39,6 +51,6 @@
|
|
39
51
|
- `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
|
40
52
|
- Works with ruby 2.5
|
41
53
|
|
42
|
-
[
|
54
|
+
[v1.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.2.0...v1.0.0/
|
43
55
|
[v0.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.1.0...v0.2.0/
|
44
56
|
[v0.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.0.0...v0.1.0/
|
data/README.md
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# WebAuthn :key:
|
2
2
|
|
3
|
-
Easily implement WebAuthn in your ruby
|
3
|
+
Easily implement WebAuthn in your ruby/rails app
|
4
4
|
|
5
5
|
[![Gem](https://img.shields.io/gem/v/webauthn.svg?style=flat-square)](https://rubygems.org/gems/webauthn)
|
6
6
|
[![Travis](https://img.shields.io/travis/cedarcode/webauthn-ruby.svg?style=flat-square)](https://travis-ci.org/cedarcode/webauthn-ruby)
|
7
7
|
|
8
|
-
## WARNING: This gem is in the early development phase. Use on production at your own risk.
|
9
|
-
|
10
8
|
## What is WebAuthn?
|
11
9
|
|
12
10
|
- [WebAuthn article with Google IO 2018 talk](https://developers.google.com/web/updates/2018/05/webauthn)
|
@@ -16,7 +14,7 @@ Easily implement WebAuthn in your ruby web server
|
|
16
14
|
|
17
15
|
## Prerequisites
|
18
16
|
|
19
|
-
This gem will help your ruby server act as a conforming [_Relying-Party_](https://www.w3.org/TR/webauthn/#relying-party), in WebAuthn terminology. But for the [_Registration_](https://www.w3.org/TR/webauthn/#registration) and [
|
17
|
+
This gem will help your ruby server act as a conforming [_Relying-Party_](https://www.w3.org/TR/webauthn/#relying-party), in WebAuthn terminology. But for the [_Registration_](https://www.w3.org/TR/webauthn/#registration) and [_Authentication_](https://www.w3.org/TR/webauthn/#authentication) ceremonies to work, you will also need
|
20
18
|
|
21
19
|
### A conforming User Agent
|
22
20
|
|
@@ -153,6 +151,24 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
153
151
|
|
154
152
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
155
153
|
|
154
|
+
### Commit message format
|
155
|
+
|
156
|
+
Each commit message follows the `<type>: <message>` format.
|
157
|
+
|
158
|
+
The "message" starts with lowercase and the "type" is one of:
|
159
|
+
|
160
|
+
* __build__: Changes that affect the build system or external dependencies
|
161
|
+
* __ci__: Changes to the CI configuration files and scripts
|
162
|
+
* __docs__: Documentation only changes
|
163
|
+
* __feat__: A new feature
|
164
|
+
* __fix__: A bug fix
|
165
|
+
* __perf__: A code change that improves performance
|
166
|
+
* __refactor__: A code change that neither fixes a bug nor adds a feature
|
167
|
+
* __style__: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
168
|
+
* __test__: Adding missing tests or correcting existing tests
|
169
|
+
|
170
|
+
Inspired in a subset of [Angular's Commit Message Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines).
|
171
|
+
|
156
172
|
## Contributing
|
157
173
|
|
158
174
|
Bug reports and pull requests are welcome on GitHub at https://github.com/cedarcode/webauthn-ruby.
|
data/Rakefile
CHANGED
data/lib/cose/ecdsa.rb
ADDED
data/lib/webauthn.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "cose/ecdsa"
|
3
4
|
require "webauthn/authenticator_attestation_response"
|
4
5
|
require "webauthn/authenticator_assertion_response"
|
5
|
-
require "webauthn/cose/ecdsa"
|
6
6
|
require "webauthn/utils"
|
7
7
|
require "webauthn/version"
|
8
8
|
|
@@ -34,7 +34,7 @@ module WebAuthn
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.challenge
|
37
|
-
SecureRandom.random_bytes(
|
37
|
+
SecureRandom.random_bytes(32)
|
38
38
|
end
|
39
39
|
private_class_method :challenge
|
40
40
|
end
|
@@ -12,10 +12,10 @@ module WebAuthn
|
|
12
12
|
@signature = signature
|
13
13
|
end
|
14
14
|
|
15
|
-
def valid?(original_challenge, original_origin,
|
15
|
+
def valid?(original_challenge, original_origin, allowed_credentials:)
|
16
16
|
super(original_challenge, original_origin) &&
|
17
|
-
valid_credential?(
|
18
|
-
valid_signature?(
|
17
|
+
valid_credential?(allowed_credentials) &&
|
18
|
+
valid_signature?(credential_public_key(allowed_credentials))
|
19
19
|
end
|
20
20
|
|
21
21
|
private
|
@@ -36,14 +36,24 @@ module WebAuthn
|
|
36
36
|
)
|
37
37
|
end
|
38
38
|
|
39
|
-
def valid_credential?(
|
40
|
-
|
39
|
+
def valid_credential?(allowed_credentials)
|
40
|
+
allowed_credential_ids = allowed_credentials.map { |credential| credential[:id] }
|
41
|
+
|
42
|
+
allowed_credential_ids.include?(credential_id)
|
41
43
|
end
|
42
44
|
|
43
45
|
def authenticator_data
|
44
46
|
@authenticator_data ||= WebAuthn::AuthenticatorData.new(authenticator_data_bytes)
|
45
47
|
end
|
46
48
|
|
49
|
+
def credential_public_key(allowed_credentials)
|
50
|
+
matched_credential = allowed_credentials.find do |credential|
|
51
|
+
credential[:id] == credential_id
|
52
|
+
end
|
53
|
+
|
54
|
+
matched_credential[:public_key]
|
55
|
+
end
|
56
|
+
|
47
57
|
def type
|
48
58
|
WebAuthn::TYPES[:get]
|
49
59
|
end
|
@@ -48,10 +48,7 @@ module WebAuthn
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def id_length
|
51
|
-
@id_length ||=
|
52
|
-
data_at(id_length_position, ID_LENGTH_LENGTH)
|
53
|
-
.unpack(UINT16_BIG_ENDIAN_FORMAT)
|
54
|
-
.first
|
51
|
+
@id_length ||= data_at(id_length_position, ID_LENGTH_LENGTH).unpack1(UINT16_BIG_ENDIAN_FORMAT)
|
55
52
|
end
|
56
53
|
|
57
54
|
def id_length_position
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "
|
3
|
+
require "cose/ecdsa"
|
4
|
+
require "cose/key/ec2"
|
5
5
|
|
6
6
|
module WebAuthn
|
7
7
|
class AuthenticatorData
|
@@ -17,7 +17,7 @@ module WebAuthn
|
|
17
17
|
data.size >= COORDINATE_LENGTH * 2 &&
|
18
18
|
cose_key.x_coordinate.length == COORDINATE_LENGTH &&
|
19
19
|
cose_key.y_coordinate.length == COORDINATE_LENGTH &&
|
20
|
-
cose_key.algorithm ==
|
20
|
+
cose_key.algorithm == COSE::ECDSA::ALG_ES256
|
21
21
|
end
|
22
22
|
|
23
23
|
def to_str
|
data/lib/webauthn/version.rb
CHANGED
data/webauthn.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path(
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require "webauthn/version"
|
6
6
|
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ["Gonzalo Rodriguez", "Braulio Martinez"]
|
11
11
|
spec.email = ["gonzalo@cedarcode.com", "braulio@cedarcode.com"]
|
12
12
|
|
13
|
-
spec.summary =
|
13
|
+
spec.summary = "WebAuthn in ruby ― Ruby implementation of a WebAuthn Relying Party"
|
14
14
|
spec.homepage = "https://github.com/cedarcode/webauthn-ruby"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
30
|
spec.add_dependency "cbor", "~> 0.5.9.2"
|
31
|
+
spec.add_dependency "cose", "~> 0.1.0"
|
31
32
|
|
32
33
|
spec.add_development_dependency "bundler", "~> 1.16"
|
33
34
|
spec.add_development_dependency "byebug", "~> 10.0"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webauthn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Rodriguez
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-09-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cbor
|
@@ -25,6 +25,20 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 0.5.9.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: cose
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.1.0
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.1.0
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: bundler
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,6 +128,7 @@ files:
|
|
114
128
|
- Rakefile
|
115
129
|
- bin/console
|
116
130
|
- bin/setup
|
131
|
+
- lib/cose/ecdsa.rb
|
117
132
|
- lib/webauthn.rb
|
118
133
|
- lib/webauthn/attestation_statement.rb
|
119
134
|
- lib/webauthn/attestation_statement/base.rb
|
@@ -126,8 +141,6 @@ files:
|
|
126
141
|
- lib/webauthn/authenticator_data/attested_credential_data/public_key_u2f.rb
|
127
142
|
- lib/webauthn/authenticator_response.rb
|
128
143
|
- lib/webauthn/client_data.rb
|
129
|
-
- lib/webauthn/cose/ecdsa.rb
|
130
|
-
- lib/webauthn/cose/key/ec2.rb
|
131
144
|
- lib/webauthn/utils.rb
|
132
145
|
- lib/webauthn/version.rb
|
133
146
|
- webauthn.gemspec
|
@@ -157,5 +170,5 @@ rubyforge_project:
|
|
157
170
|
rubygems_version: 2.7.7
|
158
171
|
signing_key:
|
159
172
|
specification_version: 4
|
160
|
-
summary:
|
173
|
+
summary: WebAuthn in ruby ― Ruby implementation of a WebAuthn Relying Party
|
161
174
|
test_files: []
|
data/lib/webauthn/cose/ecdsa.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WebAuthn
|
4
|
-
# COSE module has the potential to being extracted out of WebAuthn
|
5
|
-
module COSE
|
6
|
-
module Key
|
7
|
-
class EC2
|
8
|
-
KTY_LABEL = 1
|
9
|
-
ALG_LABEL = 3
|
10
|
-
|
11
|
-
CRV_LABEL = -1
|
12
|
-
X_LABEL = -2
|
13
|
-
Y_LABEL = -3
|
14
|
-
|
15
|
-
KTY_EC2 = 2
|
16
|
-
|
17
|
-
attr_reader :algorithm, :curve, :x_coordinate, :y_coordinate
|
18
|
-
|
19
|
-
def initialize(algorithm: nil, curve:, x_coordinate:, y_coordinate:)
|
20
|
-
if !curve
|
21
|
-
raise ArgumentError, "Required curve is missing"
|
22
|
-
elsif !x_coordinate
|
23
|
-
raise ArgumentError, "Required x-coordinate is missing"
|
24
|
-
elsif !y_coordinate
|
25
|
-
raise ArgumentError, "Required y-coordinate is missing"
|
26
|
-
else
|
27
|
-
@algorithm = algorithm
|
28
|
-
@curve = curve
|
29
|
-
@x_coordinate = x_coordinate
|
30
|
-
@y_coordinate = y_coordinate
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.from_map(map)
|
35
|
-
if map[KTY_LABEL] == KTY_EC2
|
36
|
-
new(
|
37
|
-
algorithm: map[ALG_LABEL],
|
38
|
-
curve: map[CRV_LABEL],
|
39
|
-
x_coordinate: map[X_LABEL],
|
40
|
-
y_coordinate: map[Y_LABEL]
|
41
|
-
)
|
42
|
-
else
|
43
|
-
raise "Not an EC2 key"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.from_cbor(cbor)
|
48
|
-
from_map(CBOR.decode(cbor))
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|