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/. */
7 #import <AuthenticationServices/AuthenticationServices.h>
9 #include "MacOSWebAuthnService.h"
11 #include "CFTypeRefPtr.h"
12 #include "WebAuthnAutoFillEntry.h"
13 #include "WebAuthnEnumStrings.h"
14 #include "WebAuthnResult.h"
15 #include "WebAuthnTransportIdentifiers.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/StaticPrefs_security.h"
18 #include "mozilla/dom/CanonicalBrowsingContext.h"
19 #include "nsCocoaUtils.h"
20 #include "nsIWebAuthnPromise.h"
21 #include "nsThreadUtils.h"
23 // The documentation for the platform APIs used here can be found at:
24 // https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys
27 static mozilla::LazyLogModule gMacOSWebAuthnServiceLog("macoswebauthnservice");
30 namespace mozilla::dom {
31 class API_AVAILABLE(macos(13.3)) MacOSWebAuthnService;
32 } // namespace mozilla::dom
34 // The following ASC* declarations are from the private framework
35 // AuthenticationServicesCore. The full definitions can be found in WebKit's
36 // source at Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h.
37 // Overriding ASAuthorizationController's _requestContextWithRequests is
38 // currently the only way to provide the right information to the macOS
39 // WebAuthn API (namely, the clientDataHash for requests made to physical
42 NS_ASSUME_NONNULL_BEGIN
44 @class ASCPublicKeyCredentialDescriptor;
45 @interface ASCPublicKeyCredentialDescriptor : NSObject <NSSecureCoding>
46 - (instancetype)initWithCredentialID:(NSData*)credentialID
48 (nullable NSArray<NSString*>*)allowedTransports;
51 @protocol ASCPublicKeyCredentialCreationOptions
52 @property(nonatomic, copy) NSData* clientDataHash;
53 @property(nonatomic, nullable, copy) NSData* challenge;
54 @property(nonatomic, copy)
55 NSArray<ASCPublicKeyCredentialDescriptor*>* excludedCredentials;
58 @protocol ASCPublicKeyCredentialAssertionOptions <NSCopying>
59 @property(nonatomic, copy) NSData* clientDataHash;
62 @protocol ASCCredentialRequestContext
63 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialCreationOptions>
64 platformKeyCredentialCreationOptions;
65 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialCreationOptions>
66 securityKeyCredentialCreationOptions;
67 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialAssertionOptions>
68 platformKeyCredentialAssertionOptions;
69 @property(nonatomic, nullable, copy) id<ASCPublicKeyCredentialAssertionOptions>
70 securityKeyCredentialAssertionOptions;
73 @interface ASAuthorizationController (Secrets)
74 - (id<ASCCredentialRequestContext>)
75 _requestContextWithRequests:(NSArray<ASAuthorizationRequest*>*)requests
76 error:(NSError**)outError;
79 NSArray<NSString*>* TransportsByteToTransportsArray(const uint8_t aTransports)
80 API_AVAILABLE(macos(13.3)) {
81 NSMutableArray<NSString*>* transportsNS = [[NSMutableArray alloc] init];
82 if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) ==
83 MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
86 ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportUSB];
88 if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) ==
89 MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
92 ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportNFC];
94 if ((aTransports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) ==
95 MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
98 ASAuthorizationSecurityKeyPublicKeyCredentialDescriptorTransportBluetooth];
100 // TODO (bug 1859367): the platform doesn't have a definition for "internal"
101 // transport. When it does, this code should be updated to handle it.
105 NSArray* CredentialListsToCredentialDescriptorArray(
106 const nsTArray<nsTArray<uint8_t>>& aCredentialList,
107 const nsTArray<uint8_t>& aCredentialListTransports,
108 const Class credentialDescriptorClass) API_AVAILABLE(macos(13.3)) {
109 MOZ_ASSERT(aCredentialList.Length() == aCredentialListTransports.Length());
110 NSMutableArray* credentials = [[NSMutableArray alloc] init];
111 for (size_t i = 0; i < aCredentialList.Length(); i++) {
112 const nsTArray<uint8_t>& credentialId = aCredentialList[i];
113 const uint8_t& credentialTransports = aCredentialListTransports[i];
114 NSData* credentialIdNS = [NSData dataWithBytes:credentialId.Elements()
115 length:credentialId.Length()];
116 NSArray<NSString*>* credentialTransportsNS =
117 TransportsByteToTransportsArray(credentialTransports);
118 NSObject* credential = [[credentialDescriptorClass alloc]
119 initWithCredentialID:credentialIdNS
120 transports:credentialTransportsNS];
121 [credentials addObject:credential];
126 // MacOSAuthorizationController is an ASAuthorizationController that overrides
127 // _requestContextWithRequests so that the implementation can set some options
128 // that aren't directly settable using the public API.
129 API_AVAILABLE(macos(13.3))
130 @interface MacOSAuthorizationController : ASAuthorizationController
133 @implementation MacOSAuthorizationController {
134 nsTArray<uint8_t> mClientDataHash;
135 nsTArray<nsTArray<uint8_t>> mCredentialList;
136 nsTArray<uint8_t> mCredentialListTransports;
139 - (void)setRegistrationOptions:
140 (id<ASCPublicKeyCredentialCreationOptions>)registrationOptions {
141 registrationOptions.clientDataHash =
142 [NSData dataWithBytes:mClientDataHash.Elements()
143 length:mClientDataHash.Length()];
144 // Unset challenge so that the implementation uses clientDataHash (the API
145 // returns an error otherwise).
146 registrationOptions.challenge = nil;
147 const Class publicKeyCredentialDescriptorClass =
148 NSClassFromString(@"ASCPublicKeyCredentialDescriptor");
149 NSArray<ASCPublicKeyCredentialDescriptor*>* excludedCredentials =
150 CredentialListsToCredentialDescriptorArray(
151 mCredentialList, mCredentialListTransports,
152 publicKeyCredentialDescriptorClass);
153 if ([excludedCredentials count] > 0) {
154 registrationOptions.excludedCredentials = excludedCredentials;
158 - (void)stashClientDataHash:(nsTArray<uint8_t>&&)clientDataHash
159 andCredentialList:(nsTArray<nsTArray<uint8_t>>&&)credentialList
160 andCredentialListTransports:(nsTArray<uint8_t>&&)credentialListTransports {
161 mClientDataHash = std::move(clientDataHash);
162 mCredentialList = std::move(credentialList);
163 mCredentialListTransports = std::move(credentialListTransports);
166 - (id<ASCCredentialRequestContext>)
167 _requestContextWithRequests:(NSArray<ASAuthorizationRequest*>*)requests
168 error:(NSError**)outError {
169 id<ASCCredentialRequestContext> context =
170 [super _requestContextWithRequests:requests error:outError];
172 if (context.platformKeyCredentialCreationOptions) {
173 [self setRegistrationOptions:context.platformKeyCredentialCreationOptions];
175 if (context.securityKeyCredentialCreationOptions) {
176 [self setRegistrationOptions:context.securityKeyCredentialCreationOptions];
179 if (context.platformKeyCredentialAssertionOptions) {
180 id<ASCPublicKeyCredentialAssertionOptions> assertionOptions =
181 context.platformKeyCredentialAssertionOptions;
182 assertionOptions.clientDataHash =
183 [NSData dataWithBytes:mClientDataHash.Elements()
184 length:mClientDataHash.Length()];
185 context.platformKeyCredentialAssertionOptions =
186 [assertionOptions copyWithZone:nil];
188 if (context.securityKeyCredentialAssertionOptions) {
189 id<ASCPublicKeyCredentialAssertionOptions> assertionOptions =
190 context.securityKeyCredentialAssertionOptions;
191 assertionOptions.clientDataHash =
192 [NSData dataWithBytes:mClientDataHash.Elements()
193 length:mClientDataHash.Length()];
194 context.securityKeyCredentialAssertionOptions =
195 [assertionOptions copyWithZone:nil];
202 // MacOSAuthenticatorRequestDelegate is an ASAuthorizationControllerDelegate,
203 // which can be set as an ASAuthorizationController's delegate to be called
204 // back when a request for a platform authenticator attestation or assertion
205 // response completes either with an attestation or assertion
206 // (didCompleteWithAuthorization) or with an error (didCompleteWithError).
207 API_AVAILABLE(macos(13.3))
208 @interface MacOSAuthenticatorRequestDelegate
209 : NSObject <ASAuthorizationControllerDelegate>
210 - (void)setCallback:(mozilla::dom::MacOSWebAuthnService*)callback;
213 // MacOSAuthenticatorPresentationContextProvider is an
214 // ASAuthorizationControllerPresentationContextProviding, which can be set as
215 // an ASAuthorizationController's presentationContextProvider, and provides a
216 // presentation anchor for the ASAuthorizationController. Basically, this
217 // provides the API a handle to the window that made the request.
218 API_AVAILABLE(macos(13.3))
219 @interface MacOSAuthenticatorPresentationContextProvider
220 : NSObject <ASAuthorizationControllerPresentationContextProviding>
221 @property(nonatomic, strong) NSWindow* window;
224 namespace mozilla::dom {
226 #pragma clang diagnostic push
227 #pragma clang diagnostic ignored "-Wnullability-completeness"
228 class API_AVAILABLE(macos(13.3)) MacOSWebAuthnService final
229 : public nsIWebAuthnService {
231 MacOSWebAuthnService()
232 : mTransactionState(Nothing(),
233 "MacOSWebAuthnService::mTransactionState") {}
235 NS_DECL_THREADSAFE_ISUPPORTS
236 NS_DECL_NSIWEBAUTHNSERVICE
238 void FinishMakeCredential(const nsTArray<uint8_t>& aRawAttestationObject,
239 const nsTArray<uint8_t>& aCredentialId,
240 const nsTArray<nsString>& aTransports,
241 const Maybe<nsString>& aAuthenticatorAttachment);
243 void FinishGetAssertion(const nsTArray<uint8_t>& aCredentialId,
244 const nsTArray<uint8_t>& aSignature,
245 const nsTArray<uint8_t>& aAuthenticatorData,
246 const nsTArray<uint8_t>& aUserHandle,
247 const Maybe<nsString>& aAuthenticatorAttachment);
248 void ReleasePlatformResources();
249 void AbortTransaction(nsresult aError);
252 ~MacOSWebAuthnService() = default;
254 void PerformRequests(NSArray<ASAuthorizationRequest*>* aRequests,
255 nsTArray<uint8_t>&& aClientDataHash,
256 nsTArray<nsTArray<uint8_t>>&& aCredentialList,
257 nsTArray<uint8_t>&& aCredentialListTransports,
258 uint64_t aBrowsingContextId);
260 struct TransactionState {
261 uint64_t transactionId;
262 uint64_t browsingContextId;
263 Maybe<RefPtr<nsIWebAuthnSignArgs>> pendingSignArgs;
264 Maybe<RefPtr<nsIWebAuthnSignPromise>> pendingSignPromise;
265 Maybe<nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>> autoFillEntries;
268 using TransactionStateMutex = DataMutex<Maybe<TransactionState>>;
269 void DoGetAssertion(Maybe<nsTArray<uint8_t>>&& aSelectedCredentialId,
270 const TransactionStateMutex::AutoLock& aGuard);
272 TransactionStateMutex mTransactionState;
275 ASAuthorizationWebBrowserPublicKeyCredentialManager* mCredentialManager = nil;
276 nsCOMPtr<nsIWebAuthnRegisterPromise> mRegisterPromise;
277 nsCOMPtr<nsIWebAuthnSignPromise> mSignPromise;
278 MacOSAuthorizationController* mAuthorizationController = nil;
279 MacOSAuthenticatorRequestDelegate* mRequestDelegate = nil;
280 MacOSAuthenticatorPresentationContextProvider* mPresentationContextProvider =
283 #pragma clang diagnostic pop
285 } // namespace mozilla::dom
287 nsTArray<uint8_t> NSDataToArray(NSData* data) {
288 nsTArray<uint8_t> array(reinterpret_cast<const uint8_t*>(data.bytes),
293 @implementation MacOSAuthenticatorRequestDelegate {
294 RefPtr<mozilla::dom::MacOSWebAuthnService> mCallback;
297 - (void)setCallback:(mozilla::dom::MacOSWebAuthnService*)callback {
298 mCallback = callback;
301 - (void)authorizationController:(ASAuthorizationController*)controller
302 didCompleteWithAuthorization:(ASAuthorization*)authorization {
303 if ([authorization.credential
305 @protocol(ASAuthorizationPublicKeyCredentialRegistration)]) {
306 MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
307 ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
308 "got registration"));
309 id<ASAuthorizationPublicKeyCredentialRegistration> credential =
310 (id<ASAuthorizationPublicKeyCredentialRegistration>)
311 authorization.credential;
312 nsTArray<uint8_t> rawAttestationObject(
313 NSDataToArray(credential.rawAttestationObject));
314 nsTArray<uint8_t> credentialId(NSDataToArray(credential.credentialID));
315 nsTArray<nsString> transports;
316 mozilla::Maybe<nsString> authenticatorAttachment;
317 if ([credential isKindOfClass:
318 [ASAuthorizationPlatformPublicKeyCredentialRegistration
320 transports.AppendElement(u"internal"_ns);
321 #if defined(MAC_OS_VERSION_13_5) && \
322 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_5
323 if (__builtin_available(macos 13.5, *)) {
324 ASAuthorizationPlatformPublicKeyCredentialRegistration*
326 (ASAuthorizationPlatformPublicKeyCredentialRegistration*)
328 switch (platformCredential.attachment) {
329 case ASAuthorizationPublicKeyCredentialAttachmentCrossPlatform:
330 authenticatorAttachment.emplace(u"cross-platform"_ns);
332 case ASAuthorizationPublicKeyCredentialAttachmentPlatform:
333 authenticatorAttachment.emplace(u"platform"_ns);
341 // The platform didn't tell us what transport was used, but we know it
342 // wasn't the internal transport. The transport response is not signed by
343 // the authenticator. It represents the "transports that the authenticator
344 // is believed to support, or an empty sequence if the information is
345 // unavailable". We believe macOS supports usb, so we return usb.
346 transports.AppendElement(u"usb"_ns);
347 authenticatorAttachment.emplace(u"cross-platform"_ns);
349 mCallback->FinishMakeCredential(rawAttestationObject, credentialId,
350 transports, authenticatorAttachment);
351 } else if ([authorization.credential
353 @protocol(ASAuthorizationPublicKeyCredentialAssertion)]) {
354 MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
355 ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
357 id<ASAuthorizationPublicKeyCredentialAssertion> credential =
358 (id<ASAuthorizationPublicKeyCredentialAssertion>)
359 authorization.credential;
360 nsTArray<uint8_t> credentialId(NSDataToArray(credential.credentialID));
361 nsTArray<uint8_t> signature(NSDataToArray(credential.signature));
362 nsTArray<uint8_t> rawAuthenticatorData(
363 NSDataToArray(credential.rawAuthenticatorData));
364 nsTArray<uint8_t> userHandle(NSDataToArray(credential.userID));
365 mozilla::Maybe<nsString> authenticatorAttachment;
367 isKindOfClass:[ASAuthorizationPlatformPublicKeyCredentialAssertion
369 #if defined(MAC_OS_VERSION_13_5) && \
370 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_5
371 if (__builtin_available(macos 13.5, *)) {
372 ASAuthorizationPlatformPublicKeyCredentialAssertion*
374 (ASAuthorizationPlatformPublicKeyCredentialAssertion*)
376 switch (platformCredential.attachment) {
377 case ASAuthorizationPublicKeyCredentialAttachmentCrossPlatform:
378 authenticatorAttachment.emplace(u"cross-platform"_ns);
380 case ASAuthorizationPublicKeyCredentialAttachmentPlatform:
381 authenticatorAttachment.emplace(u"platform"_ns);
389 authenticatorAttachment.emplace(u"cross-platform"_ns);
391 mCallback->FinishGetAssertion(credentialId, signature, rawAuthenticatorData,
392 userHandle, authenticatorAttachment);
395 gMacOSWebAuthnServiceLog, mozilla::LogLevel::Error,
396 ("MacOSAuthenticatorRequestDelegate::didCompleteWithAuthorization: "
397 "authorization.credential is neither registration nor assertion!"));
398 MOZ_ASSERT_UNREACHABLE(
399 "should have ASAuthorizationPublicKeyCredentialRegistration or "
400 "ASAuthorizationPublicKeyCredentialAssertion");
402 mCallback->ReleasePlatformResources();
406 - (void)authorizationController:(ASAuthorizationController*)controller
407 didCompleteWithError:(NSError*)error {
408 nsAutoString errorDescription;
409 nsCocoaUtils::GetStringForNSString(error.localizedDescription,
411 nsAutoString errorDomain;
412 nsCocoaUtils::GetStringForNSString(error.domain, errorDomain);
413 MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Warning,
414 ("MacOSAuthenticatorRequestDelegate::didCompleteWithError: domain "
415 "'%s' code %ld (%s)",
416 NS_ConvertUTF16toUTF8(errorDomain).get(), error.code,
417 NS_ConvertUTF16toUTF8(errorDescription).get()));
418 nsresult rv = NS_ERROR_DOM_NOT_ALLOWED_ERR;
419 // For some reason, the error for "the credential used in a registration was
420 // on the exclude list" is in the "WKErrorDomain" domain with code 8, which
421 // is presumably WKErrorDuplicateCredential.
422 const NSInteger WKErrorDuplicateCredential = 8;
423 if (errorDomain.EqualsLiteral("WKErrorDomain") &&
424 error.code == WKErrorDuplicateCredential) {
425 rv = NS_ERROR_DOM_INVALID_STATE_ERR;
426 } else if (error.domain == ASAuthorizationErrorDomain) {
427 switch (error.code) {
428 case ASAuthorizationErrorCanceled:
429 rv = NS_ERROR_DOM_ABORT_ERR;
431 case ASAuthorizationErrorFailed:
432 // The message is right, but it's not about indexeddb.
433 // See https://webidl.spec.whatwg.org/#constrainterror
434 rv = NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
436 case ASAuthorizationErrorUnknown:
437 rv = NS_ERROR_DOM_UNKNOWN_ERR;
440 // rv already has a default value
444 mCallback->AbortTransaction(rv);
449 @implementation MacOSAuthenticatorPresentationContextProvider
450 @synthesize window = window;
452 - (ASPresentationAnchor)presentationAnchorForAuthorizationController:
453 (ASAuthorizationController*)controller {
458 namespace mozilla::dom {
460 #pragma clang diagnostic push
461 #pragma clang diagnostic ignored "-Wnullability-completeness"
462 // Given a browsingContextId, attempts to determine the NSWindow associated
463 // with that browser.
464 nsresult BrowsingContextIdToNSWindow(uint64_t browsingContextId,
467 RefPtr<BrowsingContext> browsingContext(
468 BrowsingContext::Get(browsingContextId));
469 if (!browsingContext) {
470 return NS_ERROR_NOT_AVAILABLE;
472 CanonicalBrowsingContext* canonicalBrowsingContext =
473 browsingContext->Canonical();
474 if (!canonicalBrowsingContext) {
475 return NS_ERROR_NOT_AVAILABLE;
477 nsCOMPtr<nsIWidget> widget(
478 canonicalBrowsingContext->GetParentProcessWidgetContaining());
480 return NS_ERROR_NOT_AVAILABLE;
482 *window = static_cast<NSWindow*>(widget->GetNativeData(NS_NATIVE_WINDOW));
485 #pragma clang diagnostic pop
487 already_AddRefed<nsIWebAuthnService> NewMacOSWebAuthnServiceIfAvailable() {
488 MOZ_ASSERT(XRE_IsParentProcess());
489 if (!StaticPrefs::security_webauthn_enable_macos_passkeys()) {
491 gMacOSWebAuthnServiceLog, LogLevel::Debug,
492 ("macOS platform support for webauthn (passkeys) disabled by pref"));
495 // This code checks for the entitlement
496 // 'com.apple.developer.web-browser.public-key-credential', which must be
497 // true to be able to use the platform APIs.
498 CFTypeRefPtr<SecTaskRef> entitlementTask(
499 CFTypeRefPtr<SecTaskRef>::WrapUnderCreateRule(
500 SecTaskCreateFromSelf(nullptr)));
501 CFTypeRefPtr<CFBooleanRef> entitlementValue(
502 CFTypeRefPtr<CFBooleanRef>::WrapUnderCreateRule(
503 reinterpret_cast<CFBooleanRef>(SecTaskCopyValueForEntitlement(
504 entitlementTask.get(),
505 CFSTR("com.apple.developer.web-browser.public-key-credential"),
507 if (!entitlementValue || !CFBooleanGetValue(entitlementValue.get())) {
509 gMacOSWebAuthnServiceLog, LogLevel::Warning,
510 ("entitlement com.apple.developer.web-browser.public-key-credential "
511 "not present: platform passkey APIs will not be available"));
514 nsCOMPtr<nsIWebAuthnService> service(new MacOSWebAuthnService());
515 return service.forget();
518 void MacOSWebAuthnService::AbortTransaction(nsresult aError) {
519 MOZ_ASSERT(NS_IsMainThread());
520 if (mRegisterPromise) {
521 Unused << mRegisterPromise->Reject(aError);
522 mRegisterPromise = nullptr;
525 Unused << mSignPromise->Reject(aError);
526 mSignPromise = nullptr;
528 ReleasePlatformResources();
531 #pragma clang diagnostic push
532 #pragma clang diagnostic ignored "-Wnullability-completeness"
533 NS_IMPL_ISUPPORTS(MacOSWebAuthnService, nsIWebAuthnService)
534 #pragma clang diagnostic pop
537 MacOSWebAuthnService::MakeCredential(uint64_t aTransactionId,
538 uint64_t aBrowsingContextId,
539 nsIWebAuthnRegisterArgs* aArgs,
540 nsIWebAuthnRegisterPromise* aPromise) {
542 auto guard = mTransactionState.Lock();
543 *guard = Some(TransactionState{
550 NS_DispatchToMainThread(NS_NewRunnableFunction(
551 "MacOSWebAuthnService::MakeCredential",
552 [self = RefPtr{this}, browsingContextId(aBrowsingContextId),
553 aArgs = nsCOMPtr{aArgs}, aPromise = nsCOMPtr{aPromise}]() {
554 // Bug 1884574 - The Reset() call above should have cancelled any
555 // transactions that were dispatched to the platform, the platform
556 // should have called didCompleteWithError, and didCompleteWithError
557 // should have rejected the pending promise. However, in some scenarios,
558 // the platform fails to call the callback, and this leads to a
559 // diagnostic assertion failure when we drop `mRegisterPromise`. Avoid
560 // this by aborting the transaction here.
561 if (self->mRegisterPromise) {
562 MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
563 ("MacOSAuthenticatorRequestDelegate::MakeCredential: "
564 "platform failed to call callback"));
565 self->AbortTransaction(NS_ERROR_DOM_ABORT_ERR);
567 self->mRegisterPromise = aPromise;
570 Unused << aArgs->GetRpId(rpId);
571 NSString* rpIdNS = nsCocoaUtils::ToNSString(rpId);
573 nsTArray<uint8_t> challenge;
574 Unused << aArgs->GetChallenge(challenge);
575 NSData* challengeNS = [NSData dataWithBytes:challenge.Elements()
576 length:challenge.Length()];
578 nsTArray<uint8_t> userId;
579 Unused << aArgs->GetUserId(userId);
580 NSData* userIdNS = [NSData dataWithBytes:userId.Elements()
581 length:userId.Length()];
583 nsAutoString userName;
584 Unused << aArgs->GetUserName(userName);
585 NSString* userNameNS = nsCocoaUtils::ToNSString(userName);
587 nsAutoString userDisplayName;
588 Unused << aArgs->GetUserName(userDisplayName);
589 NSString* userDisplayNameNS = nsCocoaUtils::ToNSString(userDisplayName);
591 nsTArray<int32_t> coseAlgs;
592 Unused << aArgs->GetCoseAlgs(coseAlgs);
593 NSMutableArray* credentialParameters = [[NSMutableArray alloc] init];
594 for (const auto& coseAlg : coseAlgs) {
595 ASAuthorizationPublicKeyCredentialParameters* credentialParameter =
596 [[ASAuthorizationPublicKeyCredentialParameters alloc]
597 initWithAlgorithm:coseAlg];
598 [credentialParameters addObject:credentialParameter];
601 nsTArray<nsTArray<uint8_t>> excludeList;
602 Unused << aArgs->GetExcludeList(excludeList);
603 nsTArray<uint8_t> excludeListTransports;
604 Unused << aArgs->GetExcludeListTransports(excludeListTransports);
605 if (excludeList.Length() != excludeListTransports.Length()) {
606 self->mRegisterPromise->Reject(NS_ERROR_INVALID_ARG);
610 Maybe<ASAuthorizationPublicKeyCredentialUserVerificationPreference>
611 userVerificationPreference = Nothing();
612 nsAutoString userVerification;
613 Unused << aArgs->GetUserVerification(userVerification);
614 if (userVerification.EqualsLiteral(
615 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
616 userVerificationPreference.emplace(
617 ASAuthorizationPublicKeyCredentialUserVerificationPreferenceRequired);
618 } else if (userVerification.EqualsLiteral(
619 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
620 userVerificationPreference.emplace(
621 ASAuthorizationPublicKeyCredentialUserVerificationPreferencePreferred);
623 userVerification.EqualsLiteral(
624 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED)) {
625 userVerificationPreference.emplace(
626 ASAuthorizationPublicKeyCredentialUserVerificationPreferenceDiscouraged);
629 // The API doesn't support attestation for platform passkeys and shows
630 // no consent UI for non-none attestation for cross-platform devices,
631 // so this must always be none.
632 ASAuthorizationPublicKeyCredentialAttestationKind
633 attestationPreference =
634 ASAuthorizationPublicKeyCredentialAttestationKindNone;
636 // Initialize the platform provider with the rpId.
637 ASAuthorizationPlatformPublicKeyCredentialProvider* platformProvider =
638 [[ASAuthorizationPlatformPublicKeyCredentialProvider alloc]
639 initWithRelyingPartyIdentifier:rpIdNS];
640 // Make a credential registration request with the challenge, userName,
642 ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest*
643 platformRegistrationRequest = [platformProvider
644 createCredentialRegistrationRequestWithChallenge:challengeNS
647 [platformProvider release];
648 platformRegistrationRequest.attestationPreference =
649 attestationPreference;
650 if (userVerificationPreference.isSome()) {
651 platformRegistrationRequest.userVerificationPreference =
652 *userVerificationPreference;
655 // Initialize the cross-platform provider with the rpId.
656 ASAuthorizationSecurityKeyPublicKeyCredentialProvider*
657 crossPlatformProvider =
658 [[ASAuthorizationSecurityKeyPublicKeyCredentialProvider alloc]
659 initWithRelyingPartyIdentifier:rpIdNS];
660 // Make a credential registration request with the challenge,
661 // userDisplayName, userName, and userId.
662 ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest*
663 crossPlatformRegistrationRequest = [crossPlatformProvider
664 createCredentialRegistrationRequestWithChallenge:challengeNS
669 [crossPlatformProvider release];
670 crossPlatformRegistrationRequest.attestationPreference =
671 attestationPreference;
672 crossPlatformRegistrationRequest.credentialParameters =
673 credentialParameters;
674 if (userVerificationPreference.isSome()) {
675 crossPlatformRegistrationRequest.userVerificationPreference =
676 *userVerificationPreference;
678 nsTArray<uint8_t> clientDataHash;
679 nsresult rv = aArgs->GetClientDataHash(clientDataHash);
681 self->mRegisterPromise->Reject(rv);
684 nsAutoString authenticatorAttachment;
685 rv = aArgs->GetAuthenticatorAttachment(authenticatorAttachment);
686 if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) {
687 self->mRegisterPromise->Reject(rv);
690 NSMutableArray* requests = [[NSMutableArray alloc] init];
691 if (authenticatorAttachment.EqualsLiteral(
692 MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
693 [requests addObject:platformRegistrationRequest];
694 } else if (authenticatorAttachment.EqualsLiteral(
695 MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
696 [requests addObject:crossPlatformRegistrationRequest];
698 // Regarding the value of authenticator attachment, according to the
699 // specification, "client platforms MUST ignore unknown values,
700 // treating an unknown value as if the member does not exist".
701 [requests addObject:platformRegistrationRequest];
702 [requests addObject:crossPlatformRegistrationRequest];
704 self->PerformRequests(
705 requests, std::move(clientDataHash), std::move(excludeList),
706 std::move(excludeListTransports), browsingContextId);
711 void MacOSWebAuthnService::PerformRequests(
712 NSArray<ASAuthorizationRequest*>* aRequests,
713 nsTArray<uint8_t>&& aClientDataHash,
714 nsTArray<nsTArray<uint8_t>>&& aCredentialList,
715 nsTArray<uint8_t>&& aCredentialListTransports,
716 uint64_t aBrowsingContextId) {
717 MOZ_ASSERT(NS_IsMainThread());
718 // Create a MacOSAuthorizationController and initialize it with the requests.
719 MOZ_ASSERT(!mAuthorizationController);
720 mAuthorizationController = [[MacOSAuthorizationController alloc]
721 initWithAuthorizationRequests:aRequests];
722 [mAuthorizationController
723 stashClientDataHash:std::move(aClientDataHash)
724 andCredentialList:std::move(aCredentialList)
725 andCredentialListTransports:std::move(aCredentialListTransports)];
727 // Set up the delegate to run when the operation completes.
728 MOZ_ASSERT(!mRequestDelegate);
729 mRequestDelegate = [[MacOSAuthenticatorRequestDelegate alloc] init];
730 [mRequestDelegate setCallback:this];
731 mAuthorizationController.delegate = mRequestDelegate;
733 // Create a presentation context provider so the API knows which window
735 NSWindow* window = nullptr;
736 nsresult rv = BrowsingContextIdToNSWindow(aBrowsingContextId, &window);
738 AbortTransaction(NS_ERROR_DOM_INVALID_STATE_ERR);
741 MOZ_ASSERT(!mPresentationContextProvider);
742 mPresentationContextProvider =
743 [[MacOSAuthenticatorPresentationContextProvider alloc] init];
744 mPresentationContextProvider.window = window;
745 mAuthorizationController.presentationContextProvider =
746 mPresentationContextProvider;
748 // Finally, perform the request.
749 [mAuthorizationController performRequests];
752 void MacOSWebAuthnService::FinishMakeCredential(
753 const nsTArray<uint8_t>& aRawAttestationObject,
754 const nsTArray<uint8_t>& aCredentialId,
755 const nsTArray<nsString>& aTransports,
756 const Maybe<nsString>& aAuthenticatorAttachment) {
757 MOZ_ASSERT(NS_IsMainThread());
758 if (!mRegisterPromise) {
762 RefPtr<WebAuthnRegisterResult> result(new WebAuthnRegisterResult(
763 aRawAttestationObject, Nothing(), aCredentialId, aTransports,
764 aAuthenticatorAttachment));
765 Unused << mRegisterPromise->Resolve(result);
766 mRegisterPromise = nullptr;
770 MacOSWebAuthnService::GetAssertion(uint64_t aTransactionId,
771 uint64_t aBrowsingContextId,
772 nsIWebAuthnSignArgs* aArgs,
773 nsIWebAuthnSignPromise* aPromise) {
776 auto guard = mTransactionState.Lock();
777 *guard = Some(TransactionState{
781 Some(RefPtr{aPromise}),
785 bool conditionallyMediated;
786 Unused << aArgs->GetConditionallyMediated(&conditionallyMediated);
787 if (!conditionallyMediated) {
788 DoGetAssertion(Nothing(), guard);
792 // Using conditional mediation, so dispatch a task to collect any available
794 NS_DispatchToMainThread(NS_NewRunnableFunction(
795 "platformCredentialsForRelyingParty",
796 [self = RefPtr{this}, aTransactionId, aArgs = nsCOMPtr{aArgs}]() {
797 // This handler is called when platformCredentialsForRelyingParty
799 auto credentialsCompletionHandler = ^(
800 NSArray<ASAuthorizationWebBrowserPlatformPublicKeyCredential*>*
802 nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>> autoFillEntries;
803 for (NSUInteger i = 0; i < credentials.count; i++) {
804 const auto& credential = credentials[i];
805 nsAutoString userName;
806 nsCocoaUtils::GetStringForNSString(credential.name, userName);
808 nsCocoaUtils::GetStringForNSString(credential.relyingParty, rpId);
809 autoFillEntries.AppendElement(new WebAuthnAutoFillEntry(
810 nsIWebAuthnAutoFillEntry::PROVIDER_PLATFORM_MACOS, userName,
811 rpId, NSDataToArray(credential.credentialID)));
813 auto guard = self->mTransactionState.Lock();
814 if (guard->isSome() && guard->ref().transactionId == aTransactionId) {
815 guard->ref().autoFillEntries.emplace(std::move(autoFillEntries));
818 // This handler is called when
819 // requestAuthorizationForPublicKeyCredentials completes.
820 auto authorizationHandler = ^(
821 ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState
822 authorizationState) {
823 // If authorized, list any available passkeys.
824 if (authorizationState ==
825 ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationStateAuthorized) {
827 Unused << aArgs->GetRpId(rpId);
828 [self->mCredentialManager
829 platformCredentialsForRelyingParty:nsCocoaUtils::ToNSString(
832 credentialsCompletionHandler];
835 if (!self->mCredentialManager) {
836 self->mCredentialManager =
837 [[ASAuthorizationWebBrowserPublicKeyCredentialManager alloc]
840 // Request authorization to examine any available passkeys. This will
841 // cause a permission prompt to appear once.
842 [self->mCredentialManager
843 requestAuthorizationForPublicKeyCredentials:authorizationHandler];
849 void MacOSWebAuthnService::DoGetAssertion(
850 Maybe<nsTArray<uint8_t>>&& aSelectedCredentialId,
851 const TransactionStateMutex::AutoLock& aGuard) {
852 if (aGuard->isNothing() || aGuard->ref().pendingSignArgs.isNothing() ||
853 aGuard->ref().pendingSignPromise.isNothing()) {
857 // Take the pending Args and Promise to prevent repeated calls to
858 // DoGetAssertion for this transaction.
859 RefPtr<nsIWebAuthnSignArgs> aArgs = aGuard->ref().pendingSignArgs.extract();
860 RefPtr<nsIWebAuthnSignPromise> aPromise =
861 aGuard->ref().pendingSignPromise.extract();
862 uint64_t aBrowsingContextId = aGuard->ref().browsingContextId;
864 NS_DispatchToMainThread(NS_NewRunnableFunction(
865 "MacOSWebAuthnService::MakeCredential",
866 [self = RefPtr{this}, browsingContextId(aBrowsingContextId), aArgs,
868 aSelectedCredentialId = std::move(aSelectedCredentialId)]() mutable {
869 // Bug 1884574 - This AbortTransaction call is necessary.
870 // See comment in MacOSWebAuthnService::MakeCredential.
871 if (self->mSignPromise) {
872 MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug,
873 ("MacOSAuthenticatorRequestDelegate::DoGetAssertion: "
874 "platform failed to call callback"));
875 self->AbortTransaction(NS_ERROR_DOM_ABORT_ERR);
877 self->mSignPromise = aPromise;
880 Unused << aArgs->GetRpId(rpId);
881 NSString* rpIdNS = nsCocoaUtils::ToNSString(rpId);
883 nsTArray<uint8_t> challenge;
884 Unused << aArgs->GetChallenge(challenge);
885 NSData* challengeNS = [NSData dataWithBytes:challenge.Elements()
886 length:challenge.Length()];
888 nsTArray<nsTArray<uint8_t>> allowList;
889 nsTArray<uint8_t> allowListTransports;
890 if (aSelectedCredentialId.isSome()) {
891 allowList.AppendElement(aSelectedCredentialId.extract());
892 allowListTransports.AppendElement(
893 MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL);
895 Unused << aArgs->GetAllowList(allowList);
896 Unused << aArgs->GetAllowListTransports(allowListTransports);
898 NSMutableArray* platformAllowedCredentials =
899 [[NSMutableArray alloc] init];
900 for (const auto& allowedCredentialId : allowList) {
901 NSData* allowedCredentialIdNS =
902 [NSData dataWithBytes:allowedCredentialId.Elements()
903 length:allowedCredentialId.Length()];
904 ASAuthorizationPlatformPublicKeyCredentialDescriptor*
906 [[ASAuthorizationPlatformPublicKeyCredentialDescriptor alloc]
907 initWithCredentialID:allowedCredentialIdNS];
908 [platformAllowedCredentials addObject:allowedCredential];
910 const Class securityKeyPublicKeyCredentialDescriptorClass =
912 @"ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor");
913 NSArray<ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor*>*
914 crossPlatformAllowedCredentials =
915 CredentialListsToCredentialDescriptorArray(
916 allowList, allowListTransports,
917 securityKeyPublicKeyCredentialDescriptorClass);
919 Maybe<ASAuthorizationPublicKeyCredentialUserVerificationPreference>
920 userVerificationPreference = Nothing();
921 nsAutoString userVerification;
922 Unused << aArgs->GetUserVerification(userVerification);
923 if (userVerification.EqualsLiteral(
924 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
925 userVerificationPreference.emplace(
926 ASAuthorizationPublicKeyCredentialUserVerificationPreferenceRequired);
927 } else if (userVerification.EqualsLiteral(
928 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
929 userVerificationPreference.emplace(
930 ASAuthorizationPublicKeyCredentialUserVerificationPreferencePreferred);
932 userVerification.EqualsLiteral(
933 MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED)) {
934 userVerificationPreference.emplace(
935 ASAuthorizationPublicKeyCredentialUserVerificationPreferenceDiscouraged);
938 // Initialize the platform provider with the rpId.
939 ASAuthorizationPlatformPublicKeyCredentialProvider* platformProvider =
940 [[ASAuthorizationPlatformPublicKeyCredentialProvider alloc]
941 initWithRelyingPartyIdentifier:rpIdNS];
942 // Make a credential assertion request with the challenge.
943 ASAuthorizationPlatformPublicKeyCredentialAssertionRequest*
944 platformAssertionRequest = [platformProvider
945 createCredentialAssertionRequestWithChallenge:challengeNS];
946 [platformProvider release];
947 platformAssertionRequest.allowedCredentials =
948 platformAllowedCredentials;
949 if (userVerificationPreference.isSome()) {
950 platformAssertionRequest.userVerificationPreference =
951 *userVerificationPreference;
954 // Initialize the cross-platform provider with the rpId.
955 ASAuthorizationSecurityKeyPublicKeyCredentialProvider*
956 crossPlatformProvider =
957 [[ASAuthorizationSecurityKeyPublicKeyCredentialProvider alloc]
958 initWithRelyingPartyIdentifier:rpIdNS];
959 // Make a credential assertion request with the challenge.
960 ASAuthorizationSecurityKeyPublicKeyCredentialAssertionRequest*
961 crossPlatformAssertionRequest = [crossPlatformProvider
962 createCredentialAssertionRequestWithChallenge:challengeNS];
963 [crossPlatformProvider release];
964 crossPlatformAssertionRequest.allowedCredentials =
965 crossPlatformAllowedCredentials;
966 if (userVerificationPreference.isSome()) {
967 crossPlatformAssertionRequest.userVerificationPreference =
968 *userVerificationPreference;
970 nsTArray<uint8_t> clientDataHash;
971 nsresult rv = aArgs->GetClientDataHash(clientDataHash);
973 self->mSignPromise->Reject(rv);
976 nsTArray<nsTArray<uint8_t>> unusedCredentialIds;
977 nsTArray<uint8_t> unusedTransports;
978 // allowList and allowListTransports won't actually get used.
979 self->PerformRequests(
980 @[ platformAssertionRequest, crossPlatformAssertionRequest ],
981 std::move(clientDataHash), std::move(allowList),
982 std::move(allowListTransports), browsingContextId);
986 void MacOSWebAuthnService::FinishGetAssertion(
987 const nsTArray<uint8_t>& aCredentialId, const nsTArray<uint8_t>& aSignature,
988 const nsTArray<uint8_t>& aAuthenticatorData,
989 const nsTArray<uint8_t>& aUserHandle,
990 const Maybe<nsString>& aAuthenticatorAttachment) {
991 MOZ_ASSERT(NS_IsMainThread());
996 RefPtr<WebAuthnSignResult> result(new WebAuthnSignResult(
997 aAuthenticatorData, Nothing(), aCredentialId, aSignature, aUserHandle,
998 aAuthenticatorAttachment));
999 Unused << mSignPromise->Resolve(result);
1000 mSignPromise = nullptr;
1003 void MacOSWebAuthnService::ReleasePlatformResources() {
1004 MOZ_ASSERT(NS_IsMainThread());
1005 [mCredentialManager release];
1006 mCredentialManager = nil;
1007 [mAuthorizationController release];
1008 mAuthorizationController = nil;
1009 [mRequestDelegate release];
1010 mRequestDelegate = nil;
1011 [mPresentationContextProvider release];
1012 mPresentationContextProvider = nil;
1016 MacOSWebAuthnService::Reset() {
1017 auto guard = mTransactionState.Lock();
1018 if (guard->isSome()) {
1019 if (guard->ref().pendingSignPromise.isSome()) {
1020 // This request was never dispatched to the platform API, so
1021 // we need to reject the promise ourselves.
1022 guard->ref().pendingSignPromise.ref()->Reject(
1023 NS_ERROR_DOM_NOT_ALLOWED_ERR);
1027 NS_DispatchToMainThread(NS_NewRunnableFunction(
1028 "MacOSWebAuthnService::Cancel", [self = RefPtr{this}] {
1029 // cancel results in the delegate's didCompleteWithError method being
1030 // called, which will release all platform resources.
1031 [self->mAuthorizationController cancel];
1037 MacOSWebAuthnService::GetIsUVPAA(bool* aAvailable) {
1043 MacOSWebAuthnService::Cancel(uint64_t aTransactionId) {
1044 return NS_ERROR_NOT_IMPLEMENTED;
1048 MacOSWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId,
1049 const nsAString& aOrigin,
1051 auto guard = mTransactionState.Lock();
1052 if (guard->isNothing() ||
1053 guard->ref().browsingContextId != aBrowsingContextId ||
1054 guard->ref().pendingSignArgs.isNothing()) {
1060 Unused << guard->ref().pendingSignArgs.ref()->GetOrigin(origin);
1061 if (origin != aOrigin) {
1066 *aRv = guard->ref().transactionId;
1071 MacOSWebAuthnService::GetAutoFillEntries(
1072 uint64_t aTransactionId, nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>& aRv) {
1073 auto guard = mTransactionState.Lock();
1074 if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1075 guard->ref().pendingSignArgs.isNothing() ||
1076 guard->ref().autoFillEntries.isNothing()) {
1077 return NS_ERROR_NOT_AVAILABLE;
1079 aRv.Assign(guard->ref().autoFillEntries.ref());
1084 MacOSWebAuthnService::SelectAutoFillEntry(
1085 uint64_t aTransactionId, const nsTArray<uint8_t>& aCredentialId) {
1086 auto guard = mTransactionState.Lock();
1087 if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1088 guard->ref().pendingSignArgs.isNothing()) {
1089 return NS_ERROR_NOT_AVAILABLE;
1092 nsTArray<nsTArray<uint8_t>> allowList;
1093 Unused << guard->ref().pendingSignArgs.ref()->GetAllowList(allowList);
1094 if (!allowList.IsEmpty() && !allowList.Contains(aCredentialId)) {
1095 return NS_ERROR_FAILURE;
1098 Maybe<nsTArray<uint8_t>> id;
1100 id.ref().Assign(aCredentialId);
1101 DoGetAssertion(std::move(id), guard);
1107 MacOSWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) {
1108 auto guard = mTransactionState.Lock();
1109 if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
1110 guard->ref().pendingSignArgs.isNothing()) {
1111 return NS_ERROR_NOT_AVAILABLE;
1113 DoGetAssertion(Nothing(), guard);
1118 MacOSWebAuthnService::PinCallback(uint64_t aTransactionId,
1119 const nsACString& aPin) {
1120 return NS_ERROR_NOT_IMPLEMENTED;
1124 MacOSWebAuthnService::ResumeMakeCredential(uint64_t aTransactionId,
1125 bool aForceNoneAttestation) {
1126 return NS_ERROR_NOT_IMPLEMENTED;
1130 MacOSWebAuthnService::SelectionCallback(uint64_t aTransactionId,
1132 return NS_ERROR_NOT_IMPLEMENTED;
1136 MacOSWebAuthnService::AddVirtualAuthenticator(
1137 const nsACString& protocol, const nsACString& transport,
1138 bool hasResidentKey, bool hasUserVerification, bool isUserConsenting,
1139 bool isUserVerified, uint64_t* _retval) {
1140 return NS_ERROR_NOT_IMPLEMENTED;
1144 MacOSWebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
1145 return NS_ERROR_NOT_IMPLEMENTED;
1149 MacOSWebAuthnService::AddCredential(uint64_t authenticatorId,
1150 const nsACString& credentialId,
1151 bool isResidentCredential,
1152 const nsACString& rpId,
1153 const nsACString& privateKey,
1154 const nsACString& userHandle,
1155 uint32_t signCount) {
1156 return NS_ERROR_NOT_IMPLEMENTED;
1160 MacOSWebAuthnService::GetCredentials(
1161 uint64_t authenticatorId,
1162 nsTArray<RefPtr<nsICredentialParameters>>& _retval) {
1163 return NS_ERROR_NOT_IMPLEMENTED;
1167 MacOSWebAuthnService::RemoveCredential(uint64_t authenticatorId,
1168 const nsACString& credentialId) {
1169 return NS_ERROR_NOT_IMPLEMENTED;
1173 MacOSWebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
1174 return NS_ERROR_NOT_IMPLEMENTED;
1178 MacOSWebAuthnService::SetUserVerified(uint64_t authenticatorId,
1179 bool isUserVerified) {
1180 return NS_ERROR_NOT_IMPLEMENTED;
1184 MacOSWebAuthnService::Listen() { return NS_ERROR_NOT_IMPLEMENTED; }
1187 MacOSWebAuthnService::RunCommand(const nsACString& cmd) {
1188 return NS_ERROR_NOT_IMPLEMENTED;
1191 } // namespace mozilla::dom
1193 NS_ASSUME_NONNULL_END