Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/PWebAuthnTransactionParent.h"
8
#include "mozilla/MozPromise.h"
9
#include "mozilla/ipc/BackgroundParent.h"
10
#include "mozilla/ClearOnShutdown.h"
11
#include "mozilla/Unused.h"
12
#include "nsTextFormatter.h"
13
#include "winwebauthn/webauthn.h"
14
#include "WinWebAuthnManager.h"
15
16
namespace mozilla {
17
namespace dom {
18
19
namespace {
20
static mozilla::LazyLogModule gWinWebAuthnManagerLog("winwebauthnkeymanager");
21
StaticAutoPtr<WinWebAuthnManager> gWinWebAuthnManager;
22
static HMODULE gWinWebAuthnModule = 0;
23
24
static decltype(WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*
25
gWinWebauthnIsUVPAA = nullptr;
26
static decltype(
27
WebAuthNAuthenticatorMakeCredential)* gWinWebauthnMakeCredential = nullptr;
28
static decltype(
29
WebAuthNFreeCredentialAttestation)* gWinWebauthnFreeCredentialAttestation =
30
nullptr;
31
static decltype(WebAuthNAuthenticatorGetAssertion)* gWinWebauthnGetAssertion =
32
nullptr;
33
static decltype(WebAuthNFreeAssertion)* gWinWebauthnFreeAssertion = nullptr;
34
static decltype(WebAuthNGetCancellationId)* gWinWebauthnGetCancellationId =
35
nullptr;
36
static decltype(
37
WebAuthNCancelCurrentOperation)* gWinWebauthnCancelCurrentOperation =
38
nullptr;
39
static decltype(WebAuthNGetErrorName)* gWinWebauthnGetErrorName = nullptr;
40
static decltype(WebAuthNGetApiVersionNumber)* gWinWebauthnGetApiVersionNumber =
41
nullptr;
42
43
} // namespace
44
45
/***********************************************************************
46
* WinWebAuthnManager Implementation
47
**********************************************************************/
48
49
constexpr uint32_t kMinWinWebAuthNApiVersion = WEBAUTHN_API_VERSION_1;
50
51
WinWebAuthnManager::WinWebAuthnManager() {
52
// Create on the main thread to make sure ClearOnShutdown() works.
53
MOZ_ASSERT(NS_IsMainThread());
54
MOZ_ASSERT(!gWinWebAuthnModule);
55
56
gWinWebAuthnModule = LoadLibrary(L"webauthn.dll");
57
58
if (gWinWebAuthnModule) {
59
gWinWebauthnIsUVPAA = reinterpret_cast<decltype(
60
WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*>(
61
GetProcAddress(
62
gWinWebAuthnModule,
63
"WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable"));
64
gWinWebauthnMakeCredential =
65
reinterpret_cast<decltype(WebAuthNAuthenticatorMakeCredential)*>(
66
GetProcAddress(gWinWebAuthnModule,
67
"WebAuthNAuthenticatorMakeCredential"));
68
gWinWebauthnFreeCredentialAttestation =
69
reinterpret_cast<decltype(WebAuthNFreeCredentialAttestation)*>(
70
GetProcAddress(gWinWebAuthnModule,
71
"WebAuthNFreeCredentialAttestation"));
72
gWinWebauthnGetAssertion =
73
reinterpret_cast<decltype(WebAuthNAuthenticatorGetAssertion)*>(
74
GetProcAddress(gWinWebAuthnModule,
75
"WebAuthNAuthenticatorGetAssertion"));
76
gWinWebauthnFreeAssertion =
77
reinterpret_cast<decltype(WebAuthNFreeAssertion)*>(
78
GetProcAddress(gWinWebAuthnModule, "WebAuthNFreeAssertion"));
79
gWinWebauthnGetCancellationId =
80
reinterpret_cast<decltype(WebAuthNGetCancellationId)*>(
81
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetCancellationId"));
82
gWinWebauthnCancelCurrentOperation =
83
reinterpret_cast<decltype(WebAuthNCancelCurrentOperation)*>(
84
GetProcAddress(gWinWebAuthnModule,
85
"WebAuthNCancelCurrentOperation"));
86
gWinWebauthnGetErrorName =
87
reinterpret_cast<decltype(WebAuthNGetErrorName)*>(
88
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetErrorName"));
89
gWinWebauthnGetApiVersionNumber =
90
reinterpret_cast<decltype(WebAuthNGetApiVersionNumber)*>(
91
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetApiVersionNumber"));
92
93
if (gWinWebauthnIsUVPAA && gWinWebauthnMakeCredential &&
94
gWinWebauthnFreeCredentialAttestation && gWinWebauthnGetAssertion &&
95
gWinWebauthnFreeAssertion && gWinWebauthnGetCancellationId &&
96
gWinWebauthnCancelCurrentOperation && gWinWebauthnGetErrorName &&
97
gWinWebauthnGetApiVersionNumber) {
98
mWinWebAuthNApiVersion = gWinWebauthnGetApiVersionNumber();
99
}
100
}
101
}
102
103
WinWebAuthnManager::~WinWebAuthnManager() {
104
if (gWinWebAuthnModule) {
105
FreeLibrary(gWinWebAuthnModule);
106
}
107
gWinWebAuthnModule = 0;
108
}
109
110
// static
111
void WinWebAuthnManager::Initialize() {
112
if (!gWinWebAuthnManager) {
113
gWinWebAuthnManager = new WinWebAuthnManager();
114
ClearOnShutdown(&gWinWebAuthnManager);
115
}
116
}
117
118
// static
119
WinWebAuthnManager* WinWebAuthnManager::Get() {
120
MOZ_ASSERT(gWinWebAuthnManager);
121
return gWinWebAuthnManager;
122
}
123
124
uint32_t WinWebAuthnManager::GetWebAuthNApiVersion() {
125
return mWinWebAuthNApiVersion;
126
}
127
128
// static
129
bool WinWebAuthnManager::AreWebAuthNApisAvailable() {
130
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
131
return mgr->GetWebAuthNApiVersion() >= kMinWinWebAuthNApiVersion;
132
}
133
134
bool WinWebAuthnManager::
135
IsUserVerifyingPlatformAuthenticatorAvailableInternal() {
136
BOOL isUVPAA = FALSE;
137
return (gWinWebauthnIsUVPAA(&isUVPAA) == S_OK && isUVPAA == TRUE);
138
}
139
140
// static
141
bool WinWebAuthnManager::IsUserVerifyingPlatformAuthenticatorAvailable() {
142
if (WinWebAuthnManager::AreWebAuthNApisAvailable()) {
143
return WinWebAuthnManager::Get()
144
->IsUserVerifyingPlatformAuthenticatorAvailableInternal();
145
}
146
return false;
147
}
148
149
void WinWebAuthnManager::AbortTransaction(const uint64_t& aTransactionId,
150
const nsresult& aError) {
151
Unused << mTransactionParent->SendAbort(aTransactionId, aError);
152
ClearTransaction();
153
}
154
155
void WinWebAuthnManager::MaybeClearTransaction(
156
PWebAuthnTransactionParent* aParent) {
157
// Only clear if we've been requested to do so by our current transaction
158
// parent.
159
if (mTransactionParent == aParent) {
160
ClearTransaction();
161
}
162
}
163
164
void WinWebAuthnManager::ClearTransaction() { mTransactionParent = nullptr; }
165
166
void WinWebAuthnManager::Register(
167
PWebAuthnTransactionParent* aTransactionParent,
168
const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aInfo) {
169
MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNRegister"));
170
171
ClearTransaction();
172
mTransactionParent = aTransactionParent;
173
174
BYTE U2FUserId = 0x01;
175
176
WEBAUTHN_EXTENSION rgExtension[1] = {};
177
DWORD cExtensions = 0;
178
BOOL HmacCreateSecret = FALSE;
179
180
// RP Information
181
WEBAUTHN_RP_ENTITY_INFORMATION rpInfo = {
182
WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION, aInfo.RpId().get(),
183
nullptr, nullptr};
184
185
// User Information
186
WEBAUTHN_USER_ENTITY_INFORMATION userInfo = {
187
WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION,
188
0,
189
nullptr,
190
nullptr,
191
nullptr,
192
nullptr};
193
194
// Client Data
195
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
196
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, aInfo.ClientDataJSON().Length(),
197
(BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};
198
199
// Algorithms
200
nsTArray<WEBAUTHN_COSE_CREDENTIAL_PARAMETER> coseParams;
201
202
// User Verification Requirement
203
DWORD winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
204
205
// Attachment
206
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
207
208
// Resident Key
209
BOOL winRequireResidentKey = FALSE;
210
211
// AttestationConveyance
212
DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
213
214
if (aInfo.Extra().isSome()) {
215
const auto& extra = aInfo.Extra().ref();
216
217
rpInfo.pwszName = extra.Rp().Name().get();
218
rpInfo.pwszIcon = extra.Rp().Icon().get();
219
220
userInfo.cbId = static_cast<DWORD>(extra.User().Id().Length());
221
userInfo.pbId = const_cast<unsigned char*>(extra.User().Id().Elements());
222
userInfo.pwszName = extra.User().Name().get();
223
userInfo.pwszIcon = extra.User().Icon().get();
224
userInfo.pwszDisplayName = extra.User().DisplayName().get();
225
226
for (const auto& coseAlg : extra.coseAlgs()) {
227
WEBAUTHN_COSE_CREDENTIAL_PARAMETER coseAlgorithm = {
228
WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
229
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, coseAlg.alg()};
230
coseParams.AppendElement(coseAlgorithm);
231
}
232
233
const auto& sel = extra.AuthenticatorSelection();
234
235
UserVerificationRequirement userVerificationReq =
236
sel.userVerificationRequirement();
237
switch (userVerificationReq) {
238
case UserVerificationRequirement::Required:
239
winUserVerificationReq =
240
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
241
break;
242
case UserVerificationRequirement::Preferred:
243
winUserVerificationReq =
244
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
245
break;
246
case UserVerificationRequirement::Discouraged:
247
winUserVerificationReq =
248
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
249
break;
250
default:
251
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
252
break;
253
}
254
255
if (sel.authenticatorAttachment().isSome()) {
256
const AuthenticatorAttachment authenticatorAttachment =
257
sel.authenticatorAttachment().value();
258
switch (authenticatorAttachment) {
259
case AuthenticatorAttachment::Platform:
260
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM;
261
break;
262
case AuthenticatorAttachment::Cross_platform:
263
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
264
break;
265
default:
266
break;
267
}
268
}
269
270
winRequireResidentKey = sel.requireResidentKey();
271
272
// AttestationConveyance
273
AttestationConveyancePreference attestation =
274
extra.attestationConveyancePreference();
275
DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
276
switch (attestation) {
277
case AttestationConveyancePreference::Direct:
278
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
279
break;
280
case AttestationConveyancePreference::Indirect:
281
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT;
282
break;
283
case AttestationConveyancePreference::None:
284
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE;
285
break;
286
default:
287
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
288
break;
289
}
290
291
for (const WebAuthnExtension& ext : extra.Extensions()) {
292
MOZ_ASSERT(cExtensions <
293
(int)(sizeof(rgExtension) / sizeof(rgExtension[0])));
294
295
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionHmacSecret) {
296
HmacCreateSecret =
297
ext.get_WebAuthnExtensionHmacSecret().hmacCreateSecret() == true;
298
if (HmacCreateSecret) {
299
rgExtension[cExtensions].pwszExtensionIdentifier =
300
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET;
301
rgExtension[cExtensions].cbExtension = sizeof(BOOL);
302
rgExtension[cExtensions].pvExtension = &HmacCreateSecret;
303
cExtensions++;
304
}
305
}
306
}
307
} else {
308
userInfo.cbId = sizeof(BYTE);
309
userInfo.pbId = &U2FUserId;
310
311
WEBAUTHN_COSE_CREDENTIAL_PARAMETER coseAlgorithm = {
312
WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
313
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY,
314
WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
315
coseParams.AppendElement(coseAlgorithm);
316
317
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2;
318
}
319
320
WEBAUTHN_COSE_CREDENTIAL_PARAMETERS WebAuthNCredentialParameters = {
321
static_cast<DWORD>(coseParams.Length()), coseParams.Elements()};
322
323
// Exclude Credentials
324
nsTArray<WEBAUTHN_CREDENTIAL_EX> excludeCredentials;
325
WEBAUTHN_CREDENTIAL_EX* pExcludeCredentials = nullptr;
326
nsTArray<WEBAUTHN_CREDENTIAL_EX*> excludeCredentialsPtrs;
327
WEBAUTHN_CREDENTIAL_LIST excludeCredentialList = {0};
328
WEBAUTHN_CREDENTIAL_LIST* pExcludeCredentialList = nullptr;
329
330
for (auto& cred : aInfo.ExcludeList()) {
331
uint8_t transports = cred.transports();
332
DWORD winTransports = 0;
333
if (transports & U2F_AUTHENTICATOR_TRANSPORT_USB) {
334
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
335
}
336
if (transports & U2F_AUTHENTICATOR_TRANSPORT_NFC) {
337
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
338
}
339
if (transports & U2F_AUTHENTICATOR_TRANSPORT_BLE) {
340
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
341
}
342
if (transports & CTAP_AUTHENTICATOR_TRANSPORT_INTERNAL) {
343
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
344
}
345
346
WEBAUTHN_CREDENTIAL_EX credential = {
347
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
348
static_cast<DWORD>(cred.id().Length()), (PBYTE)(cred.id().Elements()),
349
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
350
excludeCredentials.AppendElement(credential);
351
}
352
353
if (!excludeCredentials.IsEmpty()) {
354
pExcludeCredentials = excludeCredentials.Elements();
355
for (DWORD i = 0; i < excludeCredentials.Length(); i++) {
356
excludeCredentialsPtrs.AppendElement(&pExcludeCredentials[i]);
357
}
358
excludeCredentialList.cCredentials = excludeCredentials.Length();
359
excludeCredentialList.ppCredentials = excludeCredentialsPtrs.Elements();
360
pExcludeCredentialList = &excludeCredentialList;
361
}
362
363
// MakeCredentialOptions
364
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS WebAuthNCredentialOptions = {
365
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_CURRENT_VERSION,
366
aInfo.TimeoutMS(),
367
{0, NULL},
368
{0, NULL},
369
winAttachment,
370
winRequireResidentKey,
371
winUserVerificationReq,
372
winAttestation,
373
0, // Flags
374
NULL, // CancellationId
375
pExcludeCredentialList};
376
377
GUID cancellationId = {0};
378
if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) {
379
WebAuthNCredentialOptions.pCancellationId = &cancellationId;
380
mCancellationIds.emplace(aTransactionId, &cancellationId);
381
}
382
383
if (cExtensions != 0) {
384
WebAuthNCredentialOptions.Extensions.cExtensions = cExtensions;
385
WebAuthNCredentialOptions.Extensions.pExtensions = rgExtension;
386
}
387
388
WEBAUTHN_CREDENTIAL_ATTESTATION* pWebAuthNCredentialAttestation = nullptr;
389
390
// Bug 1518876: Get Window Handle from Content process for Windows WebAuthN
391
// APIs
392
HWND hWnd = GetForegroundWindow();
393
394
HRESULT hr = gWinWebauthnMakeCredential(
395
hWnd, &rpInfo, &userInfo, &WebAuthNCredentialParameters,
396
&WebAuthNClientData, &WebAuthNCredentialOptions,
397
&pWebAuthNCredentialAttestation);
398
399
mCancellationIds.erase(aTransactionId);
400
401
if (hr == S_OK) {
402
nsTArray<uint8_t> attObject;
403
attObject.AppendElements(
404
pWebAuthNCredentialAttestation->pbAttestationObject,
405
pWebAuthNCredentialAttestation->cbAttestationObject);
406
407
nsTArray<uint8_t> credentialId;
408
credentialId.AppendElements(pWebAuthNCredentialAttestation->pbCredentialId,
409
pWebAuthNCredentialAttestation->cbCredentialId);
410
411
nsTArray<uint8_t> authenticatorData;
412
413
if (aInfo.Extra().isSome()) {
414
authenticatorData.AppendElements(
415
pWebAuthNCredentialAttestation->pbAuthenticatorData,
416
pWebAuthNCredentialAttestation->cbAuthenticatorData);
417
} else {
418
PWEBAUTHN_COMMON_ATTESTATION attestation =
419
reinterpret_cast<PWEBAUTHN_COMMON_ATTESTATION>(
420
pWebAuthNCredentialAttestation->pvAttestationDecode);
421
422
DWORD coseKeyOffset = 32 + // RPIDHash
423
1 + // Flags
424
4 + // Counter
425
16 + // AAGuid
426
2 + // Credential ID Length field
427
pWebAuthNCredentialAttestation->cbCredentialId;
428
429
// Hardcoding as couldn't finder decoder and it is an ECC key.
430
DWORD xOffset = coseKeyOffset + 10;
431
DWORD yOffset = coseKeyOffset + 45;
432
433
// Authenticator Data length check.
434
if (pWebAuthNCredentialAttestation->cbAuthenticatorData < yOffset + 32) {
435
MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_INVALID_STATE_ERR);
436
}
437
438
authenticatorData.AppendElement(0x05); // Reserved Byte
439
authenticatorData.AppendElement(0x04); // ECC Uncompressed Key
440
authenticatorData.AppendElements(
441
pWebAuthNCredentialAttestation->pbAuthenticatorData + xOffset,
442
32); // X Coordinate
443
authenticatorData.AppendElements(
444
pWebAuthNCredentialAttestation->pbAuthenticatorData + yOffset,
445
32); // Y Coordinate
446
authenticatorData.AppendElement(
447
pWebAuthNCredentialAttestation->cbCredentialId);
448
authenticatorData.AppendElements(
449
pWebAuthNCredentialAttestation->pbCredentialId,
450
pWebAuthNCredentialAttestation->cbCredentialId);
451
authenticatorData.AppendElements(attestation->pX5c->pbData,
452
attestation->pX5c->cbData);
453
authenticatorData.AppendElements(attestation->pbSignature,
454
attestation->cbSignature);
455
}
456
457
nsTArray<WebAuthnExtensionResult> extensions;
458
459
if (pWebAuthNCredentialAttestation->dwVersion >=
460
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2) {
461
PCWEBAUTHN_EXTENSIONS pExtensionList =
462
&pWebAuthNCredentialAttestation->Extensions;
463
if (pExtensionList->cExtensions != 0 &&
464
pExtensionList->pExtensions != NULL) {
465
for (DWORD dwIndex = 0; dwIndex < pExtensionList->cExtensions;
466
dwIndex++) {
467
PWEBAUTHN_EXTENSION pExtension =
468
&pExtensionList->pExtensions[dwIndex];
469
if (pExtension->pwszExtensionIdentifier &&
470
(0 == _wcsicmp(pExtension->pwszExtensionIdentifier,
471
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET)) &&
472
pExtension->cbExtension == sizeof(BOOL)) {
473
BOOL* pCredentialCreatedWithHmacSecret =
474
(BOOL*)pExtension->pvExtension;
475
if (*pCredentialCreatedWithHmacSecret) {
476
extensions.AppendElement(WebAuthnExtensionResultHmacSecret(true));
477
}
478
}
479
}
480
}
481
}
482
483
WebAuthnMakeCredentialResult result(aInfo.ClientDataJSON(), attObject,
484
credentialId, authenticatorData,
485
extensions);
486
487
Unused << mTransactionParent->SendConfirmRegister(aTransactionId, result);
488
ClearTransaction();
489
gWinWebauthnFreeCredentialAttestation(pWebAuthNCredentialAttestation);
490
491
} else {
492
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
493
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
494
495
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
496
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
497
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
498
_wcsicmp(errorName, L"UnknownError") == 0) {
499
aError = NS_ERROR_DOM_UNKNOWN_ERR;
500
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
501
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
502
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
503
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
504
}
505
506
MaybeAbortRegister(aTransactionId, aError);
507
}
508
}
509
510
void WinWebAuthnManager::MaybeAbortRegister(const uint64_t& aTransactionId,
511
const nsresult& aError) {
512
AbortTransaction(aTransactionId, aError);
513
}
514
515
void WinWebAuthnManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
516
const uint64_t& aTransactionId,
517
const WebAuthnGetAssertionInfo& aInfo) {
518
MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNSign"));
519
520
ClearTransaction();
521
mTransactionParent = aTransactionParent;
522
523
// User Verification Requirement
524
DWORD winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
525
526
// RPID
527
PCWSTR rpID = nullptr;
528
529
// Attachment
530
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
531
532
// AppId
533
BOOL bU2fAppIdUsed = FALSE;
534
BOOL* pbU2fAppIdUsed = nullptr;
535
PCWSTR winAppIdentifier = nullptr;
536
537
// Client Data
538
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
539
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, aInfo.ClientDataJSON().Length(),
540
(BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};
541
542
if (aInfo.Extra().isSome()) {
543
const auto& extra = aInfo.Extra().ref();
544
545
for (const WebAuthnExtension& ext : extra.Extensions()) {
546
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
547
winAppIdentifier =
548
ext.get_WebAuthnExtensionAppId().appIdentifier().get();
549
pbU2fAppIdUsed = &bU2fAppIdUsed;
550
break;
551
}
552
}
553
554
// RPID
555
rpID = aInfo.RpId().get();
556
557
// User Verification Requirement
558
UserVerificationRequirement userVerificationReq =
559
extra.userVerificationRequirement();
560
561
switch (userVerificationReq) {
562
case UserVerificationRequirement::Required:
563
winUserVerificationReq =
564
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
565
break;
566
case UserVerificationRequirement::Preferred:
567
winUserVerificationReq =
568
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
569
break;
570
case UserVerificationRequirement::Discouraged:
571
winUserVerificationReq =
572
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
573
break;
574
default:
575
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
576
break;
577
}
578
} else {
579
rpID = aInfo.Origin().get();
580
winAppIdentifier = aInfo.RpId().get();
581
pbU2fAppIdUsed = &bU2fAppIdUsed;
582
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2;
583
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
584
}
585
586
// allow Credentials
587
nsTArray<WEBAUTHN_CREDENTIAL_EX> allowCredentials;
588
WEBAUTHN_CREDENTIAL_EX* pAllowCredentials = nullptr;
589
nsTArray<WEBAUTHN_CREDENTIAL_EX*> allowCredentialsPtrs;
590
WEBAUTHN_CREDENTIAL_LIST allowCredentialList = {0};
591
WEBAUTHN_CREDENTIAL_LIST* pAllowCredentialList = nullptr;
592
593
for (auto& cred : aInfo.AllowList()) {
594
uint8_t transports = cred.transports();
595
DWORD winTransports = 0;
596
if (transports & U2F_AUTHENTICATOR_TRANSPORT_USB) {
597
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
598
}
599
if (transports & U2F_AUTHENTICATOR_TRANSPORT_NFC) {
600
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
601
}
602
if (transports & U2F_AUTHENTICATOR_TRANSPORT_BLE) {
603
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
604
}
605
if (transports & CTAP_AUTHENTICATOR_TRANSPORT_INTERNAL) {
606
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
607
}
608
609
WEBAUTHN_CREDENTIAL_EX credential = {
610
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
611
static_cast<DWORD>(cred.id().Length()), (PBYTE)(cred.id().Elements()),
612
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
613
allowCredentials.AppendElement(credential);
614
}
615
616
if (allowCredentials.Length()) {
617
pAllowCredentials = allowCredentials.Elements();
618
for (DWORD i = 0; i < allowCredentials.Length(); i++) {
619
allowCredentialsPtrs.AppendElement(&pAllowCredentials[i]);
620
}
621
allowCredentialList.cCredentials = allowCredentials.Length();
622
allowCredentialList.ppCredentials = allowCredentialsPtrs.Elements();
623
pAllowCredentialList = &allowCredentialList;
624
}
625
626
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS WebAuthNAssertionOptions = {
627
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION,
628
aInfo.TimeoutMS(),
629
{0, NULL},
630
{0, NULL},
631
WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY,
632
winUserVerificationReq,
633
0, // dwFlags
634
winAppIdentifier,
635
pbU2fAppIdUsed,
636
nullptr, // pCancellationId
637
pAllowCredentialList,
638
};
639
640
GUID cancellationId = {0};
641
if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) {
642
WebAuthNAssertionOptions.pCancellationId = &cancellationId;
643
mCancellationIds.emplace(aTransactionId, &cancellationId);
644
}
645
646
PWEBAUTHN_ASSERTION pWebAuthNAssertion = nullptr;
647
648
// Bug 1518876: Get Window Handle from Content process for Windows WebAuthN
649
// APIs
650
HWND hWnd = GetForegroundWindow();
651
652
HRESULT hr =
653
gWinWebauthnGetAssertion(hWnd, rpID, &WebAuthNClientData,
654
&WebAuthNAssertionOptions, &pWebAuthNAssertion);
655
656
mCancellationIds.erase(aTransactionId);
657
658
if (hr == S_OK) {
659
nsTArray<uint8_t> signature;
660
if (aInfo.Extra().isSome()) {
661
signature.AppendElements(pWebAuthNAssertion->pbSignature,
662
pWebAuthNAssertion->cbSignature);
663
} else {
664
// AuthenticatorData Length check.
665
// First 32 bytes: RPID Hash
666
// Next 1 byte: Flags
667
// Next 4 bytes: Counter
668
if (pWebAuthNAssertion->cbAuthenticatorData < 32 + 1 + 4) {
669
MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_INVALID_STATE_ERR);
670
}
671
672
signature.AppendElement(0x01); // User Presence bit
673
signature.AppendElements(pWebAuthNAssertion->pbAuthenticatorData +
674
32 + // RPID Hash length
675
1, // Flags
676
4); // Counter length
677
signature.AppendElements(pWebAuthNAssertion->pbSignature,
678
pWebAuthNAssertion->cbSignature);
679
}
680
681
nsTArray<uint8_t> keyHandle;
682
keyHandle.AppendElements(pWebAuthNAssertion->Credential.pbId,
683
pWebAuthNAssertion->Credential.cbId);
684
685
nsTArray<uint8_t> userHandle;
686
userHandle.AppendElements(pWebAuthNAssertion->pbUserId,
687
pWebAuthNAssertion->cbUserId);
688
689
nsTArray<uint8_t> authenticatorData;
690
authenticatorData.AppendElements(pWebAuthNAssertion->pbAuthenticatorData,
691
pWebAuthNAssertion->cbAuthenticatorData);
692
693
nsTArray<WebAuthnExtensionResult> extensions;
694
695
if (pbU2fAppIdUsed && *pbU2fAppIdUsed) {
696
extensions.AppendElement(WebAuthnExtensionResultAppId(true));
697
}
698
699
WebAuthnGetAssertionResult result(aInfo.ClientDataJSON(), keyHandle,
700
signature, authenticatorData, extensions,
701
signature, userHandle);
702
703
Unused << mTransactionParent->SendConfirmSign(aTransactionId, result);
704
ClearTransaction();
705
706
gWinWebauthnFreeAssertion(pWebAuthNAssertion);
707
708
} else {
709
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
710
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
711
712
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
713
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
714
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
715
_wcsicmp(errorName, L"UnknownError") == 0) {
716
aError = NS_ERROR_DOM_UNKNOWN_ERR;
717
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
718
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
719
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
720
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
721
}
722
723
MaybeAbortSign(aTransactionId, aError);
724
}
725
}
726
727
void WinWebAuthnManager::MaybeAbortSign(const uint64_t& aTransactionId,
728
const nsresult& aError) {
729
AbortTransaction(aTransactionId, aError);
730
}
731
732
void WinWebAuthnManager::Cancel(PWebAuthnTransactionParent* aParent,
733
const uint64_t& aTransactionId) {
734
if (mTransactionParent != aParent) {
735
return;
736
}
737
738
ClearTransaction();
739
740
auto iter = mCancellationIds.find(aTransactionId);
741
if (iter != mCancellationIds.end()) {
742
gWinWebauthnCancelCurrentOperation(iter->second);
743
}
744
}
745
746
} // namespace dom
747
} // namespace mozilla