aboutsummaryrefslogtreecommitdiff
path: root/contrib/libfido2/src/winhello.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libfido2/src/winhello.c')
-rw-r--r--contrib/libfido2/src/winhello.c574
1 files changed, 329 insertions, 245 deletions
diff --git a/contrib/libfido2/src/winhello.c b/contrib/libfido2/src/winhello.c
index 0fe5b4cfe4c7..efc7dc22f851 100644
--- a/contrib/libfido2/src/winhello.c
+++ b/contrib/libfido2/src/winhello.c
@@ -1,16 +1,27 @@
/*
- * Copyright (c) 2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2021-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/types.h>
#include <stdlib.h>
#include <windows.h>
-#include <webauthn.h>
#include "fido.h"
+#include "webauthn.h"
+
+#ifndef NTE_INVALID_PARAMETER
+#define NTE_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80090027)
+#endif
+#ifndef NTE_NOT_SUPPORTED
+#define NTE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80090029)
+#endif
+#ifndef NTE_DEVICE_NOT_FOUND
+#define NTE_DEVICE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090035)
+#endif
#define MAXCHARS 128
#define MAXCREDS 128
@@ -40,6 +51,108 @@ struct winhello_cred {
wchar_t *display_name;
};
+typedef DWORD WINAPI webauthn_get_api_version_t(void);
+typedef PCWSTR WINAPI webauthn_strerr_t(HRESULT);
+typedef HRESULT WINAPI webauthn_get_assert_t(HWND, LPCWSTR,
+ PCWEBAUTHN_CLIENT_DATA,
+ PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS,
+ PWEBAUTHN_ASSERTION *);
+typedef HRESULT WINAPI webauthn_make_cred_t(HWND,
+ PCWEBAUTHN_RP_ENTITY_INFORMATION,
+ PCWEBAUTHN_USER_ENTITY_INFORMATION,
+ PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS,
+ PCWEBAUTHN_CLIENT_DATA,
+ PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS,
+ PWEBAUTHN_CREDENTIAL_ATTESTATION *);
+typedef void WINAPI webauthn_free_assert_t(PWEBAUTHN_ASSERTION);
+typedef void WINAPI webauthn_free_attest_t(PWEBAUTHN_CREDENTIAL_ATTESTATION);
+
+static TLS BOOL webauthn_loaded;
+static TLS HMODULE webauthn_handle;
+static TLS webauthn_get_api_version_t *webauthn_get_api_version;
+static TLS webauthn_strerr_t *webauthn_strerr;
+static TLS webauthn_get_assert_t *webauthn_get_assert;
+static TLS webauthn_make_cred_t *webauthn_make_cred;
+static TLS webauthn_free_assert_t *webauthn_free_assert;
+static TLS webauthn_free_attest_t *webauthn_free_attest;
+
+static int
+webauthn_load(void)
+{
+ DWORD n = 1;
+
+ if (webauthn_loaded || webauthn_handle != NULL) {
+ fido_log_debug("%s: already loaded", __func__);
+ return -1;
+ }
+ if ((webauthn_handle = LoadLibrary(TEXT("webauthn.dll"))) == NULL) {
+ fido_log_debug("%s: LoadLibrary", __func__);
+ return -1;
+ }
+
+ if ((webauthn_get_api_version =
+ (webauthn_get_api_version_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNGetApiVersionNumber")) == NULL) {
+ fido_log_debug("%s: WebAuthNGetApiVersionNumber", __func__);
+ /* WebAuthNGetApiVersionNumber might not exist */
+ }
+ if (webauthn_get_api_version != NULL &&
+ (n = webauthn_get_api_version()) < 1) {
+ fido_log_debug("%s: unsupported api %lu", __func__, (u_long)n);
+ goto fail;
+ }
+ fido_log_debug("%s: api version %lu", __func__, (u_long)n);
+ if ((webauthn_strerr =
+ (webauthn_strerr_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNGetErrorName")) == NULL) {
+ fido_log_debug("%s: WebAuthNGetErrorName", __func__);
+ goto fail;
+ }
+ if ((webauthn_get_assert =
+ (webauthn_get_assert_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNAuthenticatorGetAssertion")) == NULL) {
+ fido_log_debug("%s: WebAuthNAuthenticatorGetAssertion",
+ __func__);
+ goto fail;
+ }
+ if ((webauthn_make_cred =
+ (webauthn_make_cred_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNAuthenticatorMakeCredential")) == NULL) {
+ fido_log_debug("%s: WebAuthNAuthenticatorMakeCredential",
+ __func__);
+ goto fail;
+ }
+ if ((webauthn_free_assert =
+ (webauthn_free_assert_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNFreeAssertion")) == NULL) {
+ fido_log_debug("%s: WebAuthNFreeAssertion", __func__);
+ goto fail;
+ }
+ if ((webauthn_free_attest =
+ (webauthn_free_attest_t *)GetProcAddress(webauthn_handle,
+ "WebAuthNFreeCredentialAttestation")) == NULL) {
+ fido_log_debug("%s: WebAuthNFreeCredentialAttestation",
+ __func__);
+ goto fail;
+ }
+
+ webauthn_loaded = true;
+
+ return 0;
+fail:
+ fido_log_debug("%s: GetProcAddress", __func__);
+ webauthn_get_api_version = NULL;
+ webauthn_strerr = NULL;
+ webauthn_get_assert = NULL;
+ webauthn_make_cred = NULL;
+ webauthn_free_assert = NULL;
+ webauthn_free_attest = NULL;
+ FreeLibrary(webauthn_handle);
+ webauthn_handle = NULL;
+
+ return -1;
+}
+
static wchar_t *
to_utf16(const char *utf8)
{
@@ -68,53 +181,6 @@ to_utf16(const char *utf8)
return utf16;
}
-static char *
-to_utf8(const wchar_t *utf16)
-{
- int nch;
- char *utf8;
-
- if (utf16 == NULL) {
- fido_log_debug("%s: NULL", __func__);
- return NULL;
- }
- if ((nch = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16,
- -1, NULL, 0, NULL, NULL)) < 1 || (size_t)nch > MAXCHARS) {
- fido_log_debug("%s: WideCharToMultiByte %d", __func__);
- return NULL;
- }
- if ((utf8 = calloc((size_t)nch, sizeof(*utf8))) == NULL) {
- fido_log_debug("%s: calloc", __func__);
- return NULL;
- }
- if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1,
- utf8, nch, NULL, NULL) != nch) {
- fido_log_debug("%s: WideCharToMultiByte", __func__);
- free(utf8);
- return NULL;
- }
-
- return utf8;
-}
-
-static int
-to_fido_str_array(fido_str_array_t *sa, const char **v, size_t n)
-{
- if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) {
- fido_log_debug("%s: calloc", __func__);
- return -1;
- }
- for (size_t i = 0; i < n; i++) {
- if ((sa->ptr[i] = strdup(v[i])) == NULL) {
- fido_log_debug("%s: strdup", __func__);
- return -1;
- }
- sa->len++;
- }
-
- return 0;
-}
-
static int
to_fido(HRESULT hr)
{
@@ -129,7 +195,7 @@ to_fido(HRESULT hr)
case NTE_NOT_FOUND:
return FIDO_ERR_NOT_ALLOWED;
default:
- fido_log_debug("%s: hr=0x%x", __func__, hr);
+ fido_log_debug("%s: hr=0x%lx", __func__, (u_long)hr);
return FIDO_ERR_INTERNAL;
}
}
@@ -186,7 +252,28 @@ pack_credlist(WEBAUTHN_CREDENTIALS *out, const fido_blob_array_t *in)
}
static int
-set_uv(DWORD *out, fido_opt_t uv, const char *pin)
+set_cred_uv(DWORD *out, fido_opt_t uv, const char *pin)
+{
+ if (pin) {
+ *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+ return 0;
+ }
+
+ switch (uv) {
+ case FIDO_OPT_OMIT:
+ case FIDO_OPT_FALSE:
+ *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
+ break;
+ case FIDO_OPT_TRUE:
+ *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+ break;
+ }
+
+ return 0;
+}
+
+static int
+set_assert_uv(DWORD *out, fido_opt_t uv, const char *pin)
{
if (pin) {
*out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
@@ -195,7 +282,7 @@ set_uv(DWORD *out, fido_opt_t uv, const char *pin)
switch (uv) {
case FIDO_OPT_OMIT:
- *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
+ *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
break;
case FIDO_OPT_FALSE:
*out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
@@ -210,7 +297,7 @@ set_uv(DWORD *out, fido_opt_t uv, const char *pin)
static int
pack_rp(wchar_t **id, wchar_t **name, WEBAUTHN_RP_ENTITY_INFORMATION *out,
- fido_rp_t *in)
+ const fido_rp_t *in)
{
/* keep non-const copies of pwsz* for free() */
out->dwVersion = WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION;
@@ -227,7 +314,7 @@ pack_rp(wchar_t **id, wchar_t **name, WEBAUTHN_RP_ENTITY_INFORMATION *out,
static int
pack_user(wchar_t **name, wchar_t **icon, wchar_t **display_name,
- WEBAUTHN_USER_ENTITY_INFORMATION *out, fido_user_t *in)
+ WEBAUTHN_USER_ENTITY_INFORMATION *out, const fido_user_t *in)
{
if (in->id.ptr == NULL || in->id.len > ULONG_MAX) {
fido_log_debug("%s: id", __func__);
@@ -268,6 +355,9 @@ pack_cose(WEBAUTHN_COSE_CREDENTIAL_PARAMETER *alg,
case COSE_ES256:
alg->lAlg = WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256;
break;
+ case COSE_ES384:
+ alg->lAlg = WEBAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384;
+ break;
case COSE_EDDSA:
alg->lAlg = -8; /* XXX */;
break;
@@ -287,7 +377,7 @@ pack_cose(WEBAUTHN_COSE_CREDENTIAL_PARAMETER *alg,
}
static int
-pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in)
+pack_cred_ext(WEBAUTHN_EXTENSIONS *out, const fido_cred_ext_t *in)
{
WEBAUTHN_EXTENSION *e;
WEBAUTHN_CRED_PROTECT_EXTENSION_IN *p;
@@ -298,7 +388,7 @@ pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in)
return 0; /* nothing to do */
}
if (in->mask & ~(FIDO_EXT_HMAC_SECRET | FIDO_EXT_CRED_PROTECT)) {
- fido_log_debug("%s: mask 0x%x", in->mask);
+ fido_log_debug("%s: mask 0x%x", __func__, in->mask);
return -1;
}
if (in->mask & FIDO_EXT_HMAC_SECRET)
@@ -342,103 +432,48 @@ pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in)
}
static int
-unpack_fmt(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
-{
- char *fmt;
- int r;
-
- if ((fmt = to_utf8(att->pwszFormatType)) == NULL) {
- fido_log_debug("%s: fmt", __func__);
- return -1;
- }
- r = fido_cred_set_fmt(cred, fmt);
- free(fmt);
- fmt = NULL;
- if (r != FIDO_OK) {
- fido_log_debug("%s: fido_cred_set_fmt: %s", __func__,
- fido_strerr(r));
- return -1;
- }
-
- return 0;
-}
-
-static int
-unpack_cred_authdata(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
-{
- int r;
-
- if (att->cbAuthenticatorData > SIZE_MAX) {
- fido_log_debug("%s: cbAuthenticatorData", __func__);
- return -1;
- }
- if ((r = fido_cred_set_authdata_raw(cred, att->pbAuthenticatorData,
- (size_t)att->cbAuthenticatorData)) != FIDO_OK) {
- fido_log_debug("%s: fido_cred_set_authdata_raw: %s", __func__,
- fido_strerr(r));
- return -1;
- }
-
- return 0;
-}
-
-static int
-unpack_cred_sig(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr)
+pack_assert_ext(WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *out,
+ const fido_assert_ext_t *in)
{
- int r;
+ WEBAUTHN_HMAC_SECRET_SALT_VALUES *v;
+ WEBAUTHN_HMAC_SECRET_SALT *s;
- if (attr->cbSignature > SIZE_MAX) {
- fido_log_debug("%s: cbSignature", __func__);
- return -1;
+ if (in->mask == 0) {
+ return 0; /* nothing to do */
}
- if ((r = fido_cred_set_sig(cred, attr->pbSignature,
- (size_t)attr->cbSignature)) != FIDO_OK) {
- fido_log_debug("%s: fido_cred_set_sig: %s", __func__,
- fido_strerr(r));
+ if (in->mask != FIDO_EXT_HMAC_SECRET) {
+ fido_log_debug("%s: mask 0x%x", __func__, in->mask);
return -1;
}
-
- return 0;
-}
-
-static int
-unpack_x5c(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr)
-{
- int r;
-
- fido_log_debug("%s: %u cert(s)", __func__, attr->cX5c);
-
- if (attr->cX5c == 0)
- return 0; /* self-attestation */
- if (attr->lAlg != WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256) {
- fido_log_debug("%s: lAlg %d", __func__, attr->lAlg);
- return -1;
- }
- if (attr->pX5c[0].cbData > SIZE_MAX) {
- fido_log_debug("%s: cbData", __func__);
+ if (in->hmac_salt.ptr == NULL ||
+ in->hmac_salt.len != WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH) {
+ fido_log_debug("%s: salt %p/%zu", __func__,
+ (const void *)in->hmac_salt.ptr, in->hmac_salt.len);
return -1;
}
- if ((r = fido_cred_set_x509(cred, attr->pX5c[0].pbData,
- (size_t)attr->pX5c[0].cbData)) != FIDO_OK) {
- fido_log_debug("%s: fido_cred_set_x509: %s", __func__,
- fido_strerr(r));
+ if ((v = calloc(1, sizeof(*v))) == NULL ||
+ (s = calloc(1, sizeof(*s))) == NULL) {
+ free(v);
+ fido_log_debug("%s: calloc", __func__);
return -1;
}
+ s->cbFirst = (DWORD)in->hmac_salt.len;
+ s->pbFirst = in->hmac_salt.ptr;
+ v->pGlobalHmacSalt = s;
+ out->pHmacSecretSaltValues = v;
+ out->dwFlags |= WEBAUTHN_AUTHENTICATOR_HMAC_SECRET_VALUES_FLAG;
+ out->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6;
return 0;
}
static int
-unpack_assert_authdata(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
+unpack_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
- if (wa->cbAuthenticatorData > SIZE_MAX) {
- fido_log_debug("%s: cbAuthenticatorData", __func__);
- return -1;
- }
if ((r = fido_assert_set_authdata_raw(assert, 0, wa->pbAuthenticatorData,
- (size_t)wa->cbAuthenticatorData)) != FIDO_OK) {
+ wa->cbAuthenticatorData)) != FIDO_OK) {
fido_log_debug("%s: fido_assert_set_authdata_raw: %s", __func__,
fido_strerr(r));
return -1;
@@ -448,16 +483,12 @@ unpack_assert_authdata(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
-unpack_assert_sig(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
+unpack_assert_sig(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
- if (wa->cbSignature > SIZE_MAX) {
- fido_log_debug("%s: cbSignature", __func__);
- return -1;
- }
if ((r = fido_assert_set_sig(assert, 0, wa->pbSignature,
- (size_t)wa->cbSignature)) != FIDO_OK) {
+ wa->cbSignature)) != FIDO_OK) {
fido_log_debug("%s: fido_assert_set_sig: %s", __func__,
fido_strerr(r));
return -1;
@@ -467,14 +498,10 @@ unpack_assert_sig(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
-unpack_cred_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
+unpack_cred_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
- if (wa->Credential.cbId > SIZE_MAX) {
- fido_log_debug("%s: Credential.cbId", __func__);
- return -1;
- }
if (fido_blob_set(&assert->stmt[0].id, wa->Credential.pbId,
- (size_t)wa->Credential.cbId) < 0) {
+ wa->Credential.cbId) < 0) {
fido_log_debug("%s: fido_blob_set", __func__);
return -1;
}
@@ -483,16 +510,44 @@ unpack_cred_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
-unpack_user_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
+unpack_user_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
if (wa->cbUserId == 0)
return 0; /* user id absent */
- if (wa->cbUserId > SIZE_MAX) {
- fido_log_debug("%s: cbUserId", __func__);
+ if (fido_blob_set(&assert->stmt[0].user.id, wa->pbUserId,
+ wa->cbUserId) < 0) {
+ fido_log_debug("%s: fido_blob_set", __func__);
return -1;
}
- if (fido_blob_set(&assert->stmt[0].user.id, wa->pbUserId,
- (size_t)wa->cbUserId) < 0) {
+
+ return 0;
+}
+
+static int
+unpack_hmac_secret(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
+{
+ if (wa->dwVersion != WEBAUTHN_ASSERTION_VERSION_3) {
+ fido_log_debug("%s: dwVersion %u", __func__,
+ (unsigned)wa->dwVersion);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (wa->pHmacSecret == NULL ||
+ wa->pHmacSecret->cbFirst == 0 ||
+ wa->pHmacSecret->pbFirst == NULL) {
+ fido_log_debug("%s: hmac-secret absent", __func__);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (wa->pHmacSecret->cbSecond != 0 ||
+ wa->pHmacSecret->pbSecond != NULL) {
+ fido_log_debug("%s: 64-byte hmac-secret", __func__);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (!fido_blob_is_empty(&assert->stmt[0].hmac_secret)) {
+ fido_log_debug("%s: fido_blob_is_empty", __func__);
+ return -1;
+ }
+ if (fido_blob_set(&assert->stmt[0].hmac_secret,
+ wa->pHmacSecret->pbFirst, wa->pHmacSecret->cbFirst) < 0) {
fido_log_debug("%s: fido_blob_set", __func__);
return -1;
}
@@ -501,8 +556,8 @@ unpack_user_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
-translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
- const char *pin)
+translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert,
+ const char *pin, int ms)
{
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *opt;
@@ -511,11 +566,6 @@ translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
fido_log_debug("%s: up %d", __func__, assert->up);
return FIDO_ERR_UNSUPPORTED_OPTION;
}
- /* not implemented */
- if (assert->ext.mask) {
- fido_log_debug("%s: ext 0x%x", __func__, assert->ext.mask);
- return FIDO_ERR_UNSUPPORTED_EXTENSION;
- }
if ((ctx->rp_id = to_utf16(assert->rp_id)) == NULL) {
fido_log_debug("%s: rp_id", __func__);
return FIDO_ERR_INTERNAL;
@@ -527,13 +577,18 @@ translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
/* options */
opt = &ctx->opt;
opt->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_1;
- opt->dwTimeoutMilliseconds = MAXMSEC;
+ opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms;
if (pack_credlist(&opt->CredentialList, &assert->allow_list) < 0) {
fido_log_debug("%s: pack_credlist", __func__);
return FIDO_ERR_INTERNAL;
}
- if (set_uv(&opt->dwUserVerificationRequirement, assert->uv, pin) < 0) {
- fido_log_debug("%s: set_uv", __func__);
+ if (pack_assert_ext(opt, &assert->ext) < 0) {
+ fido_log_debug("%s: pack_assert_ext", __func__);
+ return FIDO_ERR_UNSUPPORTED_EXTENSION;
+ }
+ if (set_assert_uv(&opt->dwUserVerificationRequirement, assert->uv,
+ pin) < 0) {
+ fido_log_debug("%s: set_assert_uv", __func__);
return FIDO_ERR_INTERNAL;
}
@@ -541,7 +596,7 @@ translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
}
static int
-translate_winhello_assert(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
+translate_winhello_assert(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
@@ -570,13 +625,18 @@ translate_winhello_assert(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
fido_log_debug("%s: unpack_user_id", __func__);
return FIDO_ERR_INTERNAL;
}
+ if (assert->ext.mask & FIDO_EXT_HMAC_SECRET &&
+ unpack_hmac_secret(assert, wa) < 0) {
+ fido_log_debug("%s: unpack_hmac_secret", __func__);
+ return FIDO_ERR_INTERNAL;
+ }
return FIDO_OK;
}
static int
-translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
- const char *pin)
+translate_fido_cred(struct winhello_cred *ctx, const fido_cred_t *cred,
+ const char *pin, int ms)
{
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *opt;
@@ -600,7 +660,9 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
/* options */
opt = &ctx->opt;
opt->dwVersion = WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_1;
- opt->dwTimeoutMilliseconds = MAXMSEC;
+ opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms;
+ opt->dwAttestationConveyancePreference =
+ WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
if (pack_credlist(&opt->CredentialList, &cred->excl) < 0) {
fido_log_debug("%s: pack_credlist", __func__);
return FIDO_ERR_INTERNAL;
@@ -609,8 +671,9 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
fido_log_debug("%s: pack_cred_ext", __func__);
return FIDO_ERR_UNSUPPORTED_EXTENSION;
}
- if (set_uv(&opt->dwUserVerificationRequirement, cred->uv, pin) < 0) {
- fido_log_debug("%s: set_uv", __func__);
+ if (set_cred_uv(&opt->dwUserVerificationRequirement, (cred->ext.mask &
+ FIDO_EXT_CRED_PROTECT) ? FIDO_OPT_TRUE : cred->uv, pin) < 0) {
+ fido_log_debug("%s: set_cred_uv", __func__);
return FIDO_ERR_INTERNAL;
}
if (cred->rk == FIDO_OPT_TRUE) {
@@ -621,66 +684,78 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
}
static int
-translate_winhello_cred(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
+decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
- if (unpack_fmt(cred, att) < 0) {
- fido_log_debug("%s: unpack_fmt", __func__);
- return FIDO_ERR_INTERNAL;
- }
- if (unpack_cred_authdata(cred, att) < 0) {
- fido_log_debug("%s: unpack_cred_authdata", __func__);
- return FIDO_ERR_INTERNAL;
+ fido_cred_t *cred = arg;
+ char *name = NULL;
+ int ok = -1;
+
+ if (cbor_string_copy(key, &name) < 0) {
+ fido_log_debug("%s: cbor type", __func__);
+ ok = 0; /* ignore */
+ goto fail;
}
- switch (att->dwAttestationDecodeType) {
- case WEBAUTHN_ATTESTATION_DECODE_NONE:
- if (att->pvAttestationDecode != NULL) {
- fido_log_debug("%s: pvAttestationDecode", __func__);
- return FIDO_ERR_INTERNAL;
+ if (!strcmp(name, "fmt")) {
+ if (cbor_decode_fmt(val, &cred->fmt) < 0) {
+ fido_log_debug("%s: cbor_decode_fmt", __func__);
+ goto fail;
}
- break;
- case WEBAUTHN_ATTESTATION_DECODE_COMMON:
- if (att->pvAttestationDecode == NULL) {
- fido_log_debug("%s: pvAttestationDecode", __func__);
- return FIDO_ERR_INTERNAL;
+ } else if (!strcmp(name, "attStmt")) {
+ if (cbor_decode_attstmt(val, &cred->attstmt) < 0) {
+ fido_log_debug("%s: cbor_decode_attstmt", __func__);
+ goto fail;
}
- if (unpack_cred_sig(cred, att->pvAttestationDecode) < 0) {
- fido_log_debug("%s: unpack_cred_sig", __func__);
- return FIDO_ERR_INTERNAL;
+ } else if (!strcmp(name, "authData")) {
+ if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
+ fido_log_debug("%s: fido_blob_decode", __func__);
+ goto fail;
}
- if (unpack_x5c(cred, att->pvAttestationDecode) < 0) {
- fido_log_debug("%s: unpack_x5c", __func__);
- return FIDO_ERR_INTERNAL;
+ if (cbor_decode_cred_authdata(val, cred->type,
+ &cred->authdata_cbor, &cred->authdata, &cred->attcred,
+ &cred->authdata_ext) < 0) {
+ fido_log_debug("%s: cbor_decode_cred_authdata",
+ __func__);
+ goto fail;
}
- break;
- default:
- fido_log_debug("%s: dwAttestationDecodeType: %u", __func__,
- att->dwAttestationDecodeType);
- return FIDO_ERR_INTERNAL;
}
- return FIDO_OK;
+ ok = 0;
+fail:
+ free(name);
+
+ return (ok);
}
static int
-winhello_manifest(BOOL *present)
+translate_winhello_cred(fido_cred_t *cred,
+ const WEBAUTHN_CREDENTIAL_ATTESTATION *att)
{
- DWORD n;
- HRESULT hr;
- int r = FIDO_OK;
+ cbor_item_t *item = NULL;
+ struct cbor_load_result cbor;
+ int r = FIDO_ERR_INTERNAL;
- if ((n = WebAuthNGetApiVersionNumber()) < 1) {
- fido_log_debug("%s: unsupported api %u", __func__, n);
- return FIDO_ERR_INTERNAL;
+ if (att->pbAttestationObject == NULL) {
+ fido_log_debug("%s: pbAttestationObject", __func__);
+ goto fail;
}
- fido_log_debug("%s: api version %u", __func__, n);
- hr = WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable(present);
- if (hr != S_OK) {
- r = to_fido(hr);
- fido_log_debug("%s: %ls -> %s", __func__,
- WebAuthNGetErrorName(hr), fido_strerr(r));
+ if ((item = cbor_load(att->pbAttestationObject,
+ att->cbAttestationObject, &cbor)) == NULL) {
+ fido_log_debug("%s: cbor_load", __func__);
+ goto fail;
+ }
+ if (cbor_isa_map(item) == false ||
+ cbor_map_is_definite(item) == false ||
+ cbor_map_iter(item, cred, decode_attobj) < 0) {
+ fido_log_debug("%s: cbor type", __func__);
+ goto fail;
}
+ r = FIDO_OK;
+fail:
+ if (item != NULL)
+ cbor_decref(&item);
+
return r;
}
@@ -690,12 +765,11 @@ winhello_get_assert(HWND w, struct winhello_assert *ctx)
HRESULT hr;
int r = FIDO_OK;
- hr = WebAuthNAuthenticatorGetAssertion(w, ctx->rp_id, &ctx->cd,
- &ctx->opt, &ctx->assert);
- if (hr != S_OK) {
+ if ((hr = webauthn_get_assert(w, ctx->rp_id, &ctx->cd, &ctx->opt,
+ &ctx->assert)) != S_OK) {
r = to_fido(hr);
- fido_log_debug("%s: %ls -> %s", __func__,
- WebAuthNGetErrorName(hr), fido_strerr(r));
+ fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr),
+ fido_strerr(r));
}
return r;
@@ -707,12 +781,11 @@ winhello_make_cred(HWND w, struct winhello_cred *ctx)
HRESULT hr;
int r = FIDO_OK;
- hr = WebAuthNAuthenticatorMakeCredential(w, &ctx->rp, &ctx->user,
- &ctx->cose, &ctx->cd, &ctx->opt, &ctx->att);
- if (hr != S_OK) {
+ if ((hr = webauthn_make_cred(w, &ctx->rp, &ctx->user, &ctx->cose,
+ &ctx->cd, &ctx->opt, &ctx->att)) != S_OK) {
r = to_fido(hr);
- fido_log_debug("%s: %ls -> %s", __func__,
- WebAuthNGetErrorName(hr), fido_strerr(r));
+ fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr),
+ fido_strerr(r));
}
return r;
@@ -724,10 +797,13 @@ winhello_assert_free(struct winhello_assert *ctx)
if (ctx == NULL)
return;
if (ctx->assert != NULL)
- WebAuthNFreeAssertion(ctx->assert);
+ webauthn_free_assert(ctx->assert);
free(ctx->rp_id);
free(ctx->opt.CredentialList.pCredentials);
+ if (ctx->opt.pHmacSecretSaltValues != NULL)
+ free(ctx->opt.pHmacSecretSaltValues->pGlobalHmacSalt);
+ free(ctx->opt.pHmacSecretSaltValues);
free(ctx);
}
@@ -737,7 +813,7 @@ winhello_cred_free(struct winhello_cred *ctx)
if (ctx == NULL)
return;
if (ctx->att != NULL)
- WebAuthNFreeCredentialAttestation(ctx->att);
+ webauthn_free_attest(ctx->att);
free(ctx->rp_id);
free(ctx->rp_name);
@@ -757,8 +833,6 @@ winhello_cred_free(struct winhello_cred *ctx)
int
fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
{
- int r;
- BOOL present;
fido_dev_info_t *di;
if (ilen == 0) {
@@ -767,13 +841,9 @@ fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
if (devlist == NULL) {
return FIDO_ERR_INVALID_ARGUMENT;
}
- if ((r = winhello_manifest(&present)) != FIDO_OK) {
- fido_log_debug("%s: winhello_manifest", __func__);
- return r;
- }
- if (present == false) {
- fido_log_debug("%s: not present", __func__);
- return FIDO_OK;
+ if (!webauthn_loaded && webauthn_load() < 0) {
+ fido_log_debug("%s: webauthn_load", __func__);
+ return FIDO_OK; /* not an error */
}
di = &devlist[*olen];
@@ -799,9 +869,12 @@ fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
int
fido_winhello_open(fido_dev_t *dev)
{
+ if (!webauthn_loaded && webauthn_load() < 0) {
+ fido_log_debug("%s: webauthn_load", __func__);
+ return FIDO_ERR_INTERNAL;
+ }
if (dev->flags != 0)
return FIDO_ERR_INVALID_ARGUMENT;
-
dev->attr.flags = FIDO_CAP_CBOR | FIDO_CAP_WINK;
dev->flags = FIDO_DEV_WINHELLO | FIDO_DEV_CRED_PROT | FIDO_DEV_PIN_SET;
@@ -826,7 +899,7 @@ fido_winhello_cancel(fido_dev_t *dev)
int
fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert,
- const char *pin)
+ const char *pin, int ms)
{
HWND w;
struct winhello_assert *ctx;
@@ -834,19 +907,24 @@ fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert,
(void)dev;
+ fido_assert_reset_rx(assert);
+
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
fido_log_debug("%s: calloc", __func__);
goto fail;
}
if ((w = GetForegroundWindow()) == NULL) {
fido_log_debug("%s: GetForegroundWindow", __func__);
- goto fail;
+ if ((w = GetTopWindow(NULL)) == NULL) {
+ fido_log_debug("%s: GetTopWindow", __func__);
+ goto fail;
+ }
}
- if ((r = translate_fido_assert(ctx, assert, pin)) != FIDO_OK) {
+ if ((r = translate_fido_assert(ctx, assert, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: translate_fido_assert", __func__);
goto fail;
}
- if ((r = winhello_get_assert(w, ctx)) != S_OK) {
+ if ((r = winhello_get_assert(w, ctx)) != FIDO_OK) {
fido_log_debug("%s: winhello_get_assert", __func__);
goto fail;
}
@@ -867,16 +945,16 @@ fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
const char *v[3] = { "U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE" };
const char *e[2] = { "credProtect", "hmac-secret" };
const char *t[2] = { "nfc", "usb" };
- const char *o[4] = { "rk", "up", "plat", "clientPin" };
+ const char *o[4] = { "rk", "up", "uv", "plat" };
(void)dev;
fido_cbor_info_reset(ci);
- if (to_fido_str_array(&ci->versions, v, nitems(v)) < 0 ||
- to_fido_str_array(&ci->extensions, e, nitems(e)) < 0 ||
- to_fido_str_array(&ci->transports, t, nitems(t)) < 0) {
- fido_log_debug("%s: to_fido_str_array", __func__);
+ if (fido_str_array_pack(&ci->versions, v, nitems(v)) < 0 ||
+ fido_str_array_pack(&ci->extensions, e, nitems(e)) < 0 ||
+ fido_str_array_pack(&ci->transports, t, nitems(t)) < 0) {
+ fido_log_debug("%s: fido_str_array_pack", __func__);
return FIDO_ERR_INTERNAL;
}
if ((ci->options.name = calloc(nitems(o), sizeof(char *))) == NULL ||
@@ -897,7 +975,8 @@ fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
}
int
-fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
+fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
+ int ms)
{
HWND w;
struct winhello_cred *ctx;
@@ -905,15 +984,20 @@ fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
(void)dev;
+ fido_cred_reset_rx(cred);
+
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
fido_log_debug("%s: calloc", __func__);
goto fail;
}
if ((w = GetForegroundWindow()) == NULL) {
fido_log_debug("%s: GetForegroundWindow", __func__);
- goto fail;
+ if ((w = GetTopWindow(NULL)) == NULL) {
+ fido_log_debug("%s: GetTopWindow", __func__);
+ goto fail;
+ }
}
- if ((r = translate_fido_cred(ctx, cred, pin)) != FIDO_OK) {
+ if ((r = translate_fido_cred(ctx, cred, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: translate_fido_cred", __func__);
goto fail;
}