Skip to content

Commit

Permalink
fido/win: gate Windows WebAuthn API availability on a minimum version
Browse files Browse the repository at this point in the history
There are versions of webauthn.dll that ship without BLE support. On
platforms where that is the case, direct access to FIDO token is not
blocked by the OS and so we don't want to integrate with webauthn.dll
there. This changes WinWebAuthnApi to call WebAuthNGetApiVersion on
initialization and mark the API as unavailable if the version number is
 not at least the current version (1).

The check may be overridden by a flag while we wait for
WebAuthNGetApiVersion function to ship.

Bug: 898718
Change-Id: Ic20e55a416d858214b9f444031f4700567933eb4
Reviewed-on: https://chromium-review.googlesource.com/c/1327885
Commit-Queue: Martin Kreichgauer <martinkr@chromium.org>
Reviewed-by: Adam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607005}
  • Loading branch information
Martin Kreichgauer authored and Commit Bot committed Nov 9, 2018
1 parent 504013e commit dfbcc8a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 17 deletions.
8 changes: 8 additions & 0 deletions device/fido/features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ namespace device {
// native WebAuthentication API, where available.
const base::Feature kWebAuthUseNativeWinApi{"WebAuthenticationUseNativeWinApi",
base::FEATURE_DISABLED_BY_DEFAULT};

// If true, the minimum API version check for integration with the native
// Windows WebAuthentication API is disabled. This is an interim solution for
// for manual testing while we await the release of a DLL that implements the
// version check.
const base::Feature kWebAuthDisableWinApiVersionCheckForTesting{
"WebAuthenticationDisableWinApiVersionCheckForTesting",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_WIN)

extern const base::Feature kWebAuthProxyCryptotoken{
Expand Down
3 changes: 3 additions & 0 deletions device/fido/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace device {
#if defined(OS_WIN)
COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthUseNativeWinApi;

COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthDisableWinApiVersionCheckForTesting;
#endif // defined(OS_WIN)

// Controls the proxying of Cryptotoken requests through WebAuthn.
Expand Down
61 changes: 44 additions & 17 deletions device/fido/win/webauthn_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@

#include "device/fido/win/webauthn_api.h"

#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/native_library.h"
#include "base/no_destructor.h"
#include "device/fido/features.h"

namespace device {

// We do not integrate with older API versions of webauthn.dll because they
// don't support BLE and direct device access to USB and BLE FIDO devices is
// not yet blocked on those platforms.
constexpr uint32_t kMinWinWebAuthnApiVersion = WEBAUTHN_API_VERSION_1;

// WinWebAuthnApiImpl is the default implementation of WinWebAuthnApi, which
// attempts to load webauthn.dll on intialization.
class WinWebAuthnApiImpl : public WinWebAuthnApi {
Expand All @@ -26,32 +33,48 @@ class WinWebAuthnApiImpl : public WinWebAuthnApi {
#define BIND_FN(fn_pointer, lib_handle, fn_name) \
DCHECK(!fn_pointer); \
fn_pointer = reinterpret_cast<decltype(fn_pointer)>( \
GetProcAddress(lib_handle, fn_name)); \
if (!fn_pointer) { \
DLOG(ERROR) << "failed to bind " << fn_name; \
return; \
GetProcAddress(lib_handle, fn_name));

#define BIND_FN_OR_RETURN(fn_pointer, lib_handle, fn_name) \
BIND_FN(fn_pointer, lib_handle, fn_name); \
if (!fn_pointer) { \
DLOG(ERROR) << "failed to bind " << fn_name; \
return; \
}

BIND_FN(is_user_verifying_platform_authenticator_available_, webauthn_dll,
"WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable");
BIND_FN(authenticator_make_credential_, webauthn_dll,
"WebAuthNAuthenticatorMakeCredential");
BIND_FN(authenticator_get_assertion_, webauthn_dll,
"WebAuthNAuthenticatorGetAssertion");
BIND_FN(cancel_current_operation_, webauthn_dll,
"WebAuthNCancelCurrentOperation");
BIND_FN(get_error_name_, webauthn_dll, "WebAuthNGetErrorName");
BIND_FN(free_credential_attestation_, webauthn_dll,
"WebAuthNFreeCredentialAttestation");
BIND_FN(free_assertion_, webauthn_dll, "WebAuthNFreeAssertion");
BIND_FN_OR_RETURN(is_user_verifying_platform_authenticator_available_,
webauthn_dll,
"WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable");
BIND_FN_OR_RETURN(authenticator_make_credential_, webauthn_dll,
"WebAuthNAuthenticatorMakeCredential");
BIND_FN_OR_RETURN(authenticator_get_assertion_, webauthn_dll,
"WebAuthNAuthenticatorGetAssertion");
BIND_FN_OR_RETURN(cancel_current_operation_, webauthn_dll,
"WebAuthNCancelCurrentOperation");
BIND_FN_OR_RETURN(get_error_name_, webauthn_dll, "WebAuthNGetErrorName");
BIND_FN_OR_RETURN(free_credential_attestation_, webauthn_dll,
"WebAuthNFreeCredentialAttestation");
BIND_FN_OR_RETURN(free_assertion_, webauthn_dll, "WebAuthNFreeAssertion");

is_bound_ = true;

// Determine the API version of webauthn.dll. There is a version currently
// shipping with Windows RS5 from before WebAuthNGetApiVersionNumber was
// added (i.e., before WEBAUTHN_API_VERSION_1). Therefore we allow this
// function to be missing.
BIND_FN(get_api_version_number_, webauthn_dll,
"WebAuthNGetApiVersionNumber");
api_version_ = get_api_version_number_ ? get_api_version_number_() : 0;
}

~WinWebAuthnApiImpl() override {}

// WinWebAuthnApi:
bool IsAvailable() const override { return is_bound_; }
bool IsAvailable() const override {
return is_bound_ && (api_version_ >= kMinWinWebAuthnApiVersion ||
base::FeatureList::IsEnabled(
kWebAuthDisableWinApiVersionCheckForTesting));
}

HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(BOOL* result) override {
DCHECK(is_bound_);
Expand Down Expand Up @@ -113,7 +136,11 @@ class WinWebAuthnApiImpl : public WinWebAuthnApi {
nullptr;
decltype(&WebAuthNFreeAssertion) free_assertion_ = nullptr;

// This method is not available in all versions of webauthn.dll.
decltype(&WebAuthNGetApiVersionNumber) get_api_version_number_ = nullptr;

bool is_bound_ = false;
uint32_t api_version_ = 0;
};

static WinWebAuthnApi* kDefaultForTesting = nullptr;
Expand Down

0 comments on commit dfbcc8a

Please sign in to comment.