Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use local base64_ functions #423

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/webauthn/encoder.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require "base64"

module WebAuthn
def self.standard_encoder
@standard_encoder ||= Encoder.new
Expand Down
20 changes: 17 additions & 3 deletions lib/webauthn/u2f_migrator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,36 @@ def attestation_type
end

def attestation_trust_path
@attestation_trust_path ||= [OpenSSL::X509::Certificate.new(Base64.strict_decode64(@certificate))]
@attestation_trust_path ||= [OpenSSL::X509::Certificate.new(base64_strict_decode64(@certificate))]
end

private

def base64_strict_decode64(data)
data.unpack1("m0")
end

def base64_urlsafe_decode64(data)
if !data.end_with?("=") && data.length % 4 != 0
data = data.ljust((data.length + 3) & ~3, "=")
data.tr!("-_", "+/")
else
data = data.tr("-_", "+/")
end
data.unpack1("m0")
end

# https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#u2f-authenticatorMakeCredential-interoperability
# Let credentialId be a credentialIdLength byte array initialized with CTAP1/U2F response key handle bytes.
def credential_id
Base64.urlsafe_decode64(@key_handle)
base64_urlsafe_decode64(@key_handle)
end

# Let x9encodedUserPublicKey be the user public key returned in the U2F registration response message [U2FRawMsgs].
# Let coseEncodedCredentialPublicKey be the result of converting x9encodedUserPublicKey’s value from ANS X9.62 /
# Sec-1 v2 uncompressed curve point representation [SEC1V2] to COSE_Key representation ([RFC8152] Section 7).
def credential_cose_key
decoded_public_key = Base64.strict_decode64(@public_key)
decoded_public_key = base64_strict_decode64(@public_key)
if WebAuthn::AttestationStatement::FidoU2f::PublicKey.uncompressed_point?(decoded_public_key)
COSE::Key::EC2.new(
alg: COSE::Algorithm.by_name("ES256").id,
Expand Down
24 changes: 24 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,27 @@ def fake_certificate_chain_validation_time(attestation_statement, time)
store
end
end

def base64_strict_encode64(data)
[data].pack("m0")
end

def base64_strict_decode64(data)
data.unpack1("m0")
end

def base64_urlsafe_decode64(data)
if !data.end_with?("=") && data.length % 4 != 0
data = data.ljust((data.length + 3) & ~3, "=")
data.tr!("-_", "+/")
else
data = data.tr("-_", "+/")
end
data.unpack1("m0")
end

def base64_urlsafe_encode64(data)
str = base64_strict_encode64(data)
str.tr!("+/", "-_")
str
end
6 changes: 3 additions & 3 deletions spec/webauthn/attestation_statement/android_safetynet_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
payload,
attestation_key,
"RS256",
x5c: [Base64.strict_encode64(leaf_certificate.to_der)]
x5c: [base64_strict_encode64(leaf_certificate.to_der)]
)
end

Expand All @@ -26,7 +26,7 @@
end
let(:timestamp) { Time.now }
let(:cts_profile_match) { true }
let(:nonce) { Base64.strict_encode64(OpenSSL::Digest::SHA256.digest(authenticator_data_bytes + client_data_hash)) }
let(:nonce) { base64_strict_encode64(OpenSSL::Digest::SHA256.digest(authenticator_data_bytes + client_data_hash)) }
let(:attestation_key) { create_rsa_key }

let(:leaf_certificate) do
Expand Down Expand Up @@ -63,7 +63,7 @@
end

context "when nonce is not set to the base64 of the SHA256 of authData + clientDataHash" do
let(:nonce) { Base64.strict_encode64(OpenSSL::Digest.digest("SHA256", "something else")) }
let(:nonce) { base64_strict_encode64(OpenSSL::Digest.digest("SHA256", "something else")) }

it "returns false" do
expect(statement.valid?(authenticator_data, client_data_hash)).to be_falsy
Expand Down
8 changes: 4 additions & 4 deletions spec/webauthn/authenticator_assertion_response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,12 @@
let(:assertion_data) { seeds[:u2f_migration][:assertion] }
let(:assertion_response) do
WebAuthn::AuthenticatorAssertionResponse.new(
client_data_json: Base64.strict_decode64(assertion_data[:response][:client_data_json]),
authenticator_data: Base64.strict_decode64(assertion_data[:response][:authenticator_data]),
signature: Base64.strict_decode64(assertion_data[:response][:signature])
client_data_json: base64_strict_decode64(assertion_data[:response][:client_data_json]),
authenticator_data: base64_strict_decode64(assertion_data[:response][:authenticator_data]),
signature: base64_strict_decode64(assertion_data[:response][:signature])
)
end
let(:original_challenge) { Base64.strict_decode64(assertion_data[:challenge]) }
let(:original_challenge) { base64_strict_decode64(assertion_data[:challenge]) }

context "when correct FIDO AppID is given as rp_id" do
it "verifies" do
Expand Down
48 changes: 24 additions & 24 deletions spec/webauthn/authenticator_attestation_response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

context "when fido-u2f attestation" do
let(:original_challenge) do
Base64.strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
base64_strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
end

let(:origin) { "http://localhost:3000" }
Expand All @@ -59,8 +59,8 @@
response = seeds[:security_key_direct][:authenticator_attestation_response]

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -98,7 +98,7 @@
let(:origin) { "https://localhost:13010" }

let(:original_challenge) do
Base64.strict_decode64(
base64_strict_decode64(
seeds[:security_key_packed_self][:credential_creation_options][:challenge]
)
end
Expand All @@ -107,8 +107,8 @@
response = seeds[:security_key_packed_self][:authenticator_attestation_response]

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -140,7 +140,7 @@
let(:origin) { "http://localhost:3000" }

let(:original_challenge) do
Base64.strict_decode64(
base64_strict_decode64(
seeds[:security_key_packed_x5c][:credential_creation_options][:challenge]
)
end
Expand All @@ -149,8 +149,8 @@
response = seeds[:security_key_packed_x5c][:authenticator_attestation_response]

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -185,14 +185,14 @@
context "when TPM attestation" do
let(:origin) { seeds[:tpm][:origin] }
let(:time) { Time.utc(2019, 8, 13, 22, 6) }
let(:challenge) { Base64.strict_decode64(seeds[:tpm][:credential_creation_options][:challenge]) }
let(:challenge) { base64_strict_decode64(seeds[:tpm][:credential_creation_options][:challenge]) }

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

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -244,15 +244,15 @@
let(:origin) { "https://7f41ac45.ngrok.io" }

let(:original_challenge) do
Base64.strict_decode64(seeds[:android_safetynet_direct][:credential_creation_options][:challenge])
base64_strict_decode64(seeds[:android_safetynet_direct][:credential_creation_options][:challenge])
end

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

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -288,15 +288,15 @@
let(:origin) { seeds[:android_key_direct][:origin] }

let(:original_challenge) do
Base64.urlsafe_decode64(seeds[:android_key_direct][:credential_creation_options][:challenge])
base64_urlsafe_decode64(seeds[:android_key_direct][:credential_creation_options][:challenge])
end

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

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.urlsafe_decode64(response[:attestation_object]),
client_data_json: Base64.urlsafe_decode64(response[:client_data_json])
attestation_object: base64_urlsafe_decode64(response[:attestation_object]),
client_data_json: base64_urlsafe_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -332,15 +332,15 @@
let(:origin) { seeds[:macbook_touch_id][:origin] }

let(:original_challenge) do
Base64.urlsafe_decode64(seeds[:macbook_touch_id][:credential_creation_options][:challenge])
base64_urlsafe_decode64(seeds[:macbook_touch_id][:credential_creation_options][:challenge])
end

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

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.urlsafe_decode64(response[:attestation_object]),
client_data_json: Base64.urlsafe_decode64(response[:client_data_json])
attestation_object: base64_urlsafe_decode64(response[:attestation_object]),
client_data_json: base64_urlsafe_decode64(response[:client_data_json])
)
end

Expand Down Expand Up @@ -546,7 +546,7 @@

describe "attestation statement verification" do
let(:original_challenge) do
Base64.strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
base64_strict_decode64(seeds[:security_key_direct][:credential_creation_options][:challenge])
end

let(:origin) { "http://localhost:3000" }
Expand All @@ -555,8 +555,8 @@
response = seeds[:security_key_direct][:authenticator_attestation_response]

WebAuthn::AuthenticatorAttestationResponse.new(
attestation_object: Base64.strict_decode64(response[:attestation_object]),
client_data_json: Base64.strict_decode64(response[:client_data_json])
attestation_object: base64_strict_decode64(response[:attestation_object]),
client_data_json: base64_strict_decode64(response[:client_data_json])
)
end

Expand Down
12 changes: 6 additions & 6 deletions spec/webauthn/public_key_credential_with_assertion_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
RSpec.describe "PublicKeyCredentialWithAssertion" do
describe "#verify" do
let(:client) { WebAuthn::FakeClient.new(origin, encoding: false) }
let(:challenge) { Base64.urlsafe_encode64(raw_challenge) }
let(:challenge) { base64_urlsafe_encode64(raw_challenge) }
let(:raw_challenge) { fake_challenge }
let(:origin) { fake_origin }

let!(:credential) { create_credential(client: client) }
let(:credential_raw_id) { credential[0] }
let(:credential_id) { Base64.urlsafe_encode64(credential_raw_id) }
let(:credential_id) { base64_urlsafe_encode64(credential_raw_id) }
let(:credential_type) { "public-key" }
let(:credential_authenticator_attachment) { 'platform' }
let(:credential_public_key) { Base64.urlsafe_encode64(credential[1]) }
let(:credential_public_key) { base64_urlsafe_encode64(credential[1]) }
let(:credential_sign_count) { credential[2] }

let(:assertion_response) do
Expand Down Expand Up @@ -105,7 +105,7 @@
end

context "because it is not the base64url of raw id" do
let(:credential_id) { Base64.urlsafe_encode64(credential_raw_id + "a") }
let(:credential_id) { base64_urlsafe_encode64(credential_raw_id + "a") }

it "fails" do
expect do
Expand All @@ -132,7 +132,7 @@
end

context "when challenge is invalid" do
let(:challenge) { Base64.urlsafe_encode64("another challenge") }
let(:challenge) { base64_urlsafe_encode64("another challenge") }

it "fails" do
expect do
Expand Down Expand Up @@ -273,7 +273,7 @@

let(:assertion_response) do
WebAuthn::AuthenticatorAssertionResponse.new(
**seeds[:u2f_migration][:assertion][:response].transform_values { |v| Base64.strict_decode64(v) }
**seeds[:u2f_migration][:assertion][:response].transform_values { |v| base64_strict_decode64(v) }
)
end

Expand Down
8 changes: 4 additions & 4 deletions spec/webauthn/public_key_credential_with_attestation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
end

let(:type) { "public-key" }
let(:id) { Base64.urlsafe_encode64(raw_id) }
let(:id) { base64_urlsafe_encode64(raw_id) }
let(:raw_id) { SecureRandom.random_bytes(16) }
let(:authenticator_attachment) { 'platform' }

Expand All @@ -35,7 +35,7 @@
end

let(:client) { WebAuthn::FakeClient.new(origin, encoding: false) }
let(:challenge) { Base64.urlsafe_encode64(raw_challenge) }
let(:challenge) { base64_urlsafe_encode64(raw_challenge) }
let(:raw_challenge) { fake_challenge }
let(:origin) { fake_origin }

Expand Down Expand Up @@ -79,7 +79,7 @@
end

context "because it is not the base64url of raw id" do
let(:id) { Base64.urlsafe_encode64(raw_id + "a") }
let(:id) { base64_urlsafe_encode64(raw_id + "a") }

it "fails" do
expect { public_key_credential.verify(challenge) }.to raise_error(RuntimeError)
Expand All @@ -98,7 +98,7 @@
context "when challenge value is invalid" do
it "fails" do
expect {
public_key_credential.verify(Base64.urlsafe_encode64("another challenge"))
public_key_credential.verify(base64_urlsafe_encode64("another challenge"))
}.to raise_error(WebAuthn::ChallengeVerificationError)
end
end
Expand Down
10 changes: 5 additions & 5 deletions spec/webauthn/public_key_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

RSpec.describe "PublicKey" do
let(:uncompressed_point_public_key) do
Base64.strict_decode64(seeds[:u2f_migration][:stored_credential][:public_key])
base64_strict_decode64(seeds[:u2f_migration][:stored_credential][:public_key])
end
let(:cose_public_key) do
Base64.urlsafe_decode64(
base64_urlsafe_decode64(
"pQECAyYgASFYIPJKd_-Rl0QtQwbLggjGC_EbUFIMriCkdc2yuaukkBuNIlggaBsBjCwnMzFL7OUGJNm4b-HVpFNUa_NbsHGARuYKHfU"
)
end
Expand Down Expand Up @@ -94,14 +94,14 @@

context "when signature was signed with public key" do
let(:signature) do
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:signature])
base64_strict_decode64(seeds[:u2f_migration][:assertion][:response][:signature])
end
let(:authenticator_data) do
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:authenticator_data])
base64_strict_decode64(seeds[:u2f_migration][:assertion][:response][:authenticator_data])
end
let(:client_data_hash) do
WebAuthn::ClientData.new(
Base64.strict_decode64(seeds[:u2f_migration][:assertion][:response][:client_data_json])
base64_strict_decode64(seeds[:u2f_migration][:assertion][:response][:client_data_json])
).hash
end
let(:verification_data) { authenticator_data + client_data_hash }
Expand Down
Loading