127 lines
5.9 KiB
C++
127 lines
5.9 KiB
C++
#include "pch.h"
|
|
#include "MainPage.xaml.h"
|
|
#include "PluginRegistrationManager.h"
|
|
#include <CorError.h>
|
|
|
|
namespace winrt::PasskeyManager::implementation {
|
|
PluginRegistrationManager::PluginRegistrationManager() :
|
|
m_pluginRegistered(false),
|
|
m_initialized(false),
|
|
m_pluginState(EXPERIMENTAL_PLUGIN_AUTHENTICATOR_STATE::PluginAuthenticatorState_Unknown)
|
|
{
|
|
Initialize();
|
|
m_webAuthnDll.reset(LoadLibraryExW(L"webauthn.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
|
|
}
|
|
|
|
PluginRegistrationManager::~PluginRegistrationManager()
|
|
{
|
|
}
|
|
|
|
HRESULT PluginRegistrationManager::Initialize()
|
|
{
|
|
HRESULT hr = RefreshPluginState();
|
|
RETURN_HR_IF_EXPECTED(S_OK, RefreshPluginState() == NTE_NOT_FOUND);
|
|
RETURN_HR(hr);
|
|
}
|
|
|
|
HRESULT PluginRegistrationManager::RegisterPlugin()
|
|
{
|
|
// Get the function pointer of WebAuthNPluginAddAuthenticator
|
|
auto webAuthNPluginAddAuthenticator = GetProcAddressByFunctionDeclaration(
|
|
m_webAuthnDll.get(),
|
|
EXPERIMENTAL_WebAuthNPluginAddAuthenticator);
|
|
RETURN_HR_IF_NULL(E_FAIL, webAuthNPluginAddAuthenticator);
|
|
|
|
/*
|
|
* This section creates a sample authenticatorInfo blob to include in the registration
|
|
* request. This blob must CBOR encoded using the format defined
|
|
* in https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetInfo
|
|
*
|
|
* 'AAGUID' maybe used to fetch information about the authenticator from the FIDO Metadata Service and other sources.
|
|
* Refer: https://fidoalliance.org/metadata/
|
|
*
|
|
* 'extensions' field is used to perform feature detection on the authenticator
|
|
* and maybe used to determine if the authenticator is filtered out.
|
|
*/
|
|
std::string tempAaguidStr{ c_pluginAaguid };
|
|
tempAaguidStr.erase(std::remove(tempAaguidStr.begin(), tempAaguidStr.end(), L'-'), tempAaguidStr.end());
|
|
std::transform(tempAaguidStr.begin(), tempAaguidStr.end(), tempAaguidStr.begin(), [](unsigned char c) { return static_cast<char>(std::toupper(c)); });
|
|
// The following hex strings represent the encoding of
|
|
// {1: ["FIDO_2_0", "FIDO_2_1"], 2: ["prf", "hmac-secret"], 3: h'/* AAGUID */', 4: {"rk": true, "up": true, "uv": true},
|
|
// 9: ["internal"], 10: [{"alg": -7, "type": "public-key"}]}
|
|
std::string authenticatorInfoStrPart1 = "A60182684649444F5F325F30684649444F5F325F310282637072666B686D61632D7365637265740350";
|
|
std::string authenticatorInfoStrPart2 = "04A362726BF5627570F5627576F5098168696E7465726E616C0A81A263616C672664747970656A7075626C69632D6B6579";
|
|
std::string fullAuthenticatorInfoStr = authenticatorInfoStrPart1 + tempAaguidStr + authenticatorInfoStrPart2;
|
|
std::vector<BYTE> authenticatorInfo = hexStringToBytes(fullAuthenticatorInfoStr);
|
|
|
|
// Validate that c_pluginClsid is a valid CLSID
|
|
CLSID CLSID_ContosoPluginAuthenticator;
|
|
RETURN_IF_FAILED(CLSIDFromString(c_pluginClsid, &CLSID_ContosoPluginAuthenticator));
|
|
|
|
EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS addOptions{};
|
|
addOptions.pwszAuthenticatorName = c_pluginName;
|
|
addOptions.pwszPluginRpId = c_pluginRpId;
|
|
addOptions.pwszPluginClsId = c_pluginClsid;
|
|
addOptions.pbAuthenticatorInfo = authenticatorInfo.data();
|
|
addOptions.cbAuthenticatorInfo = static_cast<DWORD>(authenticatorInfo.size());
|
|
|
|
EXPERIMENTAL_PWEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE addResponse;
|
|
RETURN_IF_FAILED(webAuthNPluginAddAuthenticator(&addOptions, &addResponse));
|
|
|
|
// The response from plugin contains the public key used to sign plugin operation requests. Stash it for later use.
|
|
wil::unique_hkey hKey;
|
|
RETURN_IF_WIN32_ERROR(RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
c_pluginRegistryPath,
|
|
0,
|
|
nullptr,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
nullptr,
|
|
&hKey,
|
|
nullptr));
|
|
|
|
RETURN_IF_WIN32_ERROR(RegSetValueEx(
|
|
hKey.get(),
|
|
c_windowsPluginRequestSigningKeyRegKeyName,
|
|
0,
|
|
REG_BINARY,
|
|
addResponse->pbOpSignPubKey,
|
|
addResponse->cbOpSignPubKey));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT PluginRegistrationManager::UnregisterPlugin()
|
|
{
|
|
// Get the function pointer of WebAuthNPluginRemoveAuthenticator
|
|
auto webAuthNPluginRemoveAuthenticator = GetProcAddressByFunctionDeclaration(
|
|
m_webAuthnDll.get(),
|
|
EXPERIMENTAL_WebAuthNPluginRemoveAuthenticator);
|
|
RETURN_HR_IF_NULL(E_FAIL, webAuthNPluginRemoveAuthenticator);
|
|
|
|
RETURN_HR(webAuthNPluginRemoveAuthenticator(c_pluginClsid));
|
|
}
|
|
|
|
HRESULT PluginRegistrationManager::RefreshPluginState()
|
|
{
|
|
// Reset the plugin state and registration status
|
|
m_pluginRegistered = false;
|
|
m_pluginState = EXPERIMENTAL_PLUGIN_AUTHENTICATOR_STATE::PluginAuthenticatorState_Unknown;
|
|
|
|
// Get handle to EXPERIMENTAL_WebAuthNPluginGetAuthenticatorState which takes in a GUID and returns EXPERIMENTAL_PLUGIN_AUTHENTICATOR_STATE
|
|
auto webAuthNPluginGetAuthenticatorState = GetProcAddressByFunctionDeclaration(
|
|
m_webAuthnDll.get(),
|
|
EXPERIMENTAL_WebAuthNPluginGetAuthenticatorState);
|
|
RETURN_HR_IF_NULL(E_FAIL, webAuthNPluginGetAuthenticatorState);
|
|
|
|
// Get the plugin state
|
|
EXPERIMENTAL_PLUGIN_AUTHENTICATOR_STATE localPluginState;
|
|
RETURN_IF_FAILED(webAuthNPluginGetAuthenticatorState(c_pluginClsid, &localPluginState));
|
|
|
|
// If the EXPERIMENTAL_WebAuthNPluginGetAuthenticatorState function succeeded, that indicates the plugin is registered and localPluginState is the valid plugin state
|
|
m_pluginRegistered = true;
|
|
m_pluginState = localPluginState;
|
|
return S_OK;
|
|
}
|
|
}
|