Skip to content

Commit 54d025c

Browse files
refactor: remove base64 dependency
1 parent 69492d0 commit 54d025c

10 files changed

+62
-58
lines changed

lib/webauthn/encoder.rb

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# frozen_string_literal: true
22

3-
require "base64"
43
require "webauthn/encoders"
54

65
module WebAuthn

lib/webauthn/u2f_migrator.rb

+5-3
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,24 @@ def attestation_type
4343
end
4444

4545
def attestation_trust_path
46-
@attestation_trust_path ||= [OpenSSL::X509::Certificate.new(Base64.strict_decode64(@certificate))]
46+
@attestation_trust_path ||= [
47+
OpenSSL::X509::Certificate.new(WebAuthn::Encoders::Base64Encoder.decode(@certificate))
48+
]
4749
end
4850

4951
private
5052

5153
# https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#u2f-authenticatorMakeCredential-interoperability
5254
# Let credentialId be a credentialIdLength byte array initialized with CTAP1/U2F response key handle bytes.
5355
def credential_id
54-
Base64.urlsafe_decode64(@key_handle)
56+
WebAuthn::Encoders::Base64UrlEncoder.decode(@key_handle)
5557
end
5658

5759
# Let x9encodedUserPublicKey be the user public key returned in the U2F registration response message [U2FRawMsgs].
5860
# Let coseEncodedCredentialPublicKey be the result of converting x9encodedUserPublicKey’s value from ANS X9.62 /
5961
# Sec-1 v2 uncompressed curve point representation [SEC1V2] to COSE_Key representation ([RFC8152] Section 7).
6062
def credential_cose_key
61-
decoded_public_key = Base64.strict_decode64(@public_key)
63+
decoded_public_key = WebAuthn::Encoders::Base64Encoder.decode(@public_key)
6264
if WebAuthn::AttestationStatement::FidoU2f::PublicKey.uncompressed_point?(decoded_public_key)
6365
COSE::Key::EC2.new(
6466
alg: COSE::Algorithm.by_name("ES256").id,

spec/webauthn/attestation_statement/android_safetynet_spec.rb

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
require "spec_helper"
44

5-
require "base64"
65
require "jwt"
76
require "openssl"
87
require "webauthn/attestation_statement/android_safetynet"
@@ -17,7 +16,7 @@
1716
payload,
1817
attestation_key,
1918
"RS256",
20-
x5c: [Base64.strict_encode64(leaf_certificate.to_der)]
19+
x5c: [WebAuthn::Encoders::Base64Encoder.encode(leaf_certificate.to_der)]
2120
)
2221
end
2322

@@ -26,7 +25,11 @@
2625
end
2726
let(:timestamp) { Time.now }
2827
let(:cts_profile_match) { true }
29-
let(:nonce) { Base64.strict_encode64(OpenSSL::Digest::SHA256.digest(authenticator_data_bytes + client_data_hash)) }
28+
let(:nonce) do
29+
WebAuthn::Encoders::Base64Encoder.encode(
30+
OpenSSL::Digest::SHA256.digest(authenticator_data_bytes + client_data_hash)
31+
)
32+
end
3033
let(:attestation_key) { create_rsa_key }
3134

3235
let(:leaf_certificate) do
@@ -63,7 +66,7 @@
6366
end
6467

6568
context "when nonce is not set to the base64 of the SHA256 of authData + clientDataHash" do
66-
let(:nonce) { Base64.strict_encode64(OpenSSL::Digest.digest("SHA256", "something else")) }
69+
let(:nonce) { WebAuthn::Encoders::Base64Encoder.encode(OpenSSL::Digest.digest("SHA256", "something else")) }
6770

6871
it "returns false" do
6972
expect(statement.valid?(authenticator_data, client_data_hash)).to be_falsy

spec/webauthn/authenticator_assertion_response_spec.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -518,12 +518,12 @@
518518
let(:assertion_data) { seeds[:u2f_migration][:assertion] }
519519
let(:assertion_response) do
520520
WebAuthn::AuthenticatorAssertionResponse.new(
521-
client_data_json: Base64.strict_decode64(assertion_data[:response][:client_data_json]),
522-
authenticator_data: Base64.strict_decode64(assertion_data[:response][:authenticator_data]),
523-
signature: Base64.strict_decode64(assertion_data[:response][:signature])
521+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(assertion_data[:response][:client_data_json]),
522+
authenticator_data: WebAuthn::Encoders::Base64Encoder.decode(assertion_data[:response][:authenticator_data]),
523+
signature: WebAuthn::Encoders::Base64Encoder.decode(assertion_data[:response][:signature])
524524
)
525525
end
526-
let(:original_challenge) { Base64.strict_decode64(assertion_data[:challenge]) }
526+
let(:original_challenge) { WebAuthn::Encoders::Base64Encoder.decode(assertion_data[:challenge]) }
527527

528528
context "when correct FIDO AppID is given as rp_id" do
529529
it "verifies" do

spec/webauthn/authenticator_attestation_response_spec.rb

+26-25
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
require "spec_helper"
44
require "support/seeds"
55

6-
require "base64"
76
require "webauthn/authenticator_attestation_response"
87
require "openssl"
98

@@ -114,7 +113,7 @@
114113

115114
context "when fido-u2f attestation" do
116115
let(:original_challenge) do
117-
Base64.strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
116+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:security_key_direct][:credential_creation_options][:challenge])
118117
end
119118

120119
context "when there is a single origin" do
@@ -124,8 +123,8 @@
124123
response = seeds[:security_key_direct][:authenticator_attestation_response]
125124

126125
WebAuthn::AuthenticatorAttestationResponse.new(
127-
attestation_object: Base64.strict_decode64(response[:attestation_object]),
128-
client_data_json: Base64.strict_decode64(response[:client_data_json])
126+
attestation_object: WebAuthn::Encoders::Base64Encoder.decode(response[:attestation_object]),
127+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(response[:client_data_json])
129128
)
130129
end
131130

@@ -194,7 +193,7 @@
194193
let(:origin) { "https://localhost:13010" }
195194

196195
let(:original_challenge) do
197-
Base64.strict_decode64(
196+
WebAuthn::Encoders::Base64Encoder.decode(
198197
seeds[:security_key_packed_self][:credential_creation_options][:challenge]
199198
)
200199
end
@@ -203,8 +202,8 @@
203202
response = seeds[:security_key_packed_self][:authenticator_attestation_response]
204203

205204
WebAuthn::AuthenticatorAttestationResponse.new(
206-
attestation_object: Base64.strict_decode64(response[:attestation_object]),
207-
client_data_json: Base64.strict_decode64(response[:client_data_json])
205+
attestation_object: WebAuthn::Encoders::Base64Encoder.decode(response[:attestation_object]),
206+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(response[:client_data_json])
208207
)
209208
end
210209

@@ -234,7 +233,7 @@
234233
let(:origin) { "http://localhost:3000" }
235234

236235
let(:original_challenge) do
237-
Base64.strict_decode64(
236+
WebAuthn::Encoders::Base64Encoder.decode(
238237
seeds[:security_key_packed_x5c][:credential_creation_options][:challenge]
239238
)
240239
end
@@ -243,8 +242,8 @@
243242
response = seeds[:security_key_packed_x5c][:authenticator_attestation_response]
244243

245244
WebAuthn::AuthenticatorAttestationResponse.new(
246-
attestation_object: Base64.strict_decode64(response[:attestation_object]),
247-
client_data_json: Base64.strict_decode64(response[:client_data_json])
245+
attestation_object: WebAuthn::Encoders::Base64Encoder.decode(response[:attestation_object]),
246+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(response[:client_data_json])
248247
)
249248
end
250249

@@ -274,14 +273,14 @@
274273
context "when TPM attestation" do
275274
let(:origin) { seeds[:tpm][:origin] }
276275
let(:time) { Time.utc(2019, 8, 13, 22, 6) }
277-
let(:challenge) { Base64.urlsafe_decode64(seeds[:tpm][:credential_creation_options][:challenge]) }
276+
let(:challenge) { WebAuthn::Encoders::Base64UrlEncoder.decode(seeds[:tpm][:credential_creation_options][:challenge]) }
278277

279278
let(:attestation_response) do
280279
response = seeds[:tpm][:authenticator_attestation_response]
281280

282281
WebAuthn::AuthenticatorAttestationResponse.new(
283-
attestation_object: Base64.urlsafe_decode64(response[:attestation_object]),
284-
client_data_json: Base64.urlsafe_decode64(response[:client_data_json])
282+
attestation_object: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:attestation_object]),
283+
client_data_json: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:client_data_json])
285284
)
286285
end
287286

@@ -334,15 +333,17 @@
334333
let(:origin) { "https://7f41ac45.ngrok.io" }
335334

336335
let(:original_challenge) do
337-
Base64.strict_decode64(seeds[:android_safetynet_direct][:credential_creation_options][:challenge])
336+
WebAuthn::Encoders::Base64Encoder.decode(
337+
seeds[:android_safetynet_direct][:credential_creation_options][:challenge]
338+
)
338339
end
339340

340341
let(:attestation_response) do
341342
response = seeds[:android_safetynet_direct][:authenticator_attestation_response]
342343

343344
WebAuthn::AuthenticatorAttestationResponse.new(
344-
attestation_object: Base64.strict_decode64(response[:attestation_object]),
345-
client_data_json: Base64.strict_decode64(response[:client_data_json])
345+
attestation_object: WebAuthn::Encoders::Base64Encoder.decode(response[:attestation_object]),
346+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(response[:client_data_json])
346347
)
347348
end
348349

@@ -371,15 +372,15 @@
371372

372373
context "when android-key attestation" do
373374
let(:original_challenge) do
374-
Base64.urlsafe_decode64(seeds[:android_key_direct][:credential_creation_options][:challenge])
375+
WebAuthn::Encoders::Base64UrlEncoder.decode(seeds[:android_key_direct][:credential_creation_options][:challenge])
375376
end
376377

377378
let(:attestation_response) do
378379
response = seeds[:android_key_direct][:authenticator_attestation_response]
379380

380381
WebAuthn::AuthenticatorAttestationResponse.new(
381-
attestation_object: Base64.urlsafe_decode64(response[:attestation_object]),
382-
client_data_json: Base64.urlsafe_decode64(response[:client_data_json])
382+
attestation_object: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:attestation_object]),
383+
client_data_json: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:client_data_json])
383384
)
384385
end
385386

@@ -468,15 +469,15 @@
468469
let(:origin) { seeds[:macbook_touch_id][:origin] }
469470

470471
let(:original_challenge) do
471-
Base64.urlsafe_decode64(seeds[:macbook_touch_id][:credential_creation_options][:challenge])
472+
WebAuthn::Encoders::Base64UrlEncoder.decode(seeds[:macbook_touch_id][:credential_creation_options][:challenge])
472473
end
473474

474475
let(:attestation_response) do
475476
response = seeds[:macbook_touch_id][:authenticator_attestation_response]
476477

477478
WebAuthn::AuthenticatorAttestationResponse.new(
478-
attestation_object: Base64.urlsafe_decode64(response[:attestation_object]),
479-
client_data_json: Base64.urlsafe_decode64(response[:client_data_json])
479+
attestation_object: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:attestation_object]),
480+
client_data_json: WebAuthn::Encoders::Base64UrlEncoder.decode(response[:client_data_json])
480481
)
481482
end
482483

@@ -766,7 +767,7 @@
766767

767768
describe "attestation statement verification" do
768769
let(:original_challenge) do
769-
Base64.strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
770+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:security_key_direct][:credential_creation_options][:challenge])
770771
end
771772

772773
let(:origin) { "http://localhost:3000" }
@@ -775,8 +776,8 @@
775776
response = seeds[:security_key_direct][:authenticator_attestation_response]
776777

777778
WebAuthn::AuthenticatorAttestationResponse.new(
778-
attestation_object: Base64.strict_decode64(response[:attestation_object]),
779-
client_data_json: Base64.strict_decode64(response[:client_data_json])
779+
attestation_object: WebAuthn::Encoders::Base64Encoder.decode(response[:attestation_object]),
780+
client_data_json: WebAuthn::Encoders::Base64Encoder.decode(response[:client_data_json])
780781
)
781782
end
782783

spec/webauthn/public_key_credential_with_assertion_spec.rb

+8-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
require "spec_helper"
44

5-
require "base64"
65
require "securerandom"
76
require "webauthn/authenticator_assertion_response"
87
require "webauthn/configuration"
@@ -13,16 +12,16 @@
1312
RSpec.describe "PublicKeyCredentialWithAssertion" do
1413
describe "#verify" do
1514
let(:client) { WebAuthn::FakeClient.new(origin, encoding: false) }
16-
let(:challenge) { Base64.urlsafe_encode64(raw_challenge) }
15+
let(:challenge) { WebAuthn::Encoders::Base64UrlEncoder.encode(raw_challenge) }
1716
let(:raw_challenge) { fake_challenge }
1817
let(:origin) { fake_origin }
1918

2019
let!(:credential) { create_credential(client: client) }
2120
let(:credential_raw_id) { credential[0] }
22-
let(:credential_id) { Base64.urlsafe_encode64(credential_raw_id) }
21+
let(:credential_id) { WebAuthn::Encoders::Base64UrlEncoder.encode(credential_raw_id) }
2322
let(:credential_type) { "public-key" }
2423
let(:credential_authenticator_attachment) { 'platform' }
25-
let(:credential_public_key) { Base64.urlsafe_encode64(credential[1]) }
24+
let(:credential_public_key) { WebAuthn::Encoders::Base64UrlEncoder.encode(credential[1]) }
2625
let(:credential_sign_count) { credential[2] }
2726

2827
let(:assertion_response) do
@@ -105,7 +104,7 @@
105104
end
106105

107106
context "because it is not the base64url of raw id" do
108-
let(:credential_id) { Base64.urlsafe_encode64(credential_raw_id + "a") }
107+
let(:credential_id) { WebAuthn::Encoders::Base64UrlEncoder.encode(credential_raw_id + "a") }
109108

110109
it "fails" do
111110
expect do
@@ -132,7 +131,7 @@
132131
end
133132

134133
context "when challenge is invalid" do
135-
let(:challenge) { Base64.urlsafe_encode64("another challenge") }
134+
let(:challenge) { WebAuthn::Encoders::Base64UrlEncoder.encode("another challenge") }
136135

137136
it "fails" do
138137
expect do
@@ -273,7 +272,9 @@
273272

274273
let(:assertion_response) do
275274
WebAuthn::AuthenticatorAssertionResponse.new(
276-
**seeds[:u2f_migration][:assertion][:response].transform_values { |v| Base64.strict_decode64(v) }
275+
**seeds[:u2f_migration][:assertion][:response].transform_values do |v|
276+
WebAuthn::Encoders::Base64Encoder.decode(v)
277+
end
277278
)
278279
end
279280

spec/webauthn/public_key_credential_with_attestation_spec.rb

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
require "spec_helper"
44

5-
require "base64"
65
require "securerandom"
76
require "webauthn/authenticator_attestation_response"
87
require "webauthn/configuration"
@@ -21,7 +20,7 @@
2120
end
2221

2322
let(:type) { "public-key" }
24-
let(:id) { Base64.urlsafe_encode64(raw_id) }
23+
let(:id) { WebAuthn::Encoders::Base64UrlEncoder.encode(raw_id) }
2524
let(:raw_id) { SecureRandom.random_bytes(16) }
2625
let(:authenticator_attachment) { 'platform' }
2726

@@ -35,7 +34,7 @@
3534
end
3635

3736
let(:client) { WebAuthn::FakeClient.new(origin, encoding: false) }
38-
let(:challenge) { Base64.urlsafe_encode64(raw_challenge) }
37+
let(:challenge) { WebAuthn::Encoders::Base64UrlEncoder.encode(raw_challenge) }
3938
let(:raw_challenge) { fake_challenge }
4039
let(:origin) { fake_origin }
4140

@@ -79,7 +78,7 @@
7978
end
8079

8180
context "because it is not the base64url of raw id" do
82-
let(:id) { Base64.urlsafe_encode64(raw_id + "a") }
81+
let(:id) { WebAuthn::Encoders::Base64UrlEncoder.encode(raw_id + "a") }
8382

8483
it "fails" do
8584
expect { public_key_credential.verify(challenge) }.to raise_error(RuntimeError)
@@ -98,7 +97,7 @@
9897
context "when challenge value is invalid" do
9998
it "fails" do
10099
expect {
101-
public_key_credential.verify(Base64.urlsafe_encode64("another challenge"))
100+
public_key_credential.verify(WebAuthn::Encoders::Base64UrlEncoder.encode("another challenge"))
102101
}.to raise_error(WebAuthn::ChallengeVerificationError)
103102
end
104103
end

spec/webauthn/public_key_spec.rb

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
RSpec.describe "PublicKey" do
1111
let(:uncompressed_point_public_key) do
12-
Base64.strict_decode64(seeds[:u2f_migration][:stored_credential][:public_key])
12+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:u2f_migration][:stored_credential][:public_key])
1313
end
1414
let(:cose_public_key) do
15-
Base64.urlsafe_decode64(
15+
WebAuthn::Encoders::Base64UrlEncoder.decode(
1616
"pQECAyYgASFYIPJKd_-Rl0QtQwbLggjGC_EbUFIMriCkdc2yuaukkBuNIlggaBsBjCwnMzFL7OUGJNm4b-HVpFNUa_NbsHGARuYKHfU"
1717
)
1818
end
@@ -94,14 +94,14 @@
9494

9595
context "when signature was signed with public key" do
9696
let(:signature) do
97-
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:signature])
97+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:u2f_migration][:assertion][:response][:signature])
9898
end
9999
let(:authenticator_data) do
100-
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:authenticator_data])
100+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:u2f_migration][:assertion][:response][:authenticator_data])
101101
end
102102
let(:client_data_hash) do
103103
WebAuthn::ClientData.new(
104-
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:client_data_json])
104+
WebAuthn::Encoders::Base64Encoder.decode(seeds[:u2f_migration][:assertion][:response][:client_data_json])
105105
).hash
106106
end
107107
let(:verification_data) { authenticator_data + client_data_hash }

0 commit comments

Comments
 (0)