[WebAuthN] Make AuthenticatorManager
authorjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Sep 2018 22:22:36 +0000 (22:22 +0000)
committerjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Sep 2018 22:22:36 +0000 (22:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189279
<rdar://problem/44116792>

Reviewed by Chris Dumez.

Source/WebCore:

This patch does the following things in WebCore in order to support AuthenticatorManager:
1) It separates AuthenticatorTransport from PublicKeyCredentialDescriptor such that the enum
can be queried from WebKit directly.
2) It adds AuthenticatorAttachment to PublicKeyCredentialCreationOptions such that relying parties
could express their interests in cross platform authenticators.
3) It enhances IPC encoder/decoder of a few such that Vectors and empty objects can be correctly coded.
4) It moves the LocalAuthenticator implementation to WebKit to better integrate with AuthenticatorManager.
5) It moves linking to LocalAuthentication.framework to WebKit as well.
6) It temporarily bans old mock test mechanism in Internals so we could enable the new mock test mechanism in
WebKitTestRunner which we will have a better coverage of codes in UI Process. Those tests will be either
removed or ported to the new mechanism in Bug 189283.
7) It also removes "using namespace WebCore" from the top namespace in some .mm files as they are reordered
to where they could introduce name confusions.

Tests: http/wpt/webauthn/public-key-credential-create-failure-local.https.html
       http/wpt/webauthn/public-key-credential-create-success-local.https.html
       http/wpt/webauthn/public-key-credential-get-failure-local.https.html
       http/wpt/webauthn/public-key-credential-get-success-local.https.html
       http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html

* CMakeLists.txt:
* Configurations/WebCore.xcconfig:
* DerivedSources.make:
* Modules/webauthn/AuthenticatorTransport.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* Modules/webauthn/AuthenticatorTransport.idl: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl.
* Modules/webauthn/PublicKeyCredentialCreationOptions.h:
(WebCore::PublicKeyCredentialCreationOptions::encode const):
(WebCore::PublicKeyCredentialCreationOptions::decode):
* Modules/webauthn/PublicKeyCredentialCreationOptions.idl:
* Modules/webauthn/PublicKeyCredentialData.h:
(WebCore::PublicKeyCredentialData::encode const):
(WebCore::PublicKeyCredentialData::decode):
* Modules/webauthn/PublicKeyCredentialDescriptor.h:
(WebCore::PublicKeyCredentialDescriptor::encode const):
* Modules/webauthn/PublicKeyCredentialDescriptor.idl:
* Modules/webauthn/cocoa/LocalAuthenticator.mm: Removed.
* Sources.txt:
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* dom/ExceptionData.h:
* platform/cocoa/LocalAuthenticationSoftLink.mm: Removed.
* platform/cocoa/SharedBufferCocoa.mm:
(-[WebCoreSharedBufferData initWithSharedBufferDataSegment:]):
* platform/cocoa/VideoFullscreenModelVideoElement.mm:
(VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement): Deleted.
(VideoFullscreenModelVideoElement::~VideoFullscreenModelVideoElement): Deleted.
(VideoFullscreenModelVideoElement::setVideoElement): Deleted.
(VideoFullscreenModelVideoElement::handleEvent): Deleted.
(VideoFullscreenModelVideoElement::updateForEventName): Deleted.
(VideoFullscreenModelVideoElement::willExitFullscreen): Deleted.
(VideoFullscreenModelVideoElement::setVideoFullscreenLayer): Deleted.
(VideoFullscreenModelVideoElement::waitForPreparedForInlineThen): Deleted.
(VideoFullscreenModelVideoElement::requestFullscreenMode): Deleted.
(VideoFullscreenModelVideoElement::setVideoLayerFrame): Deleted.
(VideoFullscreenModelVideoElement::setVideoLayerGravity): Deleted.
(VideoFullscreenModelVideoElement::observedEventNames): Deleted.
(VideoFullscreenModelVideoElement::eventNameAll): Deleted.
(VideoFullscreenModelVideoElement::fullscreenModeChanged): Deleted.
(VideoFullscreenModelVideoElement::addClient): Deleted.
(VideoFullscreenModelVideoElement::removeClient): Deleted.
(VideoFullscreenModelVideoElement::isVisible const): Deleted.
(VideoFullscreenModelVideoElement::setHasVideo): Deleted.
(VideoFullscreenModelVideoElement::setVideoDimensions): Deleted.
(VideoFullscreenModelVideoElement::willEnterPictureInPicture): Deleted.
(VideoFullscreenModelVideoElement::didEnterPictureInPicture): Deleted.
(VideoFullscreenModelVideoElement::failedToEnterPictureInPicture): Deleted.
(VideoFullscreenModelVideoElement::willExitPictureInPicture): Deleted.
(VideoFullscreenModelVideoElement::didExitPictureInPicture): Deleted.
* platform/graphics/ca/cocoa/PlatformCAAnimationCocoa.mm:
(WebCore::hasExplicitBeginTime):
(WebCore::setHasExplicitBeginTime):
(WebCore::toCAFillModeType):
(WebCore::toCAValueFunctionType):
(WebCore::toCAMediaTimingFunction):
(WebCore::PlatformCAAnimationCocoa::setFromValue):
(WebCore::PlatformCAAnimationCocoa::setToValue):
(WebCore::PlatformCAAnimationCocoa::setValues):
(fromCAFillModeType): Deleted.
(fromCAValueFunctionType): Deleted.
(PlatformCAAnimationCocoa::create): Deleted.
(PlatformCAAnimationCocoa::PlatformCAAnimationCocoa): Deleted.
(PlatformCAAnimationCocoa::~PlatformCAAnimationCocoa): Deleted.
(PlatformCAAnimationCocoa::copy const): Deleted.
(PlatformCAAnimationCocoa::platformAnimation const): Deleted.
(PlatformCAAnimationCocoa::keyPath const): Deleted.
(PlatformCAAnimationCocoa::beginTime const): Deleted.
(PlatformCAAnimationCocoa::setBeginTime): Deleted.
(PlatformCAAnimationCocoa::duration const): Deleted.
(PlatformCAAnimationCocoa::setDuration): Deleted.
(PlatformCAAnimationCocoa::speed const): Deleted.
(PlatformCAAnimationCocoa::setSpeed): Deleted.
(PlatformCAAnimationCocoa::timeOffset const): Deleted.
(PlatformCAAnimationCocoa::setTimeOffset): Deleted.
(PlatformCAAnimationCocoa::repeatCount const): Deleted.
(PlatformCAAnimationCocoa::setRepeatCount): Deleted.
(PlatformCAAnimationCocoa::autoreverses const): Deleted.
(PlatformCAAnimationCocoa::setAutoreverses): Deleted.
(PlatformCAAnimationCocoa::fillMode const): Deleted.
(PlatformCAAnimationCocoa::setFillMode): Deleted.
(PlatformCAAnimationCocoa::setTimingFunction): Deleted.
(PlatformCAAnimationCocoa::copyTimingFunctionFrom): Deleted.
(PlatformCAAnimationCocoa::isRemovedOnCompletion const): Deleted.
(PlatformCAAnimationCocoa::setRemovedOnCompletion): Deleted.
(PlatformCAAnimationCocoa::isAdditive const): Deleted.
(PlatformCAAnimationCocoa::setAdditive): Deleted.
(PlatformCAAnimationCocoa::valueFunction const): Deleted.
(PlatformCAAnimationCocoa::setValueFunction): Deleted.
(PlatformCAAnimationCocoa::setFromValue): Deleted.
(PlatformCAAnimationCocoa::copyFromValueFrom): Deleted.
(PlatformCAAnimationCocoa::setToValue): Deleted.
(PlatformCAAnimationCocoa::copyToValueFrom): Deleted.
(PlatformCAAnimationCocoa::setValues): Deleted.
(PlatformCAAnimationCocoa::copyValuesFrom): Deleted.
(PlatformCAAnimationCocoa::setKeyTimes): Deleted.
(PlatformCAAnimationCocoa::copyKeyTimesFrom): Deleted.
(PlatformCAAnimationCocoa::setTimingFunctions): Deleted.
(PlatformCAAnimationCocoa::copyTimingFunctionsFrom): Deleted.
* platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm:
(PlatformCAFilters::filterValueForOperation): Deleted.
(PlatformCAFilters::colorMatrixValueForFilter): Deleted.
(PlatformCAFilters::setBlendingFiltersOnLayer): Deleted.
(PlatformCAFilters::numAnimatedFilterProperties): Deleted.
(PlatformCAFilters::animatedFilterPropertyName): Deleted.
* platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
(-[WebAnimationDelegate animationDidStart:]):
(-[WebAnimationDelegate animationDidStop:finished:]):
(-[WebAnimationDelegate setOwner:]):
(PlatformCALayerCocoa::create): Deleted.
(PlatformCALayer::platformCALayer): Deleted.
(mediaTimeToCurrentTime): Deleted.
(PlatformCALayerCocoa::setOwner): Deleted.
(toCAFilterType): Deleted.
(PlatformCALayerCocoa::layerTypeForPlatformLayer): Deleted.
(PlatformCALayerCocoa::PlatformCALayerCocoa): Deleted.
(PlatformCALayerCocoa::commonInit): Deleted.
(PlatformCALayerCocoa::clone const): Deleted.
(PlatformCALayerCocoa::~PlatformCALayerCocoa): Deleted.
(PlatformCALayerCocoa::animationStarted): Deleted.
(PlatformCALayerCocoa::animationEnded): Deleted.
(PlatformCALayerCocoa::setNeedsDisplay): Deleted.
(PlatformCALayerCocoa::setNeedsDisplayInRect): Deleted.
(PlatformCALayerCocoa::copyContentsFromLayer): Deleted.
(PlatformCALayerCocoa::superlayer const): Deleted.
(PlatformCALayerCocoa::removeFromSuperlayer): Deleted.
(PlatformCALayerCocoa::setSublayers): Deleted.
(PlatformCALayerCocoa::removeAllSublayers): Deleted.
(PlatformCALayerCocoa::appendSublayer): Deleted.
(PlatformCALayerCocoa::insertSublayer): Deleted.
(PlatformCALayerCocoa::replaceSublayer): Deleted.
(PlatformCALayerCocoa::adoptSublayers): Deleted.
(PlatformCALayerCocoa::addAnimationForKey): Deleted.
(PlatformCALayerCocoa::removeAnimationForKey): Deleted.
(PlatformCALayerCocoa::animationForKey): Deleted.
(PlatformCALayerCocoa::setMask): Deleted.
(PlatformCALayerCocoa::isOpaque const): Deleted.
(PlatformCALayerCocoa::setOpaque): Deleted.
(PlatformCALayerCocoa::bounds const): Deleted.
(PlatformCALayerCocoa::setBounds): Deleted.
(PlatformCALayerCocoa::position const): Deleted.
(PlatformCALayerCocoa::setPosition): Deleted.
(PlatformCALayerCocoa::anchorPoint const): Deleted.
(PlatformCALayerCocoa::setAnchorPoint): Deleted.
(PlatformCALayerCocoa::transform const): Deleted.
(PlatformCALayerCocoa::setTransform): Deleted.
(PlatformCALayerCocoa::sublayerTransform const): Deleted.
(PlatformCALayerCocoa::setSublayerTransform): Deleted.
(PlatformCALayerCocoa::isHidden const): Deleted.
(PlatformCALayerCocoa::setHidden): Deleted.
(PlatformCALayerCocoa::contentsHidden const): Deleted.
(PlatformCALayerCocoa::setContentsHidden): Deleted.
(PlatformCALayerCocoa::userInteractionEnabled const): Deleted.
(PlatformCALayerCocoa::setUserInteractionEnabled): Deleted.
(PlatformCALayerCocoa::setBackingStoreAttached): Deleted.
(PlatformCALayerCocoa::backingStoreAttached const): Deleted.
(PlatformCALayerCocoa::geometryFlipped const): Deleted.
(PlatformCALayerCocoa::setGeometryFlipped): Deleted.
(PlatformCALayerCocoa::isDoubleSided const): Deleted.
(PlatformCALayerCocoa::setDoubleSided): Deleted.
(PlatformCALayerCocoa::masksToBounds const): Deleted.
(PlatformCALayerCocoa::setMasksToBounds): Deleted.
(PlatformCALayerCocoa::acceleratesDrawing const): Deleted.
(PlatformCALayerCocoa::setAcceleratesDrawing): Deleted.
(PlatformCALayerCocoa::wantsDeepColorBackingStore const): Deleted.
(PlatformCALayerCocoa::setWantsDeepColorBackingStore): Deleted.
(PlatformCALayerCocoa::supportsSubpixelAntialiasedText const): Deleted.
(PlatformCALayerCocoa::setSupportsSubpixelAntialiasedText): Deleted.
(PlatformCALayerCocoa::hasContents const): Deleted.
(PlatformCALayerCocoa::contents const): Deleted.
(PlatformCALayerCocoa::setContents): Deleted.
(PlatformCALayerCocoa::setContentsRect): Deleted.
(PlatformCALayerCocoa::setMinificationFilter): Deleted.
(PlatformCALayerCocoa::setMagnificationFilter): Deleted.
(PlatformCALayerCocoa::backgroundColor const): Deleted.
(PlatformCALayerCocoa::setBackgroundColor): Deleted.
(PlatformCALayerCocoa::setBorderWidth): Deleted.
(PlatformCALayerCocoa::setBorderColor): Deleted.
(PlatformCALayerCocoa::opacity const): Deleted.
(PlatformCALayerCocoa::setOpacity): Deleted.
(PlatformCALayerCocoa::setFilters): Deleted.
(PlatformCALayerCocoa::copyFiltersFrom): Deleted.
(PlatformCALayerCocoa::filtersCanBeComposited): Deleted.
(PlatformCALayerCocoa::setBlendMode): Deleted.
(PlatformCALayerCocoa::setName): Deleted.
(PlatformCALayerCocoa::setSpeed): Deleted.
(PlatformCALayerCocoa::setTimeOffset): Deleted.
(PlatformCALayerCocoa::contentsScale const): Deleted.
(PlatformCALayerCocoa::setContentsScale): Deleted.
(PlatformCALayerCocoa::cornerRadius const): Deleted.
(PlatformCALayerCocoa::setCornerRadius): Deleted.
(PlatformCALayerCocoa::setEdgeAntialiasingMask): Deleted.
(PlatformCALayerCocoa::shapeRoundedRect const): Deleted.
(PlatformCALayerCocoa::setShapeRoundedRect): Deleted.
(PlatformCALayerCocoa::shapeWindRule const): Deleted.
(PlatformCALayerCocoa::setShapeWindRule): Deleted.
(PlatformCALayerCocoa::shapePath const): Deleted.
(PlatformCALayerCocoa::setShapePath): Deleted.
(PlatformCALayerCocoa::requiresCustomAppearanceUpdateOnBoundsChange const): Deleted.
(PlatformCALayerCocoa::updateCustomAppearance): Deleted.
(layerContentsFormat): Deleted.
(PlatformCALayerCocoa::updateContentsFormat): Deleted.
(PlatformCALayerCocoa::tiledBacking): Deleted.
(PlatformCALayer::isWebLayer): Deleted.
(PlatformCALayer::setBoundsOnMainThread): Deleted.
(PlatformCALayer::setPositionOnMainThread): Deleted.
(PlatformCALayer::setAnchorPointOnMainThread): Deleted.
(PlatformCALayer::collectRectsToPaint): Deleted.
(PlatformCALayer::drawLayerContents): Deleted.
(PlatformCALayer::frameForLayer): Deleted.
(PlatformCALayerCocoa::createCompatibleLayer const): Deleted.
(PlatformCALayerCocoa::enumerateRectsBeingDrawn): Deleted.
(PlatformCALayerCocoa::backingStoreBytesPerPixel const): Deleted.
(PlatformCALayerCocoa::avPlayerLayer const): Deleted.
* platform/graphics/ca/cocoa/WebSystemBackdropLayer.mm:
(-[WebLightSystemBackdropLayer init]):
(-[WebDarkSystemBackdropLayer init]):
* platform/graphics/ca/cocoa/WebTiledBackingLayer.mm:
(-[WebTiledBackingLayer createTileController:]):
(-[WebTiledBackingLayer setNeedsDisplayInRect:]):
(-[WebTiledBackingLayer setBorderColor:]):
* testing/Internals.cpp:
(WebCore::Internals::Internals):

Source/WebCore/PAL:

It moves linking to DeviceIdentity.framework to WebKit.

* PAL.xcodeproj/project.pbxproj:

Source/WebKit:

This patch introduces AuthenticatorManager which is the central of WebAuthentication that 1) handles
web requests, 2) discovers authenticators, 3) manages authetnicators and 4) in the future interacts with UI.
The lifetime of the AuthenticatorManager is managed by WebsiteDataStore such that it is almost a singleton
per UI Process.

1) Requests come from WebAuthenticatorCoordinatorProxy and then cached in AuthenticatorManager which will
then distribute requests whenever a new authenticator is discovered.

2) An ABC AuthenticatorTransportService is provided as an interface for AuthenticatorManager to invoke
startDiscovery. Actual work will be done in corresponding derived classes, say, LocalService. LocalService
is the one that discover attached platform authenticators, for example, TouchID or FaceID.

Eache service is unique per AuthetnicatorManager, which means we will have at most 4 services, Local, USB,
NFC, and BLE. The latter three will be implemented soon. Also, AuthenticatorManager serves as an observer to
*Service, so the latter can inform the former whenever an authenticator is added or removed.

When a new authenticator is discovered, the corresponding service will create an Authetnicator object that
binds to the physical authenticator device through a *Connection object. There is no ABC for connection for
now as I forsee every *Connection will be quite different. The *Connection object is the one that send/receive
messages from the physicla device. So far, a LocalConnection is provided even though normally local authenticators
are attached. This class is provided solely for separating UI and network traffic from LocalAuthenticator's
request handling process. So we can override them in a mock test environment. I will talk about this in the
next section.

3) An ABC Authenticator is provided as an interface for AuthenticatorManager to distribute requests on. Requests
will then be handled by the derived classes, say, LocalAuthenticator. Each authenticator object is a FSM that
works asynchronously.

For LocalAuthenticator, it has 4 states for MakeCredential: Init => RequestReceived => UserConsented => Attested => End,
and 3 states for GetAssertion: Init => RequestReceived => UserConsented => End. In the transit from RequestReceived to
UserConsented, it will invoke LocalConnection to talk to LocalAuthentication.framework that prompt users for TouchID
or FaceID. And then the transit from UserConsented => Attested, it will invoke LocalConnection to talk to
DeviceIdentity.framework that does Apple attestation. Most of the work are from the original LocalAuthenticator
implementation, and this patch converts it to a FSM and simplify the callback and threading model.

When a respond is ready, each authenticator will notify their observer which is the AuthenticatorManager.
AuthenticatorManager will only reply to Web Process whenever there is a valid respond or a terminating error. Otherwise,
the request will time out. I will explore the time out mechanism in a more detailed manner in Bug 189642.

The above is a briefing of the AuthetnicatorManager architecture in functional. The asynchronous model is explained here:
1) Since most discovery and request handling processes are asynchronous, I enforced them to be executed asyncrhonous in
the interface of the ABC.
2) There is no dedicated secondary threads here. However, underlying framework might decide to perform works on a dedicated
thread and then execute the provided callback. Whenever such situation happens, the policy here is to wrap the actual callback
into a callback that will post the actual callback back to the main thread and pass the wrapping callback to the APIs. Hence,
weak pointers in the actual callback are guaranteed to work.
3) Callbacks are used only if it is one way, and they are CompletionHandlers.
4) Potential multi ways asynchronous operations are encapsulated in regarding Observer interfaces.

Finally, let me explain how the mock test works:
1) Mock testing is done in WebKitTestRunner instead of Internals because a considerable large portion of work is in UIProcess
instead of WebProcess, says, the AuthenticatorManager.
2) The basic idea is to override functionality of *Connection classes and then make them thin such that we can get the best
possible coverage in auto tests.
3) In order to enable layout tests to configure the Mock*Connection classes, a MockWebAuthenticationConfiguration struct is
provided. A corresponding JS dictionary will be created by each test and passed from the TestRunner to the connection object.
4) To bridge the above tunnel, a MockAuthenticatorManager is constructed. It is instrumented to return every error.
5) Also, Mock*Service classes are made to mock the discovery process as well.
6) Noted, every mock overrided methods are made thin.

* CMakeLists.txt:
* Configurations/WebKit.xcconfig:
* Platform/spi/Cocoa/DeviceIdentitySPI.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
* SourcesCocoa.txt:
* UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
(WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):
* UIProcess/API/C/WKWebsiteDataStoreRef.h:
* UIProcess/WebAuthentication/Authenticator.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
(WebKit::Authenticator::handleRequest):
(WebKit::Authenticator::receiveRespond const):
* UIProcess/WebAuthentication/Authenticator.h: Renamed from Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.h.
(WebKit::Authenticator::setObserver):
(WebKit::Authenticator::observer const):
(WebKit::Authenticator::requestData const):
* UIProcess/WebAuthentication/AuthenticatorManager.cpp: Added.
(WebKit::AuthenticatorManagerInternal::collectTransports):
(WebKit::AuthenticatorManager::makeCredential):
(WebKit::AuthenticatorManager::getAssertion):
(WebKit::AuthenticatorManager::clearState):
(WebKit::AuthenticatorManager::authenticatorAdded):
(WebKit::AuthenticatorManager::respondReceived):
(WebKit::AuthenticatorManager::createService const):
(WebKit::AuthenticatorManager::respondReceivedInternal):
(WebKit::AuthenticatorManager::startDiscovery):
* UIProcess/WebAuthentication/AuthenticatorManager.h: Added.
(WebKit::AuthenticatorManager::pendingCompletionHandler):
* UIProcess/WebAuthentication/AuthenticatorTransportService.cpp: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
(WebKit::AuthenticatorTransportService::create):
(WebKit::AuthenticatorTransportService::createMock):
(WebKit::AuthenticatorTransportService::AuthenticatorTransportService):
(WebKit::AuthenticatorTransportService::startDiscovery const):
* UIProcess/WebAuthentication/AuthenticatorTransportService.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
(WebKit::AuthenticatorTransportService::observer const):
* UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
* UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm: Added.
(WebKit::LocalAuthenticatorInternal::buildAuthData):
(WebKit::LocalAuthenticatorInternal::transportsContain):
(WebKit::LocalAuthenticatorInternal::produceHashSet):
(WebKit::LocalAuthenticatorInternal::toVector):
(WebKit::LocalAuthenticator::LocalAuthenticator):
(WebKit::LocalAuthenticator::makeCredential):
(WebKit::LocalAuthenticator::continueMakeCredentialAfterUserConsented):
(WebKit::LocalAuthenticator::continueMakeCredentialAfterAttested):
(WebKit::LocalAuthenticator::getAssertion):
(WebKit::LocalAuthenticator::continueGetAssertionAfterUserConsented):
* UIProcess/WebAuthentication/Cocoa/LocalConnection.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
* UIProcess/WebAuthentication/Cocoa/LocalConnection.mm: Added.
(WebKit::LocalConnection::getUserConsent const):
(WebKit::LocalConnection::getAttestation const):
* UIProcess/WebAuthentication/Cocoa/LocalService.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/Cocoa/LocalService.mm: Renamed from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
(WebKit::LocalService::LocalService):
(WebKit::LocalService::isAvailable):
(WebKit::LocalService::startDiscoveryInternal const):
(WebKit::LocalService::platformStartDiscovery const):
(WebKit::LocalService::createLocalConnection const):
* UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
(WebKit::MockAuthenticatorManager::MockAuthenticatorManager):
(WebKit::MockAuthenticatorManager::createService const):
(WebKit::MockAuthenticatorManager::respondReceivedInternal):
* UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/Mock/MockLocalConnection.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/Mock/MockLocalConnection.mm: Added.
(WebKit::MockLocalConnection::MockLocalConnection):
(WebKit::MockLocalConnection::getUserConsent const):
(WebKit::MockLocalConnection::getAttestation const):
* UIProcess/WebAuthentication/Mock/MockLocalService.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
(WebKit::MockLocalService::MockLocalService):
(WebKit::MockLocalService::platformStartDiscovery const):
(WebKit::MockLocalService::createLocalConnection const):
* UIProcess/WebAuthentication/Mock/MockLocalService.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/WebAuthenticationRequestData.h: Renamed from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
* UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp:
(WebKit::WebAuthenticatorCoordinatorProxy::WebAuthenticatorCoordinatorProxy):
(WebKit::WebAuthenticatorCoordinatorProxy::makeCredential):
(WebKit::WebAuthenticatorCoordinatorProxy::getAssertion):
(WebKit::WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailable):
(WebKit::WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailableReply): Deleted.
* UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::WebsiteDataStore):
(WebKit::WebsiteDataStore::setMockWebAuthenticationConfiguration):
* UIProcess/WebsiteData/WebsiteDataStore.h:
(WebKit::WebsiteDataStore::authenticatorManager):
* WebKit.xcodeproj/project.pbxproj:

Tools:

Besides the functionality to set the WebAuthenticationMockConfiguration. Three operations are
added to manipulate Keychain: addTestKeyToKeychain, cleanUpKeychain and keyExistedInKeychain.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/ios/LocalAuthenticator.mm: Removed.
* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setWebAuthenticationMockConfiguration):
(WTR::TestRunner::addTestKeyToKeychain):
(WTR::TestRunner::cleanUpKeychain):
(WTR::TestRunner::isKeyExisted):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::addTestKeyToKeychain):
(WTR::TestController::cleanUpKeychain):
(WTR::TestController::isKeyExisted):
(WTR::TestController::setWebAuthenticationMockConfiguration):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
* WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::addTestKeyToKeychain):
(WTR::TestController::cleanUpKeychain):
(WTR::TestController::keyExistedInKeychain):

LayoutTests:

Most of the new tests are rewritten from the LocalAuthenticator API tests. Old mock tests are temporarily skipped
for the new mock tests.

* TestExpectations:
* http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-create-failure-local.https.html: Added.
* http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-create-success-local.https.html: Added.
* http/wpt/webauthn/public-key-credential-create-success.https.html:
* http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-get-failure-local.https.html: Added.
* http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-get-success-local.https.html: Added.
* http/wpt/webauthn/public-key-credential-get-success.https.html:
* http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html: Added.
* http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available-expected.txt: Removed.
* http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available.html: Removed.
* http/wpt/webauthn/resources/util.js:
* platform/mac-wk2/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236481 268f45cc-cd09-0410-ab3c-d52691b4dbfc

89 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https.html [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https.html [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-get-success.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html [new file with mode: 0644]
LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available-expected.txt [deleted file]
LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available.html [deleted file]
LayoutTests/http/wpt/webauthn/resources/util.js
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/Configurations/WebCore.xcconfig
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/webauthn/AuthenticatorTransport.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/AuthenticatorTransport.idl [new file with mode: 0644]
Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h
Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.idl
Source/WebCore/Modules/webauthn/PublicKeyCredentialData.h
Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.h
Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl
Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.mm [deleted file]
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
Source/WebCore/Sources.txt
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/ExceptionData.h
Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.mm [deleted file]
Source/WebCore/platform/cocoa/SharedBufferCocoa.mm
Source/WebCore/platform/cocoa/VideoFullscreenModelVideoElement.mm
Source/WebCore/platform/graphics/ca/cocoa/PlatformCAAnimationCocoa.mm
Source/WebCore/platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm
Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm
Source/WebCore/platform/graphics/ca/cocoa/WebSystemBackdropLayer.mm
Source/WebCore/platform/graphics/ca/cocoa/WebTiledBackingLayer.mm
Source/WebCore/testing/Internals.cpp
Source/WebKit/CMakeLists.txt
Source/WebKit/ChangeLog
Source/WebKit/Configurations/WebKit.xcconfig
Source/WebKit/Platform/spi/Cocoa/DeviceIdentitySPI.h [moved from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h with 100% similarity]
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h
Source/WebKit/UIProcess/WebAuthentication/Authenticator.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Authenticator.h [moved from Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.h with 54% similarity]
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h [moved from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h with 88% similarity]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.mm [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp
Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/ios/LocalAuthenticator.mm [deleted file]
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp
Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm

index 44aaa9b..ea09f98 100644 (file)
@@ -1,3 +1,32 @@
+2018-09-25  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Make AuthenticatorManager
+        https://bugs.webkit.org/show_bug.cgi?id=189279
+        <rdar://problem/44116792>
+
+        Reviewed by Chris Dumez.
+
+        Most of the new tests are rewritten from the LocalAuthenticator API tests. Old mock tests are temporarily skipped
+        for the new mock tests.
+
+        * TestExpectations:
+        * http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-create-failure-local.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-create-success-local.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-create-success.https.html:
+        * http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-get-failure-local.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-get-success-local.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-get-success.https.html:
+        * http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html: Added.
+        * http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available-expected.txt: Removed.
+        * http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available.html: Removed.
+        * http/wpt/webauthn/resources/util.js:
+        * platform/mac-wk2/TestExpectations:
+
 2018-09-25  Ryan Haddad  <ryanhaddad@apple.com>
 
         REGRESSION: (r235948) Layout Test compositing/backing/backing-store-attachment-fill-forwards-animation.html is a flaky failure
index d9112cb..857ad70 100644 (file)
@@ -2862,3 +2862,11 @@ fast/gradients/conic-gradient.html [ Skip ]
 fast/gradients/conic-two-hints.html [ Skip ]
 
 webkit.org/b/187773 http/tests/webAPIStatistics [ Skip ]
+
+# Temporary disables old WebAuthN tests, will either reenable or remove them in webkit.org/b/189283
+http/wpt/credential-management/credentialscontainer-store-basics.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-failure.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-success.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-failure.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-success.https.html [ Skip ]
+http/wpt/webauthn/idl.https.html [ Skip ]
\ No newline at end of file
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt
new file mode 100644 (file)
index 0000000..a080f5f
--- /dev/null
@@ -0,0 +1,8 @@
+
+PASS PublicKeyCredential's [[create]] with unsupported public key credential parameters in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator. 2nd 
+PASS PublicKeyCredential's [[create]] without user consent in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] without attestation in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] deleting old credential in a mock local authenticator. 
+
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html
new file mode 100644 (file)
index 0000000..ac3a636
--- /dev/null
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] failure cases with a mock local authenticator.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/util.js"></script>
+<script>
+    // Default mock configuration. Tests need to override if they need different configuration.
+    if (window.testRunner)
+        testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: false, acceptAttestation: false, privateKeyBase64: "" } });
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -35 }, { type: "public-key", alg: -257 }], // ES384, RS256
+            }
+        };
+        return promise_rejects(t, "NotSupportedError", navigator.credentials.create(options), "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters.");
+    }, "PublicKeyCredential's [[create]] with unsupported public key credential parameters in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+                excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64url) }]
+            }
+        };
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator.").then(() => {
+            if (window.testRunner)
+                testRunner.cleanUpKeychain(testRpId);
+        });
+    }, "PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+                excludeCredentials: [
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["usb"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["nfc"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["ble"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["internal"] }
+                ]
+            }
+        };
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator.").then(() => {
+            if (window.testRunner)
+                testRunner.cleanUpKeychain(testRpId);
+        });
+    }, "PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator. 2nd");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+            }
+        };
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.create(options), "Couldn't get user consent.");
+    }, "PublicKeyCredential's [[create]] without user consent in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+            }
+        };
+        if (window.testRunner)
+            testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false, privateKeyBase64: "" } });
+        return promise_rejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error.");
+    }, "PublicKeyCredential's [[create]] without attestation in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+            }
+        };
+        if (window.testRunner) {
+            testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false, privateKeyBase64: "" } });
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        }
+        return promise_rejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error.").then(() => {
+            if (window.testRunner)
+                assert_false(testRunner.keyExistsInKeychain(testRpId, testUserhandleBase64));
+        });
+    }, "PublicKeyCredential's [[create]] deleting old credential in a mock local authenticator.");
+</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt
new file mode 100644 (file)
index 0000000..f66c267
--- /dev/null
@@ -0,0 +1,5 @@
+
+PASS PublicKeyCredential's [[create]] with minimum options in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] with authenticatorSelection { 'platform' } in a mock local authenticator. 
+PASS PublicKeyCredential's [[create]] with matched exclude credential ids but not transports in a mock local authenticator. 
+
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https.html
new file mode 100644 (file)
index 0000000..415fea2
--- /dev/null
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock local authenticator.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/util.js"></script>
+<script>
+    // Default mock configuration. Tests need to override if they need different configuration.
+    if (window.testRunner)
+        testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: true, privateKeyBase64: testES256PrivateKeyBase64 } });
+
+    function checkResult(credential)
+    {
+        // Check keychain
+        if (window.testRunner) {
+            assert_true(testRunner.keyExistsInKeychain(testRpId, testUserhandleBase64));
+            testRunner.cleanUpKeychain(testRpId);
+        }
+
+        // Check respond
+        assert_equals(credential.id, testCredentialIdBase64url);
+        assert_equals(credential.type, 'public-key');
+        assert_equals(bytesToHexString(credential.rawId), "48c4971e7805ee110eb04940ef70b7458fbc6d1e");
+        assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443","hashAlgorithm":"SHA-256"}');
+        // FIXME(): Check attestation object
+        assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
+    }
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "localhost",
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "Appleseed",
+                },
+                challenge: Base64URL.parse("MTIzNDU2"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+            }
+        };
+
+        return navigator.credentials.create(options).then(credential => {
+            checkResult(credential);
+        });
+    }, "PublicKeyCredential's [[create]] with minimum options in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "localhost",
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "Appleseed",
+                },
+                challenge: Base64URL.parse("MTIzNDU2"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+                authenticatorSelection: { authenticatorAttachment: "platform" }
+            }
+        };
+
+        return navigator.credentials.create(options).then(credential => {
+            checkResult(credential);
+        });
+    }, "PublicKeyCredential's [[create]] with authenticatorSelection { 'platform' } in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: Base64URL.parse(testUserhandleBase64),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+                excludeCredentials: [
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["usb"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["nfc"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["ble"] }
+                ]
+            }
+        };
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+
+        return navigator.credentials.create(options).then(credential => {
+            checkResult(credential);
+        });
+    }, "PublicKeyCredential's [[create]] with matched exclude credential ids but not transports in a mock local authenticator.");
+</script>
index 69968c3..ac584a0 100644 (file)
                 assert_equals(bytesToHexString(credential.rawId), '00');
                 assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443","hashAlgorithm":"SHA-256"}');
                 assert_equals(bytesToHexString(credential.response.attestationObject), '01');
-                console.log()
-                try {
-                    assert_throws("NotSupportedError", credential.getClientExtensionResults());
-                } catch(error) { }
+                assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
             });
     }, "PublicKeyCredential's [[create]] with minimum options");
 </script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt
new file mode 100644 (file)
index 0000000..d3f4f5d
--- /dev/null
@@ -0,0 +1,5 @@
+
+PASS PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator. 
+PASS PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator. 2nd 
+PASS PublicKeyCredential's [[get]] without user consent in a mock local authenticator. 
+
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html
new file mode 100644 (file)
index 0000000..3954a06
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[get]] failure cases.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/util.js"></script>
+<script>
+    // Default mock configuration. Tests need to override if they need different configuration.
+    if (window.testRunner)
+        testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: false, acceptAttestation: false, privateKeyBase64: "" } });
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                challenge: asciiToUint8Array("123456"),
+                allowCredentials: [
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["usb"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["nfc"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["ble"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["internal"] }
+                ]
+            }
+        };
+
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.get(options), "No matched credentials are found in the platform attached authenticator.");
+    }, "PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                challenge: asciiToUint8Array("123456"),
+                allowCredentials: [
+                    { type: "public-key", id: Base64URL.parse(testUserhandleBase64) }
+                ]
+            }
+        };
+
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.get(options), "No matched credentials are found in the platform attached authenticator.").then(() => {
+                if (window.testRunner)
+                    testRunner.cleanUpKeychain(testRpId);
+            });
+    }, "PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator. 2nd");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                challenge: asciiToUint8Array("123456")
+            }
+        };
+
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return promise_rejects(t, "NotAllowedError", navigator.credentials.get(options), "Couldn't get user consent.").then(() => {
+            if (window.testRunner)
+                testRunner.cleanUpKeychain(testRpId);
+        });
+    }, "PublicKeyCredential's [[get]] without user consent in a mock local authenticator.");
+</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt
new file mode 100644 (file)
index 0000000..68845fb
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS PublicKeyCredential's [[get]] with minimum options in a mock local authenticator. 
+PASS PublicKeyCredential's [[get]] with matched allow credentials in a mock local authenticator. 
+
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https.html
new file mode 100644 (file)
index 0000000..67771c2
--- /dev/null
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[get]] failure cases.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/util.js"></script>
+<script>
+    // Default mock configuration. Tests need to override if they need different configuration.
+    if (window.testRunner)
+        testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false, privateKeyBase64: "" } });
+
+    function checkResult(credential)
+    {
+        if (window.testRunner)
+            testRunner.cleanUpKeychain(testRpId);
+
+         // Check respond
+        assert_equals(credential.id, testCredentialIdBase64url);
+        assert_equals(credential.type, 'public-key');
+        assert_equals(bytesToHexString(credential.rawId), "48c4971e7805ee110eb04940ef70b7458fbc6d1e");
+        assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.get","challenge":"MTIzNDU2","origin":"https://localhost:9443","hashAlgorithm":"SHA-256"}');
+        assert_equals(bytesToHexString(credential.response.userHandle), "00010203040506070809");
+
+        // Check authData
+        const authData = decodeAuthData(new Uint8Array(credential.response.authenticatorData));
+        assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
+        assert_equals(authData.flags, 5);
+        assert_equals(authData.counter, 0);
+
+        // Check signature
+        return crypto.subtle.importKey("raw", Base64URL.parse(testES256PublicKeyBase64url), { name: "ECDSA", namedCurve: "P-256" }, false, ['verify']).then( publicKey => {
+            return crypto.subtle.digest("sha-256", credential.response.clientDataJSON).then ( hash => {
+                // credential.response.signature is in ASN.1 and WebCrypto expect signatures provides in r|s.
+                return crypto.subtle.verify({name: "ECDSA", hash: "SHA-256"}, publicKey, extractRawSignature(credential.response.signature), concatenateBuffers(credential.response.authenticatorData, hash)).then( verified => {
+                    assert_true(verified);
+                    assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
+                });
+            });
+        });
+    }
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                challenge: Base64URL.parse("MTIzNDU2")
+            }
+        };
+
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return navigator.credentials.get(options).then(credential => {
+            return checkResult(credential);
+        });
+    }, "PublicKeyCredential's [[get]] with minimum options in a mock local authenticator.");
+
+    promise_test(t => {
+        const options = {
+            publicKey: {
+                challenge: Base64URL.parse("MTIzNDU2"),
+                allowCredentials: [
+                    { type: "public-key", id: Base64URL.parse(testUserhandleBase64), transports: ["internal"] },
+                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64url), transports: ["internal"] }
+                ]
+            }
+        };
+
+        if (window.testRunner)
+            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
+        return navigator.credentials.get(options).then(credential => {
+            return checkResult(credential);
+        });
+    }, "PublicKeyCredential's [[get]] with matched allow credentials in a mock local authenticator.");
+</script>
index f3fd156..0664b1c 100644 (file)
@@ -22,9 +22,7 @@
             assert_equals(bytesToHexString(credential.response.authenticatorData), '01');
             assert_equals(bytesToHexString(credential.response.signature), '02');
             assert_equals(bytesToHexString(credential.response.userHandle), '03');
-            try {
-                assert_throws("NotSupportedError", credential.getClientExtensionResults());
-            } catch(error) { }
+            assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
         });
     }, "PublicKeyCredential's [[get]] with minimum options");
 </script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available-expected.txt
new file mode 100644 (file)
index 0000000..f88adb9
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() without any available user verifying platform authenticators. 
+
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html b/LayoutTests/http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html
new file mode 100644 (file)
index 0000000..e174447
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    promise_test(t => {
+        return PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then(result => {
+            assert_equals(result, false);
+        });
+    }, "PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() without any available user verifying platform authenticators.");
+</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available-expected.txt
deleted file mode 100644 (file)
index ef2a216..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-
-PASS PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() without any available authenticators. 
-PASS PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() with available authenticators. 
-
diff --git a/LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available.html b/LayoutTests/http/wpt/webauthn/public-key-is-user-verifying-platform-authenticator-available.html
deleted file mode 100644 (file)
index 181d33a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<title>Web Authentication API: PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-    promise_test(function(t) {
-        internals.mockAuthenticatorCoordinator;
-
-        return PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then(function(result) {
-            assert_equals(result, false);
-        });
-    }, "PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() without any available authenticators.");
-
-    promise_test(function(t) {
-        internals.mockAuthenticatorCoordinator.setDidUserVerifyingPlatformAuthenticatorPresent();
-
-        return PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then(function(result) {
-            assert_equals(result, true);
-        });
-    }, "PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() with available authenticators.");
-</script>
index 67ffe6c..120f90d 100644 (file)
@@ -59,3 +59,92 @@ function hexStringToUint8Array(hexString)
 
     return arrayBuffer;
 }
+
+function decodeAuthData(authDataUint8Array)
+{
+    let authDataObject = { };
+    let pos = 0;
+    let size = 0;
+
+    // RP ID Hash
+    size = 32;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    authDataObject.rpIdHash = authDataUint8Array.slice(pos, pos + size);
+    pos = pos + size;
+
+    // FLAGS
+    size = 1;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    authDataObject.flags = authDataUint8Array.slice(pos, pos + size)[0];
+    pos = pos + size;
+
+    // Counter
+    size = 4;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    authDataObject.counter = new Uint32Array(authDataUint8Array.slice(pos, pos + size))[0];
+    pos = pos + size;
+
+    if (pos == authDataUint8Array.byteLength)
+        return authDataObject;
+
+    // AAGUID
+    size = 16;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    authDataObject.aaguid = authDataUint8Array.slice(pos, pos + size);
+    pos = pos + size;
+
+    // L
+    size = 2;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    // Little Endian
+    authDataObject.l = new Uint16Array(authDataUint8Array.slice(pos, pos + size))[0];
+    pos = pos + size;
+
+    // Credential ID
+    size = authDataObject.l;
+    if (pos + size > authDataUint8Array.byteLength)
+        return { };
+    authDataObject.credentialID = authDataUint8Array.slice(pos, pos + size);
+    pos = pos + size;
+
+    // FIXME(): Add CBOR decoder to parse the public key.
+
+    // Assume no extensions.
+    return authDataObject;
+}
+
+function concatenateBuffers(buffer1, buffer2)
+{
+    let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
+    tmp.set(new Uint8Array(buffer1), 0);
+    tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
+    return tmp.buffer;
+}
+
+// Very dirty asn1 decoder. Just works.
+function extractRawSignature(asn1signature)
+{
+    const signature = new Uint8Array(asn1signature);
+    let tmp = new Uint8Array(64);
+    const rStart =  signature[3] - 32;
+    tmp.set(new Uint8Array(signature.slice(4 + rStart, 36 + rStart)), 0);
+    const sStart =  signature[37 + rStart] - 32;
+    tmp.set(new Uint8Array(signature.slice(38 + rStart + sStart)), 32);
+    return tmp.buffer;
+}
+
+const testCredentialIdBase64url = "SMSXHngF7hEOsElA73C3RY-8bR4";
+const testES256PrivateKeyBase64 =
+    "BDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749VBJPgqUIwfhWHJ91nb7U" +
+    "PH76c0+WFOzZKslPyyFse4goGIW2R7k9VHLPEZl5nfnBgEVFh5zev+/xpHQIvuq6" +
+    "RQ==";
+const testES256PublicKeyBase64url =
+    "BDj_zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF_Qm1749VBJPgqUIwfhWHJ91nb7U" +
+    "PH76c0-WFOzZKslPyyFse4g";
+const testRpId = "localhost";
+const testUserhandleBase64 = "AAECAwQFBgcICQ==";
index 623581f..5a150c2 100644 (file)
@@ -882,3 +882,9 @@ webkit.org/b/184204 [ Sierra ] http/wpt/cache-storage/cache-put-keys.https.any.w
 webkit.org/b/189094 [ HighSierra+ ] accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html [ Skip ]
 
 webkit.org/b/189598 compositing/backing/backing-store-attachment-fill-forwards-animation.html [ Pass Failure ]
+
+# Skip local authenticator tests for mac now.
+http/wpt/webauthn/public-key-credential-create-failure-local.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-success-local.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-failure-local.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-success-local.https.html [ Skip ]
index d96a0e3..a2b7946 100644 (file)
@@ -415,6 +415,7 @@ set(WebCore_NON_SVG_IDL_FILES
     Modules/webauthn/AuthenticatorAssertionResponse.idl
     Modules/webauthn/AuthenticatorAttestationResponse.idl
     Modules/webauthn/AuthenticatorResponse.idl
+    Modules/webauthn/AuthenticatorTransport.idl
     Modules/webauthn/PublicKeyCredential.idl
     Modules/webauthn/PublicKeyCredentialCreationOptions.idl
     Modules/webauthn/PublicKeyCredentialDescriptor.idl
index 893420f..68e3189 100644 (file)
@@ -1,3 +1,253 @@
+2018-09-25  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Make AuthenticatorManager
+        https://bugs.webkit.org/show_bug.cgi?id=189279
+        <rdar://problem/44116792>
+
+        Reviewed by Chris Dumez.
+
+        This patch does the following things in WebCore in order to support AuthenticatorManager:
+        1) It separates AuthenticatorTransport from PublicKeyCredentialDescriptor such that the enum
+        can be queried from WebKit directly.
+        2) It adds AuthenticatorAttachment to PublicKeyCredentialCreationOptions such that relying parties
+        could express their interests in cross platform authenticators.
+        3) It enhances IPC encoder/decoder of a few such that Vectors and empty objects can be correctly coded.
+        4) It moves the LocalAuthenticator implementation to WebKit to better integrate with AuthenticatorManager.
+        5) It moves linking to LocalAuthentication.framework to WebKit as well.
+        6) It temporarily bans old mock test mechanism in Internals so we could enable the new mock test mechanism in
+        WebKitTestRunner which we will have a better coverage of codes in UI Process. Those tests will be either
+        removed or ported to the new mechanism in Bug 189283.
+        7) It also removes "using namespace WebCore" from the top namespace in some .mm files as they are reordered
+        to where they could introduce name confusions.
+
+        Tests: http/wpt/webauthn/public-key-credential-create-failure-local.https.html
+               http/wpt/webauthn/public-key-credential-create-success-local.https.html
+               http/wpt/webauthn/public-key-credential-get-failure-local.https.html
+               http/wpt/webauthn/public-key-credential-get-success-local.https.html
+               http/wpt/webauthn/public-key-credential-is-user-verifying-platform-authenticator-available.html
+
+        * CMakeLists.txt:
+        * Configurations/WebCore.xcconfig:
+        * DerivedSources.make:
+        * Modules/webauthn/AuthenticatorTransport.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * Modules/webauthn/AuthenticatorTransport.idl: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl.
+        * Modules/webauthn/PublicKeyCredentialCreationOptions.h:
+        (WebCore::PublicKeyCredentialCreationOptions::encode const):
+        (WebCore::PublicKeyCredentialCreationOptions::decode):
+        * Modules/webauthn/PublicKeyCredentialCreationOptions.idl:
+        * Modules/webauthn/PublicKeyCredentialData.h:
+        (WebCore::PublicKeyCredentialData::encode const):
+        (WebCore::PublicKeyCredentialData::decode):
+        * Modules/webauthn/PublicKeyCredentialDescriptor.h:
+        (WebCore::PublicKeyCredentialDescriptor::encode const):
+        * Modules/webauthn/PublicKeyCredentialDescriptor.idl:
+        * Modules/webauthn/cocoa/LocalAuthenticator.mm: Removed.
+        * Sources.txt:
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/ExceptionData.h:
+        * platform/cocoa/LocalAuthenticationSoftLink.mm: Removed.
+        * platform/cocoa/SharedBufferCocoa.mm:
+        (-[WebCoreSharedBufferData initWithSharedBufferDataSegment:]):
+        * platform/cocoa/VideoFullscreenModelVideoElement.mm:
+        (VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement): Deleted.
+        (VideoFullscreenModelVideoElement::~VideoFullscreenModelVideoElement): Deleted.
+        (VideoFullscreenModelVideoElement::setVideoElement): Deleted.
+        (VideoFullscreenModelVideoElement::handleEvent): Deleted.
+        (VideoFullscreenModelVideoElement::updateForEventName): Deleted.
+        (VideoFullscreenModelVideoElement::willExitFullscreen): Deleted.
+        (VideoFullscreenModelVideoElement::setVideoFullscreenLayer): Deleted.
+        (VideoFullscreenModelVideoElement::waitForPreparedForInlineThen): Deleted.
+        (VideoFullscreenModelVideoElement::requestFullscreenMode): Deleted.
+        (VideoFullscreenModelVideoElement::setVideoLayerFrame): Deleted.
+        (VideoFullscreenModelVideoElement::setVideoLayerGravity): Deleted.
+        (VideoFullscreenModelVideoElement::observedEventNames): Deleted.
+        (VideoFullscreenModelVideoElement::eventNameAll): Deleted.
+        (VideoFullscreenModelVideoElement::fullscreenModeChanged): Deleted.
+        (VideoFullscreenModelVideoElement::addClient): Deleted.
+        (VideoFullscreenModelVideoElement::removeClient): Deleted.
+        (VideoFullscreenModelVideoElement::isVisible const): Deleted.
+        (VideoFullscreenModelVideoElement::setHasVideo): Deleted.
+        (VideoFullscreenModelVideoElement::setVideoDimensions): Deleted.
+        (VideoFullscreenModelVideoElement::willEnterPictureInPicture): Deleted.
+        (VideoFullscreenModelVideoElement::didEnterPictureInPicture): Deleted.
+        (VideoFullscreenModelVideoElement::failedToEnterPictureInPicture): Deleted.
+        (VideoFullscreenModelVideoElement::willExitPictureInPicture): Deleted.
+        (VideoFullscreenModelVideoElement::didExitPictureInPicture): Deleted.
+        * platform/graphics/ca/cocoa/PlatformCAAnimationCocoa.mm:
+        (WebCore::hasExplicitBeginTime):
+        (WebCore::setHasExplicitBeginTime):
+        (WebCore::toCAFillModeType):
+        (WebCore::toCAValueFunctionType):
+        (WebCore::toCAMediaTimingFunction):
+        (WebCore::PlatformCAAnimationCocoa::setFromValue):
+        (WebCore::PlatformCAAnimationCocoa::setToValue):
+        (WebCore::PlatformCAAnimationCocoa::setValues):
+        (fromCAFillModeType): Deleted.
+        (fromCAValueFunctionType): Deleted.
+        (PlatformCAAnimationCocoa::create): Deleted.
+        (PlatformCAAnimationCocoa::PlatformCAAnimationCocoa): Deleted.
+        (PlatformCAAnimationCocoa::~PlatformCAAnimationCocoa): Deleted.
+        (PlatformCAAnimationCocoa::copy const): Deleted.
+        (PlatformCAAnimationCocoa::platformAnimation const): Deleted.
+        (PlatformCAAnimationCocoa::keyPath const): Deleted.
+        (PlatformCAAnimationCocoa::beginTime const): Deleted.
+        (PlatformCAAnimationCocoa::setBeginTime): Deleted.
+        (PlatformCAAnimationCocoa::duration const): Deleted.
+        (PlatformCAAnimationCocoa::setDuration): Deleted.
+        (PlatformCAAnimationCocoa::speed const): Deleted.
+        (PlatformCAAnimationCocoa::setSpeed): Deleted.
+        (PlatformCAAnimationCocoa::timeOffset const): Deleted.
+        (PlatformCAAnimationCocoa::setTimeOffset): Deleted.
+        (PlatformCAAnimationCocoa::repeatCount const): Deleted.
+        (PlatformCAAnimationCocoa::setRepeatCount): Deleted.
+        (PlatformCAAnimationCocoa::autoreverses const): Deleted.
+        (PlatformCAAnimationCocoa::setAutoreverses): Deleted.
+        (PlatformCAAnimationCocoa::fillMode const): Deleted.
+        (PlatformCAAnimationCocoa::setFillMode): Deleted.
+        (PlatformCAAnimationCocoa::setTimingFunction): Deleted.
+        (PlatformCAAnimationCocoa::copyTimingFunctionFrom): Deleted.
+        (PlatformCAAnimationCocoa::isRemovedOnCompletion const): Deleted.
+        (PlatformCAAnimationCocoa::setRemovedOnCompletion): Deleted.
+        (PlatformCAAnimationCocoa::isAdditive const): Deleted.
+        (PlatformCAAnimationCocoa::setAdditive): Deleted.
+        (PlatformCAAnimationCocoa::valueFunction const): Deleted.
+        (PlatformCAAnimationCocoa::setValueFunction): Deleted.
+        (PlatformCAAnimationCocoa::setFromValue): Deleted.
+        (PlatformCAAnimationCocoa::copyFromValueFrom): Deleted.
+        (PlatformCAAnimationCocoa::setToValue): Deleted.
+        (PlatformCAAnimationCocoa::copyToValueFrom): Deleted.
+        (PlatformCAAnimationCocoa::setValues): Deleted.
+        (PlatformCAAnimationCocoa::copyValuesFrom): Deleted.
+        (PlatformCAAnimationCocoa::setKeyTimes): Deleted.
+        (PlatformCAAnimationCocoa::copyKeyTimesFrom): Deleted.
+        (PlatformCAAnimationCocoa::setTimingFunctions): Deleted.
+        (PlatformCAAnimationCocoa::copyTimingFunctionsFrom): Deleted.
+        * platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm:
+        (PlatformCAFilters::filterValueForOperation): Deleted.
+        (PlatformCAFilters::colorMatrixValueForFilter): Deleted.
+        (PlatformCAFilters::setBlendingFiltersOnLayer): Deleted.
+        (PlatformCAFilters::numAnimatedFilterProperties): Deleted.
+        (PlatformCAFilters::animatedFilterPropertyName): Deleted.
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
+        (-[WebAnimationDelegate animationDidStart:]):
+        (-[WebAnimationDelegate animationDidStop:finished:]):
+        (-[WebAnimationDelegate setOwner:]):
+        (PlatformCALayerCocoa::create): Deleted.
+        (PlatformCALayer::platformCALayer): Deleted.
+        (mediaTimeToCurrentTime): Deleted.
+        (PlatformCALayerCocoa::setOwner): Deleted.
+        (toCAFilterType): Deleted.
+        (PlatformCALayerCocoa::layerTypeForPlatformLayer): Deleted.
+        (PlatformCALayerCocoa::PlatformCALayerCocoa): Deleted.
+        (PlatformCALayerCocoa::commonInit): Deleted.
+        (PlatformCALayerCocoa::clone const): Deleted.
+        (PlatformCALayerCocoa::~PlatformCALayerCocoa): Deleted.
+        (PlatformCALayerCocoa::animationStarted): Deleted.
+        (PlatformCALayerCocoa::animationEnded): Deleted.
+        (PlatformCALayerCocoa::setNeedsDisplay): Deleted.
+        (PlatformCALayerCocoa::setNeedsDisplayInRect): Deleted.
+        (PlatformCALayerCocoa::copyContentsFromLayer): Deleted.
+        (PlatformCALayerCocoa::superlayer const): Deleted.
+        (PlatformCALayerCocoa::removeFromSuperlayer): Deleted.
+        (PlatformCALayerCocoa::setSublayers): Deleted.
+        (PlatformCALayerCocoa::removeAllSublayers): Deleted.
+        (PlatformCALayerCocoa::appendSublayer): Deleted.
+        (PlatformCALayerCocoa::insertSublayer): Deleted.
+        (PlatformCALayerCocoa::replaceSublayer): Deleted.
+        (PlatformCALayerCocoa::adoptSublayers): Deleted.
+        (PlatformCALayerCocoa::addAnimationForKey): Deleted.
+        (PlatformCALayerCocoa::removeAnimationForKey): Deleted.
+        (PlatformCALayerCocoa::animationForKey): Deleted.
+        (PlatformCALayerCocoa::setMask): Deleted.
+        (PlatformCALayerCocoa::isOpaque const): Deleted.
+        (PlatformCALayerCocoa::setOpaque): Deleted.
+        (PlatformCALayerCocoa::bounds const): Deleted.
+        (PlatformCALayerCocoa::setBounds): Deleted.
+        (PlatformCALayerCocoa::position const): Deleted.
+        (PlatformCALayerCocoa::setPosition): Deleted.
+        (PlatformCALayerCocoa::anchorPoint const): Deleted.
+        (PlatformCALayerCocoa::setAnchorPoint): Deleted.
+        (PlatformCALayerCocoa::transform const): Deleted.
+        (PlatformCALayerCocoa::setTransform): Deleted.
+        (PlatformCALayerCocoa::sublayerTransform const): Deleted.
+        (PlatformCALayerCocoa::setSublayerTransform): Deleted.
+        (PlatformCALayerCocoa::isHidden const): Deleted.
+        (PlatformCALayerCocoa::setHidden): Deleted.
+        (PlatformCALayerCocoa::contentsHidden const): Deleted.
+        (PlatformCALayerCocoa::setContentsHidden): Deleted.
+        (PlatformCALayerCocoa::userInteractionEnabled const): Deleted.
+        (PlatformCALayerCocoa::setUserInteractionEnabled): Deleted.
+        (PlatformCALayerCocoa::setBackingStoreAttached): Deleted.
+        (PlatformCALayerCocoa::backingStoreAttached const): Deleted.
+        (PlatformCALayerCocoa::geometryFlipped const): Deleted.
+        (PlatformCALayerCocoa::setGeometryFlipped): Deleted.
+        (PlatformCALayerCocoa::isDoubleSided const): Deleted.
+        (PlatformCALayerCocoa::setDoubleSided): Deleted.
+        (PlatformCALayerCocoa::masksToBounds const): Deleted.
+        (PlatformCALayerCocoa::setMasksToBounds): Deleted.
+        (PlatformCALayerCocoa::acceleratesDrawing const): Deleted.
+        (PlatformCALayerCocoa::setAcceleratesDrawing): Deleted.
+        (PlatformCALayerCocoa::wantsDeepColorBackingStore const): Deleted.
+        (PlatformCALayerCocoa::setWantsDeepColorBackingStore): Deleted.
+        (PlatformCALayerCocoa::supportsSubpixelAntialiasedText const): Deleted.
+        (PlatformCALayerCocoa::setSupportsSubpixelAntialiasedText): Deleted.
+        (PlatformCALayerCocoa::hasContents const): Deleted.
+        (PlatformCALayerCocoa::contents const): Deleted.
+        (PlatformCALayerCocoa::setContents): Deleted.
+        (PlatformCALayerCocoa::setContentsRect): Deleted.
+        (PlatformCALayerCocoa::setMinificationFilter): Deleted.
+        (PlatformCALayerCocoa::setMagnificationFilter): Deleted.
+        (PlatformCALayerCocoa::backgroundColor const): Deleted.
+        (PlatformCALayerCocoa::setBackgroundColor): Deleted.
+        (PlatformCALayerCocoa::setBorderWidth): Deleted.
+        (PlatformCALayerCocoa::setBorderColor): Deleted.
+        (PlatformCALayerCocoa::opacity const): Deleted.
+        (PlatformCALayerCocoa::setOpacity): Deleted.
+        (PlatformCALayerCocoa::setFilters): Deleted.
+        (PlatformCALayerCocoa::copyFiltersFrom): Deleted.
+        (PlatformCALayerCocoa::filtersCanBeComposited): Deleted.
+        (PlatformCALayerCocoa::setBlendMode): Deleted.
+        (PlatformCALayerCocoa::setName): Deleted.
+        (PlatformCALayerCocoa::setSpeed): Deleted.
+        (PlatformCALayerCocoa::setTimeOffset): Deleted.
+        (PlatformCALayerCocoa::contentsScale const): Deleted.
+        (PlatformCALayerCocoa::setContentsScale): Deleted.
+        (PlatformCALayerCocoa::cornerRadius const): Deleted.
+        (PlatformCALayerCocoa::setCornerRadius): Deleted.
+        (PlatformCALayerCocoa::setEdgeAntialiasingMask): Deleted.
+        (PlatformCALayerCocoa::shapeRoundedRect const): Deleted.
+        (PlatformCALayerCocoa::setShapeRoundedRect): Deleted.
+        (PlatformCALayerCocoa::shapeWindRule const): Deleted.
+        (PlatformCALayerCocoa::setShapeWindRule): Deleted.
+        (PlatformCALayerCocoa::shapePath const): Deleted.
+        (PlatformCALayerCocoa::setShapePath): Deleted.
+        (PlatformCALayerCocoa::requiresCustomAppearanceUpdateOnBoundsChange const): Deleted.
+        (PlatformCALayerCocoa::updateCustomAppearance): Deleted.
+        (layerContentsFormat): Deleted.
+        (PlatformCALayerCocoa::updateContentsFormat): Deleted.
+        (PlatformCALayerCocoa::tiledBacking): Deleted.
+        (PlatformCALayer::isWebLayer): Deleted.
+        (PlatformCALayer::setBoundsOnMainThread): Deleted.
+        (PlatformCALayer::setPositionOnMainThread): Deleted.
+        (PlatformCALayer::setAnchorPointOnMainThread): Deleted.
+        (PlatformCALayer::collectRectsToPaint): Deleted.
+        (PlatformCALayer::drawLayerContents): Deleted.
+        (PlatformCALayer::frameForLayer): Deleted.
+        (PlatformCALayerCocoa::createCompatibleLayer const): Deleted.
+        (PlatformCALayerCocoa::enumerateRectsBeingDrawn): Deleted.
+        (PlatformCALayerCocoa::backingStoreBytesPerPixel const): Deleted.
+        (PlatformCALayerCocoa::avPlayerLayer const): Deleted.
+        * platform/graphics/ca/cocoa/WebSystemBackdropLayer.mm:
+        (-[WebLightSystemBackdropLayer init]):
+        (-[WebDarkSystemBackdropLayer init]):
+        * platform/graphics/ca/cocoa/WebTiledBackingLayer.mm:
+        (-[WebTiledBackingLayer createTileController:]):
+        (-[WebTiledBackingLayer setNeedsDisplayInRect:]):
+        (-[WebTiledBackingLayer setBorderColor:]):
+        * testing/Internals.cpp:
+        (WebCore::Internals::Internals):
+
 2018-09-25  YUHAN WU  <yuhan_wu@apple.com>
 
         Implement MediaStreamTrack Content Hints
index a0befd4..ab84e89 100644 (file)
@@ -86,9 +86,6 @@ WK_CORE_UI_LDFLAGS_macosx = -framework CoreUI;
 WK_DATA_DETECTORS_CORE_LDFLAGS = $(WK_DATA_DETECTORS_CORE_LDFLAGS_$(WK_PLATFORM_NAME));
 WK_DATA_DETECTORS_CORE_LDFLAGS_macosx = -framework DataDetectorsCore;
 
-WK_DEVICE_IDENTITY_LDFLAGS = $(WK_DEVICE_IDENTITY_LDFLAGS_$(WK_HAVE_DEVICE_IDENTITY));
-WK_DEVICE_IDENTITY_LDFLAGS_YES = -framework DeviceIdentity;
-
 WK_GRAPHICS_SERVICES_LDFLAGS = $(WK_GRAPHICS_SERVICES_LDFLAGS_$(WK_COCOA_TOUCH));
 WK_GRAPHICS_SERVICES_LDFLAGS_cocoatouch = -framework GraphicsServices;
 
@@ -129,7 +126,7 @@ WK_URL_FORMATTING_LDFLAGS = $(WK_URL_FORMATTING_LDFLAGS_$(WK_HAVE_URL_FORMATTING
 WK_URL_FORMATTING_LDFLAGS_YES = -framework URLFormatting;
 
 // FIXME: Reduce the number of allowable_clients <rdar://problem/31823969>
-OTHER_LDFLAGS = $(inherited) $(WK_RELOCATABLE_FRAMEWORK_LDFLAGS) $(WK_UNDEFINED_SYMBOLS_LDFLAGS) -lsqlite3 -lobjc -lANGLE -allowable_client WebCoreTestSupport -allowable_client WebKitLegacy -force_load $(BUILT_PRODUCTS_DIR)/libPAL.a -framework CFNetwork -framework CoreAudio -framework CoreGraphics -framework CoreText -framework Foundation -framework ImageIO -framework Metal $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH)) $(OTHER_LDFLAGS_PLATFORM_$(WK_PLATFORM_NAME)) $(WK_APPKIT_LDFLAGS) $(WK_APPSUPPORT_LDFLAGS) $(WK_AUDIO_UNIT_LDFLAGS) $(WK_CARBON_LDFLAGS) $(WK_CORE_UI_LDFLAGS) $(WK_DATA_DETECTORS_CORE_LDFLAGS) $(WK_DEVICE_IDENTITY_LDFLAGS) $(WK_GRAPHICS_SERVICES_LDFLAGS) $(WK_IOSURFACE_LDFLAGS) $(WK_LIBWEBRTC_LDFLAGS) $(WK_MOBILE_CORE_SERVICES_LDFLAGS) $(WK_MOBILE_GESTALT_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_SYSTEM_CONFIGURATION_LDFLAGS) $(WK_SYSTEM_PREVIEW_LDFLAGS) $(WK_URL_FORMATTING_LDFLAGS);
+OTHER_LDFLAGS = $(inherited) $(WK_RELOCATABLE_FRAMEWORK_LDFLAGS) $(WK_UNDEFINED_SYMBOLS_LDFLAGS) -lsqlite3 -lobjc -lANGLE -allowable_client WebCoreTestSupport -allowable_client WebKitLegacy -force_load $(BUILT_PRODUCTS_DIR)/libPAL.a -framework CFNetwork -framework CoreAudio -framework CoreGraphics -framework CoreText -framework Foundation -framework ImageIO -framework Metal $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH)) $(OTHER_LDFLAGS_PLATFORM_$(WK_PLATFORM_NAME)) $(WK_APPKIT_LDFLAGS) $(WK_APPSUPPORT_LDFLAGS) $(WK_AUDIO_UNIT_LDFLAGS) $(WK_CARBON_LDFLAGS) $(WK_CORE_UI_LDFLAGS) $(WK_DATA_DETECTORS_CORE_LDFLAGS) $(WK_GRAPHICS_SERVICES_LDFLAGS) $(WK_IOSURFACE_LDFLAGS) $(WK_LIBWEBRTC_LDFLAGS) $(WK_MOBILE_CORE_SERVICES_LDFLAGS) $(WK_MOBILE_GESTALT_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_SYSTEM_CONFIGURATION_LDFLAGS) $(WK_SYSTEM_PREVIEW_LDFLAGS) $(WK_URL_FORMATTING_LDFLAGS);
 
 OTHER_LDFLAGS_PLATFORM_cocoatouch = -allowable_client WebKit -allowable_client iTunesU -allowable_client Casablanca -allowable_client Remote -allowable_client TVBooks -allowable_client DumpRenderTree -allowable_client WebKitTestRunner -allowable_client TestWebKitAPI;
 OTHER_LDFLAGS_PLATFORM_macosx = -sub_library libobjc -umbrella WebKit;
@@ -188,9 +185,6 @@ SUPPORTS_TEXT_BASED_API = $(SUPPORTS_TEXT_BASED_API_$(TARGET_NAME))
 SUPPORTS_TEXT_BASED_API_WebCore = $(WEBCORE_ENABLE_INSTALLAPI)
 TEXT_BASED_API_FILE = WebCore.tbd
 
-WK_HAVE_DEVICE_IDENTITY = $(WK_HAVE_DEVICE_IDENTITY_$(PLATFORM_NAME));
-WK_HAVE_DEVICE_IDENTITY_iphoneos = YES;
-
 WK_HAVE_URL_FORMATTING = $(WK_HAVE_URL_FORMATTING_$(WK_PLATFORM_NAME));
 WK_HAVE_URL_FORMATTING_iphoneos = $(WK_HAVE_URL_FORMATTING$(WK_IOS_12));
 WK_HAVE_URL_FORMATTING_iosmac = $(WK_HAVE_URL_FORMATTING$(WK_IOS_12));
index 382140f..590789a 100644 (file)
@@ -340,10 +340,11 @@ JS_BINDING_IDLS = \
     $(WebCore)/Modules/webauthn/AuthenticatorAssertionResponse.idl \
     $(WebCore)/Modules/webauthn/AuthenticatorAttestationResponse.idl \
     $(WebCore)/Modules/webauthn/AuthenticatorResponse.idl \
+    $(WebCore)/Modules/webauthn/AuthenticatorTransport.idl \
     $(WebCore)/Modules/webauthn/PublicKeyCredential.idl \
-       $(WebCore)/Modules/webauthn/PublicKeyCredentialCreationOptions.idl \
+    $(WebCore)/Modules/webauthn/PublicKeyCredentialCreationOptions.idl \
     $(WebCore)/Modules/webauthn/PublicKeyCredentialDescriptor.idl \
-       $(WebCore)/Modules/webauthn/PublicKeyCredentialRequestOptions.idl \
+    $(WebCore)/Modules/webauthn/PublicKeyCredentialRequestOptions.idl \
     $(WebCore)/Modules/webauthn/PublicKeyCredentialType.idl \
     $(WebCore)/Modules/webdatabase/DOMWindowWebDatabase.idl \
     $(WebCore)/Modules/webdatabase/Database.idl \
diff --git a/Source/WebCore/Modules/webauthn/AuthenticatorTransport.h b/Source/WebCore/Modules/webauthn/AuthenticatorTransport.h
new file mode 100644 (file)
index 0000000..d672e8a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <wtf/EnumTraits.h>
+
+namespace WebCore {
+
+enum class AuthenticatorTransport {
+    Usb,
+    Nfc,
+    Ble,
+    Internal
+};
+
+} // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::AuthenticatorTransport> {
+    using values = EnumValues<
+        WebCore::AuthenticatorTransport,
+        WebCore::AuthenticatorTransport::Usb,
+        WebCore::AuthenticatorTransport::Nfc,
+        WebCore::AuthenticatorTransport::Ble,
+        WebCore::AuthenticatorTransport::Internal
+    >;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/AuthenticatorTransport.idl b/Source/WebCore/Modules/webauthn/AuthenticatorTransport.idl
new file mode 100644 (file)
index 0000000..8bc8f54
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=WEB_AUTHN,
+] enum AuthenticatorTransport {
+    "usb",
+    "nfc",
+    "ble",
+    "internal"
+};
index 341397c..bc17b58 100644 (file)
 #include "PublicKeyCredentialDescriptor.h"
 #include "PublicKeyCredentialType.h"
 #include <wtf/CrossThreadCopier.h>
+#include <wtf/EnumTraits.h>
 #include <wtf/Forward.h>
 
 namespace WebCore {
 
 struct PublicKeyCredentialCreationOptions {
+    enum class AuthenticatorAttachment {
+        Platform,
+        CrossPlatform
+    };
+
     struct Entity {
         String name;
         String icon;
@@ -59,6 +65,13 @@ struct PublicKeyCredentialCreationOptions {
         template<class Decoder> static std::optional<Parameters> decode(Decoder&);
     };
 
+    struct AuthenticatorSelectionCriteria {
+        AuthenticatorAttachment authenticatorAttachment;
+
+        template<class Encoder> void encode(Encoder&) const;
+        template<class Decoder> static std::optional<AuthenticatorSelectionCriteria> decode(Decoder&);
+    };
+
     RpEntity rp;
     UserEntity user;
 
@@ -67,6 +80,7 @@ struct PublicKeyCredentialCreationOptions {
 
     std::optional<unsigned long> timeout;
     Vector<PublicKeyCredentialDescriptor> excludeCredentials;
+    std::optional<AuthenticatorSelectionCriteria> authenticatorSelection;
 
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static std::optional<PublicKeyCredentialCreationOptions> decode(Decoder&);
@@ -89,6 +103,21 @@ std::optional<PublicKeyCredentialCreationOptions::Parameters> PublicKeyCredentia
     return result;
 }
 
+template<class Encoder>
+void PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria::encode(Encoder& encoder) const
+{
+    encoder << authenticatorAttachment;
+}
+
+template<class Decoder>
+std::optional<PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria> PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria::decode(Decoder& decoder)
+{
+    PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria result;
+    if (!decoder.decodeEnum(result.authenticatorAttachment))
+        return std::nullopt;
+    return result;
+}
+
 // Not every member is encoded.
 template<class Encoder>
 void PublicKeyCredentialCreationOptions::encode(Encoder& encoder) const
@@ -96,7 +125,7 @@ void PublicKeyCredentialCreationOptions::encode(Encoder& encoder) const
     encoder << rp.id << rp.name << rp.icon;
     encoder << static_cast<uint64_t>(user.id.length());
     encoder.encodeFixedLengthData(user.id.data(), user.id.length(), 1);
-    encoder << user.displayName << user.name << user.icon << pubKeyCredParams << excludeCredentials;
+    encoder << user.displayName << user.name << user.icon << pubKeyCredParams << excludeCredentials << authenticatorSelection;
 }
 
 template<class Decoder>
@@ -109,15 +138,8 @@ std::optional<PublicKeyCredentialCreationOptions> PublicKeyCredentialCreationOpt
         return std::nullopt;
     if (!decoder.decode(result.rp.icon))
         return std::nullopt;
-
-    std::optional<uint64_t> userIdLength;
-    decoder >> userIdLength;
-    if (!userIdLength)
-        return std::nullopt;
-    result.user.idVector.reserveCapacity(userIdLength.value());
-    if (!decoder.decodeFixedLengthData(result.user.idVector.data(), userIdLength.value(), 1))
+    if (!decoder.decode(result.user.idVector))
         return std::nullopt;
-
     if (!decoder.decode(result.user.displayName))
         return std::nullopt;
     if (!decoder.decode(result.user.name))
@@ -128,6 +150,13 @@ std::optional<PublicKeyCredentialCreationOptions> PublicKeyCredentialCreationOpt
         return std::nullopt;
     if (!decoder.decode(result.excludeCredentials))
         return std::nullopt;
+
+    std::optional<std::optional<AuthenticatorSelectionCriteria>> authenticatorSelection;
+    decoder >> authenticatorSelection;
+    if (!authenticatorSelection)
+        return std::nullopt;
+    result.authenticatorSelection = WTFMove(authenticatorSelection.value());
+
     return result;
 }
 
@@ -151,6 +180,15 @@ template<> struct CrossThreadCopierBase<false, false, WebCore::PublicKeyCredenti
         return result;
     }
 };
+
+template<> struct EnumTraits<WebCore::PublicKeyCredentialCreationOptions::AuthenticatorAttachment> {
+    using values = EnumValues<
+        WebCore::PublicKeyCredentialCreationOptions::AuthenticatorAttachment,
+        WebCore::PublicKeyCredentialCreationOptions::AuthenticatorAttachment::Platform,
+        WebCore::PublicKeyCredentialCreationOptions::AuthenticatorAttachment::CrossPlatform
+    >;
+};
+
 } // namespace WTF
 
 #endif // ENABLE(WEB_AUTHN)
index 3853eba..a31525f 100644 (file)
@@ -36,9 +36,7 @@ typedef long COSEAlgorithmIdentifier;
 
     unsigned long timeout;
     sequence<PublicKeyCredentialDescriptor> excludeCredentials = [];
-    // We don't allow RPs to select authenticators at this stage.
-    // Hence, those options are always { "platform", true, "required" }.
-    // AuthenticatorSelectionCriteria authenticatorSelection;
+    AuthenticatorSelectionCriteria authenticatorSelection;
     // Always "direct" for us.
     // AttestationConveyancePreference attestation = "none";
     // Not support yet.
@@ -71,3 +69,20 @@ typedef long COSEAlgorithmIdentifier;
     required PublicKeyCredentialType type;
     required COSEAlgorithmIdentifier alg;
 };
+
+[
+    Conditional=WEB_AUTHN,
+] dictionary AuthenticatorSelectionCriteria {
+    AuthenticatorAttachment      authenticatorAttachment;
+    // We don't allow RPs to set the following values at this stage.
+    // Hence, those options are always { true, "required" }.
+    // boolean                      requireResidentKey = false;
+    // UserVerificationRequirement  userVerification = "preferred";
+};
+
+[
+    Conditional=WEB_AUTHN,
+] enum AuthenticatorAttachment {
+    "platform",
+    "cross-platform"
+};
index 229fb87..33928a8 100644 (file)
@@ -57,17 +57,25 @@ struct PublicKeyCredentialData {
 template<class Encoder>
 void PublicKeyCredentialData::encode(Encoder& encoder) const
 {
+    if (!rawId) {
+        encoder << true;
+        return;
+    }
+    encoder << false;
+
     encoder << static_cast<uint64_t>(rawId->byteLength());
     encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(rawId->data()), rawId->byteLength(), 1);
 
     encoder << isAuthenticatorAttestationResponse;
 
-    if (isAuthenticatorAttestationResponse) {
+    if (isAuthenticatorAttestationResponse && attestationObject) {
         encoder << static_cast<uint64_t>(attestationObject->byteLength());
         encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(attestationObject->data()), attestationObject->byteLength(), 1);
         return;
     }
 
+    if (!authenticatorData || !signature || !userHandle)
+        return;
     encoder << static_cast<uint64_t>(authenticatorData->byteLength());
     encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(authenticatorData->data()), authenticatorData->byteLength(), 1);
     encoder << static_cast<uint64_t>(signature->byteLength());
@@ -81,6 +89,13 @@ std::optional<PublicKeyCredentialData> PublicKeyCredentialData::decode(Decoder&
 {
     PublicKeyCredentialData result;
 
+    std::optional<bool> isEmpty;
+    decoder >> isEmpty;
+    if (!isEmpty)
+        return std::nullopt;
+    if (isEmpty.value())
+        return result;
+
     std::optional<uint64_t> rawIdLength;
     decoder >> rawIdLength;
     if (!rawIdLength)
index f387d87..3f7b6b5 100644 (file)
 
 #if ENABLE(WEB_AUTHN)
 
+#include "AuthenticatorTransport.h"
 #include "BufferSource.h"
 #include "PublicKeyCredentialType.h"
-#include <wtf/EnumTraits.h>
 
 namespace WebCore {
 
 struct PublicKeyCredentialDescriptor {
-    enum class AuthenticatorTransport {
-        Usb,
-        Nfc,
-        Ble
-    };
-
     PublicKeyCredentialType type;
     BufferSource id; // id becomes idVector once it is passed to UIProcess.
     Vector<uint8_t> idVector;
@@ -53,9 +47,9 @@ template<class Encoder>
 void PublicKeyCredentialDescriptor::encode(Encoder& encoder) const
 {
     encoder << type;
-    Vector<uint8_t> idVector;
-    idVector.append(id.data(), id.length());
-    encoder << idVector << transports;
+    encoder << static_cast<uint64_t>(id.length());
+    encoder.encodeFixedLengthData(id.data(), id.length(), 1);
+    encoder << transports;
 }
 
 template<class Decoder>
@@ -73,17 +67,4 @@ std::optional<PublicKeyCredentialDescriptor> PublicKeyCredentialDescriptor::deco
 
 } // namespace WebCore
 
-namespace WTF {
-
-template<> struct EnumTraits<WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport> {
-    using values = EnumValues<
-        WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport,
-        WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport::Usb,
-        WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport::Nfc,
-        WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport::Ble
-    >;
-};
-
-}
-
 #endif // ENABLE(WEB_AUTHN)
index 0c3feed..2a7d6f3 100644 (file)
 
 [
     Conditional=WEB_AUTHN,
-] enum AuthenticatorTransport {
-    "usb",
-    "nfc",
-    "ble"
-};
-
-[
-    Conditional=WEB_AUTHN,
 ] dictionary PublicKeyCredentialDescriptor {
     required PublicKeyCredentialType type;
     required BufferSource id;
diff --git a/Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.mm b/Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.mm
deleted file mode 100644 (file)
index 965d1f2..0000000
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "LocalAuthenticator.h"
-
-#if ENABLE(WEB_AUTHN)
-
-#import "CBORWriter.h"
-#import "COSEConstants.h"
-#import "ExceptionData.h"
-#import "PublicKeyCredentialCreationOptions.h"
-#import "PublicKeyCredentialData.h"
-#import "PublicKeyCredentialRequestOptions.h"
-#import <Security/SecItem.h>
-#import <pal/crypto/CryptoDigest.h>
-#import <pal/spi/cocoa/DeviceIdentitySPI.h>
-#import <wtf/BlockPtr.h>
-#import <wtf/HashSet.h>
-#import <wtf/MainThread.h>
-#import <wtf/ProcessPrivilege.h>
-#import <wtf/RetainPtr.h>
-#import <wtf/Vector.h>
-#import <wtf/text/StringHash.h>
-
-#import "LocalAuthenticationSoftLink.h"
-
-namespace WebCore {
-
-namespace LocalAuthenticatorInternal {
-
-// See https://www.w3.org/TR/webauthn/#flags.
-const uint8_t makeCredentialFlags = 0b01000101; // UP, UV and AT are set.
-const uint8_t getAssertionFlags = 0b00000101; // UP and UV are set.
-// FIXME(rdar://problem/38320512): Define Apple AAGUID.
-const uint8_t AAGUID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 16 bytes
-// Credential ID is currently SHA-1 of the corresponding public key.
-// FIXME(183534): Assume little endian here.
-const union {
-    uint16_t integer;
-    uint8_t bytes[2];
-} credentialIdLength = {0x0014};
-const size_t ES256KeySizeInBytes = 32;
-const size_t authDataPrefixFixedSize = 37; // hash(32) + flags(1) + counter(4)
-
-#if PLATFORM(IOS)
-// https://www.w3.org/TR/webauthn/#sec-authenticator-data
-static Vector<uint8_t> buildAuthData(const String& rpId, const uint8_t flags, const uint32_t counter, const Vector<uint8_t>& optionalAttestedCredentialData)
-{
-    Vector<uint8_t> authData;
-    authData.reserveCapacity(authDataPrefixFixedSize + optionalAttestedCredentialData.size());
-
-    // RP ID hash
-    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
-    // FIXME(183534): Test IDN.
-    ASSERT(rpId.isAllASCII());
-    auto asciiRpId = rpId.ascii();
-    crypto->addBytes(asciiRpId.data(), asciiRpId.length());
-    authData = crypto->computeHash();
-
-    // FLAGS
-    authData.append(flags);
-
-    // COUNTER
-    // FIXME(183534): Assume little endian here.
-    union {
-        uint32_t integer;
-        uint8_t bytes[4];
-    } counterUnion;
-    counterUnion.integer = counter;
-    authData.append(counterUnion.bytes, sizeof(counterUnion.bytes));
-
-    // ATTESTED CRED. DATA
-    authData.appendVector(optionalAttestedCredentialData);
-
-    return authData;
-}
-
-inline HashSet<String> produceHashSet(const Vector<PublicKeyCredentialDescriptor>& credentialDescriptors)
-{
-    HashSet<String> result;
-    for (auto& credentialDescriptor : credentialDescriptors) {
-        if (credentialDescriptor.transports.isEmpty() && credentialDescriptor.type == PublicKeyCredentialType::PublicKey && credentialDescriptor.idVector.size() == credentialIdLength.integer)
-            result.add(String(reinterpret_cast<const char*>(credentialDescriptor.idVector.data()), credentialDescriptor.idVector.size()));
-    }
-    return result;
-}
-#endif // !PLATFORM(IOS)
-
-} // LocalAuthenticatorInternal
-
-LocalAuthenticator::LocalAuthenticator()
-{
-    RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
-}
-
-void LocalAuthenticator::makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions& options, Callback&& callback)
-{
-    using namespace LocalAuthenticatorInternal;
-
-#if !PLATFORM(IOS)
-    // FIXME(182772)
-    ASSERT_UNUSED(hash, hash == hash);
-    ASSERT_UNUSED(options, !options.rp.id.isEmpty());
-    ASSERT_UNUSED(callback, callback);
-    callback(ExceptionData { NotAllowedError, "No avaliable authenticators."_s });
-#else
-    // The following implements https://www.w3.org/TR/webauthn/#op-make-cred as of 5 December 2017.
-    // Skip Step 4-5 as requireResidentKey and requireUserVerification are enforced.
-    // Skip Step 9 as extensions are not supported yet.
-    // Step 8 is implicitly captured by all UnknownError exception callbacks.
-    // Step 2.
-    bool canFullfillPubKeyCredParams = false;
-    for (auto& pubKeyCredParam : options.pubKeyCredParams) {
-        if (pubKeyCredParam.type == PublicKeyCredentialType::PublicKey && pubKeyCredParam.alg == COSE::ES256) {
-            canFullfillPubKeyCredParams = true;
-            break;
-        }
-    }
-    if (!canFullfillPubKeyCredParams) {
-        callback(ExceptionData { NotSupportedError, "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters."_s });
-        return;
-    }
-
-    // Step 3.
-    HashSet<String> excludeCredentialIds = produceHashSet(options.excludeCredentials);
-    if (!excludeCredentialIds.isEmpty()) {
-        // Search Keychain for the RP ID.
-        NSDictionary *query = @{
-            (id)kSecClass: (id)kSecClassKey,
-            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-            (id)kSecAttrLabel: options.rp.id,
-            (id)kSecReturnAttributes: @YES,
-            (id)kSecMatchLimit: (id)kSecMatchLimitAll,
-        };
-        CFTypeRef attributesArrayRef = nullptr;
-        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef);
-        if (status && status != errSecItemNotFound) {
-            LOG_ERROR("Couldn't query Keychain: %d", status);
-            callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-            return;
-        }
-        auto retainAttributesArray = adoptCF(attributesArrayRef);
-
-        for (NSDictionary *nsAttributes in (NSArray *)attributesArrayRef) {
-            NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel];
-            if (excludeCredentialIds.contains(String(reinterpret_cast<const char*>(nsCredentialId.bytes), nsCredentialId.length))) {
-                callback(ExceptionData { NotAllowedError, "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator."_s });
-                return;
-            }
-        }
-    }
-
-    // Step 6.
-    // FIXME(rdar://problem/35900593): Update to a formal UI.
-    // Get user consent.
-    auto context = adoptNS([allocLAContextInstance() init]);
-    NSError *error = nil;
-    if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
-        LOG_ERROR("Couldn't evaluate authentication with biometrics policy: %@", error);
-        // FIXME(182767)
-        callback(ExceptionData { NotAllowedError, "No avaliable authenticators."_s });
-        return;
-    }
-
-    NSString *reason = [NSString stringWithFormat:@"Allow %@ to create a public key credential for %@", (id)options.rp.id, (id)options.user.name];
-    // FIXME(183534): Optimize the following nested callbacks and threading.
-    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:BlockPtr<void(BOOL, NSError *)>::fromCallable([weakThis = makeWeakPtr(*this), callback = WTFMove(callback), options = crossThreadCopy(options), hash] (BOOL success, NSError *error) mutable {
-        ASSERT(!isMainThread());
-        if (!success || error) {
-            LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
-            callback(ExceptionData { NotAllowedError, "Couldn't get user consent."_s });
-            return;
-        }
-
-        // Step 7.5.
-        // Userhandle is stored in kSecAttrApplicationTag attribute.
-        // Failures after this point could block users' accounts forever. Should we follow the spec?
-        NSDictionary* deleteQuery = @{
-            (id)kSecClass: (id)kSecClassKey,
-            (id)kSecAttrLabel: options.rp.id,
-            (id)kSecAttrApplicationTag: [NSData dataWithBytes:options.user.idVector.data() length:options.user.idVector.size()],
-        };
-        OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
-        if (status && status != errSecItemNotFound) {
-            LOG_ERROR("Couldn't detele older credential: %d", status);
-            callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-            return;
-        }
-
-        // Step 7.1, 13. Apple Attestation
-        // FIXME(183534)
-        if (!weakThis)
-            return;
-        weakThis->issueClientCertificate(options.rp.id, options.user.name, hash, BlockPtr<void(SecKeyRef, NSArray *, NSError *)>::fromCallable([callback = WTFMove(callback), options = crossThreadCopy(options)] (_Nullable SecKeyRef privateKey, NSArray * _Nullable certificates, NSError * _Nullable error) {
-            ASSERT(!isMainThread());
-            if (error) {
-                LOG_ERROR("Couldn't attest: %@", error);
-                callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                return;
-            }
-            // Attestation Certificate and Attestation Issuing CA
-            ASSERT(certificates && ([certificates count] == 2));
-
-            // Step 7.2-7.4.
-            // FIXME(183533): A single kSecClassKey item couldn't store all meta data. The following schema is a tentative solution
-            // to accommodate the most important meta data, i.e. RP ID, Credential ID, and userhandle.
-            // kSecAttrLabel: RP ID
-            // kSecAttrApplicationLabel: Credential ID (auto-gen by Keychain)
-            // kSecAttrApplicationTag: userhandle
-            // Noted, the current DeviceIdentity.Framework would only allow us to pass the kSecAttrLabel as the inital attribute
-            // for the Keychain item. Since that's the only clue we have to locate the unique item, we use the pattern username@rp.id
-            // as the initial value.
-            // Also noted, the vale of kSecAttrApplicationLabel is automatically generated by the Keychain, which is a SHA-1 hash of
-            // the public key. We borrow it directly for now to workaround the stated limitations.
-            // Update the Keychain item to the above schema.
-            // FIXME(183533): DeviceIdentity.Framework would insert certificates into Keychain as well. We should update those as well.
-            Vector<uint8_t> credentialId;
-            {
-                String label(options.user.name);
-                label.append("@" + options.rp.id + "-rk"); // -rk is added by DeviceIdentity.Framework.
-                NSDictionary *credentialIdQuery = @{
-                    (id)kSecClass: (id)kSecClassKey,
-                    (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-                    (id)kSecAttrLabel: label,
-                    (id)kSecReturnAttributes: @YES
-                };
-                CFTypeRef attributesRef = nullptr;
-                OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)credentialIdQuery, &attributesRef);
-                if (status) {
-                    LOG_ERROR("Couldn't get Credential ID: %d", status);
-                    callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                    return;
-                }
-                auto retainAttributes = adoptCF(attributesRef);
-
-                NSDictionary *nsAttributes = (NSDictionary *)attributesRef;
-                NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel];
-                credentialId.append(reinterpret_cast<const uint8_t*>(nsCredentialId.bytes), nsCredentialId.length);
-
-                NSDictionary *updateQuery = @{
-                    (id)kSecClass: (id)kSecClassKey,
-                    (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-                    (id)kSecAttrApplicationLabel: nsCredentialId,
-                };
-                NSDictionary *updateParams = @{
-                    (id)kSecAttrLabel: options.rp.id,
-                    (id)kSecAttrApplicationTag: [NSData dataWithBytes:options.user.idVector.data() length:options.user.idVector.size()],
-                };
-                status = SecItemUpdate((__bridge CFDictionaryRef)updateQuery, (__bridge CFDictionaryRef)updateParams);
-                if (status) {
-                    LOG_ERROR("Couldn't update the Keychain item: %d", status);
-                    callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                    return;
-                }
-            }
-
-            // Step 10.
-            // FIXME(183533): store the counter.
-            uint32_t counter = 0;
-
-            // FIXME(183534): attestedCredentialData could throttle.
-            // Step 11. https://www.w3.org/TR/webauthn/#attested-credential-data
-            Vector<uint8_t> attestedCredentialData;
-            {
-                // aaguid
-                attestedCredentialData.append(AAGUID, sizeof(AAGUID));
-
-                // credentialIdLength
-                ASSERT(credentialId.size() == credentialIdLength.integer);
-                // FIXME(183534): Assume little endian here.
-                attestedCredentialData.append(credentialIdLength.bytes, sizeof(uint16_t));
-
-                // credentialId
-                attestedCredentialData.appendVector(credentialId);
-
-                // credentialPublicKey
-                RetainPtr<CFDataRef> publicKeyDataRef;
-                {
-                    auto publicKey = adoptCF(SecKeyCopyPublicKey(privateKey));
-                    CFErrorRef errorRef = nullptr;
-                    publicKeyDataRef = adoptCF(SecKeyCopyExternalRepresentation(publicKey.get(), &errorRef));
-                    auto retainError = adoptCF(errorRef);
-                    if (errorRef) {
-                        LOG_ERROR("Couldn't export the public key: %@", (NSError*)errorRef);
-                        callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                        return;
-                    }
-                    ASSERT(((NSData *)publicKeyDataRef.get()).length == (1 + 2 * ES256KeySizeInBytes)); // 04 | X | Y
-                }
-
-                // COSE Encoding
-                // FIXME(183535): Improve CBOR encoder to work with bytes directly.
-                Vector<uint8_t> x(ES256KeySizeInBytes);
-                [(NSData *)publicKeyDataRef.get() getBytes: x.data() range:NSMakeRange(1, ES256KeySizeInBytes)];
-                Vector<uint8_t> y(ES256KeySizeInBytes);
-                [(NSData *)publicKeyDataRef.get() getBytes: y.data() range:NSMakeRange(1 + ES256KeySizeInBytes, ES256KeySizeInBytes)];
-                cbor::CBORValue::MapValue publicKeyMap;
-                publicKeyMap[cbor::CBORValue(COSE::kty)] = cbor::CBORValue(COSE::EC2);
-                publicKeyMap[cbor::CBORValue(COSE::alg)] = cbor::CBORValue(COSE::ES256);
-                publicKeyMap[cbor::CBORValue(COSE::crv)] = cbor::CBORValue(COSE::P_256);
-                publicKeyMap[cbor::CBORValue(COSE::x)] = cbor::CBORValue(WTFMove(x));
-                publicKeyMap[cbor::CBORValue(COSE::y)] = cbor::CBORValue(WTFMove(y));
-                auto cosePublicKey = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(publicKeyMap)));
-                if (!cosePublicKey) {
-                    LOG_ERROR("Couldn't encode the public key into COSE binaries.");
-                    callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                    return;
-                }
-                attestedCredentialData.appendVector(cosePublicKey.value());
-            }
-
-            // Step 12.
-            auto authData = buildAuthData(options.rp.id, makeCredentialFlags, counter, attestedCredentialData);
-
-            // Step 13. Apple Attestation Cont'
-            // Assemble the attestation object:
-            // https://www.w3.org/TR/webauthn/#attestation-object
-            cbor::CBORValue::MapValue attestationStatementMap;
-            {
-                Vector<uint8_t> signature;
-                {
-                    CFErrorRef errorRef = nullptr;
-                    // FIXME(183652): Reduce prompt for biometrics
-                    auto signatureRef = adoptCF(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)[NSData dataWithBytes:authData.data() length:authData.size()], &errorRef));
-                    auto retainError = adoptCF(errorRef);
-                    if (errorRef) {
-                        LOG_ERROR("Couldn't generate the signature: %@", (NSError*)errorRef);
-                        callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                        return;
-                    }
-                    auto nsSignature = (NSData *)signatureRef.get();
-                    signature.append(reinterpret_cast<const uint8_t*>(nsSignature.bytes), nsSignature.length);
-                }
-                attestationStatementMap[cbor::CBORValue("alg")] = cbor::CBORValue(COSE::ES256);
-                attestationStatementMap[cbor::CBORValue("sig")] = cbor::CBORValue(signature);
-                Vector<cbor::CBORValue> cborArray;
-                for (size_t i = 0; i < [certificates count]; i++) {
-                    CFDataRef dataRef = SecCertificateCopyData((__bridge SecCertificateRef)certificates[i]);
-                    auto retainData = adoptCF(dataRef);
-                    NSData *nsData = (NSData *)dataRef;
-                    Vector<uint8_t> data;
-                    data.append(reinterpret_cast<const uint8_t*>(nsData.bytes), nsData.length);
-                    cborArray.append(cbor::CBORValue(WTFMove(data)));
-                }
-                attestationStatementMap[cbor::CBORValue("x5c")] = cbor::CBORValue(WTFMove(cborArray));
-            }
-
-            cbor::CBORValue::MapValue attestationObjectMap;
-            attestationObjectMap[cbor::CBORValue("authData")] = cbor::CBORValue(authData);
-            attestationObjectMap[cbor::CBORValue("fmt")] = cbor::CBORValue("Apple");
-            attestationObjectMap[cbor::CBORValue("attStmt")] = cbor::CBORValue(WTFMove(attestationStatementMap));
-            auto attestationObject = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(attestationObjectMap)));
-            if (!attestationObject) {
-                LOG_ERROR("Couldn't encode the attestation object.");
-                callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                return;
-            }
-
-            callback(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.value().data(), attestationObject.value().size()), nullptr, nullptr, nullptr });
-        }).get());
-    }).get()];
-#endif // !PLATFORM(IOS)
-}
-
-void LocalAuthenticator::getAssertion(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions& options, Callback&& callback)
-{
-    using namespace LocalAuthenticatorInternal;
-
-#if !PLATFORM(IOS)
-    // FIXME(182772)
-    ASSERT_UNUSED(hash, hash == hash);
-    ASSERT_UNUSED(options, !options.rpId.isEmpty());
-    ASSERT_UNUSED(callback, callback);
-    callback(ExceptionData { NotAllowedError, "No avaliable authenticators."_s });
-#else
-    // The following implements https://www.w3.org/TR/webauthn/#op-get-assertion as of 5 December 2017.
-    // Skip Step 2 as requireUserVerification is enforced.
-    // Skip Step 8 as extensions are not supported yet.
-    // Step 12 is implicitly captured by all UnknownError exception callbacks.
-    // Step 3-5. Unlike the spec, if an allow list is provided and there is no intersection between existing ones and the allow list, we always return NotAllowedError.
-    HashSet<String> allowCredentialIds = produceHashSet(options.allowCredentials);
-    if (!options.allowCredentials.isEmpty() && allowCredentialIds.isEmpty()) {
-        callback(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });
-        return;
-    }
-
-    // Search Keychain for the RP ID.
-    NSDictionary *query = @{
-        (id)kSecClass: (id)kSecClassKey,
-        (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-        (id)kSecAttrLabel: options.rpId,
-        (id)kSecReturnAttributes: @YES,
-        (id)kSecMatchLimit: (id)kSecMatchLimitAll,
-    };
-    CFTypeRef attributesArrayRef = nullptr;
-    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef);
-    if (status && status != errSecItemNotFound) {
-        LOG_ERROR("Couldn't query Keychain: %d", status);
-        callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-        return;
-    }
-    auto retainAttributesArray = adoptCF(attributesArrayRef);
-
-    NSArray *intersectedCredentialsAttributes = nil;
-    if (options.allowCredentials.isEmpty())
-        intersectedCredentialsAttributes = (NSArray *)attributesArrayRef;
-    else {
-        NSMutableArray *result = [NSMutableArray arrayWithCapacity:allowCredentialIds.size()];
-        for (NSDictionary *nsAttributes in (NSArray *)attributesArrayRef) {
-            NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel];
-            if (allowCredentialIds.contains(String(reinterpret_cast<const char*>(nsCredentialId.bytes), nsCredentialId.length)))
-                [result addObject:nsAttributes];
-        }
-        intersectedCredentialsAttributes = result;
-    }
-    if (!intersectedCredentialsAttributes.count) {
-        callback(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });
-        return;
-    }
-
-    // Step 6.
-    // FIXME(rdar://problem/35900534): We don't have an UI to prompt users for selecting intersectedCredentials, and therefore we always use the first one for now.
-    NSDictionary *selectedCredentialAttributes = intersectedCredentialsAttributes[0];
-
-    // Step 7. Get user consent.
-    // FIXME(183534): The lifetime of context is managed by reply and the early return, which is a bit subtle.
-    LAContext *context = [allocLAContextInstance() init];
-    NSError *error = nil;
-    if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
-        auto retainContext = adoptNS(context);
-        LOG_ERROR("Couldn't evaluate authentication with biometrics policy: %@", error);
-        // FIXME(182767)
-        callback(ExceptionData { NotAllowedError, "No avaliable authenticators."_s });
-        return;
-    }
-
-    Vector<uint8_t> credentialId;
-    NSData *nsCredentialId = selectedCredentialAttributes[(id)kSecAttrApplicationLabel];
-    credentialId.append(reinterpret_cast<const uint8_t*>(nsCredentialId.bytes), nsCredentialId.length);
-    Vector<uint8_t> userhandle;
-    NSData *nsUserhandle = selectedCredentialAttributes[(id)kSecAttrApplicationTag];
-    userhandle.append(reinterpret_cast<const uint8_t*>(nsUserhandle.bytes), nsUserhandle.length);
-    auto reply = BlockPtr<void(BOOL, NSError *)>::fromCallable([callback = WTFMove(callback), rpId = options.rpId.isolatedCopy(), hash, credentialId = WTFMove(credentialId), userhandle = WTFMove(userhandle), context = adoptNS(context)] (BOOL success, NSError *error) mutable {
-        ASSERT(!isMainThread());
-        if (!success || error) {
-            LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
-            callback(ExceptionData { NotAllowedError, "Couldn't get user consent."_s });
-            return;
-        }
-
-        // Step 9-10.
-        // FIXME(183533): Due to the stated Keychain limitations, we can't save the counter value.
-        // Therefore, it is always zero.
-        uint32_t counter = 0;
-        auto authData = buildAuthData(rpId, getAssertionFlags, counter, { });
-
-        // Step 11.
-        Vector<uint8_t> signature;
-        {
-            NSDictionary *query = @{
-                (id)kSecClass: (id)kSecClassKey,
-                (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-                (id)kSecAttrApplicationLabel: [NSData dataWithBytes:credentialId.data() length:credentialId.size()],
-                (id)kSecUseAuthenticationContext: context.get(),
-                (id)kSecReturnRef: @YES,
-            };
-            CFTypeRef privateKeyRef = nullptr;
-            OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &privateKeyRef);
-            if (status) {
-                LOG_ERROR("Couldn't get the private key reference: %d", status);
-                callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                return;
-            }
-            auto privateKey = adoptCF(privateKeyRef);
-
-            NSMutableData *dataToSign = [NSMutableData dataWithBytes:authData.data() length:authData.size()];
-            [dataToSign appendBytes:hash.data() length:hash.size()];
-
-            CFErrorRef errorRef = nullptr;
-            // FIXME: Converting CFTypeRef to SecKeyRef is quite subtle here.
-            auto signatureRef = adoptCF(SecKeyCreateSignature((__bridge SecKeyRef)((id)privateKeyRef), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, &errorRef));
-            auto retainError = adoptCF(errorRef);
-            if (errorRef) {
-                LOG_ERROR("Couldn't generate the signature: %@", (NSError*)errorRef);
-                callback(ExceptionData { UnknownError, "Unknown internal error."_s });
-                return;
-            }
-            auto nsSignature = (NSData *)signatureRef.get();
-            signature.append(reinterpret_cast<const uint8_t*>(nsSignature.bytes), nsSignature.length);
-        }
-
-        // Step 13.
-        callback(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), false, nullptr, nullptr, ArrayBuffer::create(authData.data(), authData.size()), ArrayBuffer::create(signature.data(), signature.size()), ArrayBuffer::create(userhandle.data(), userhandle.size()) });
-    });
-
-    // FIXME(183533): Use userhandle instead of username due to the stated Keychain limitations.
-    NSString *reason = [NSString stringWithFormat:@"Log into %@ with %@.", (id)options.rpId, selectedCredentialAttributes[(id)kSecAttrApplicationTag]];
-    [context evaluateAccessControl:(__bridge SecAccessControlRef)selectedCredentialAttributes[(id)kSecAttrAccessControl] operation:LAAccessControlOperationUseKeySign localizedReason:reason reply:reply.get()];
-#endif // !PLATFORM(IOS)
-}
-
-bool LocalAuthenticator::isAvailable() const
-{
-#if !PLATFORM(IOS)
-    // FIXME(182772)
-    return false;
-#else
-    auto context = adoptNS([allocLAContextInstance() init]);
-    NSError *error = nil;
-
-    if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
-        LOG_ERROR("Couldn't evaluate authentication with biometrics policy: %@", error);
-        return true;
-    }
-    return true;
-#endif // !PLATFORM(IOS)
-}
-
-void LocalAuthenticator::issueClientCertificate(const String& rpId, const String& username, const Vector<uint8_t>& hash, CompletionBlock _Nonnull completionHandler) const
-{
-// DeviceIdentity.Framework is not avaliable in iOS simulator.
-#if !PLATFORM(IOS) || PLATFORM(IOS_SIMULATOR)
-    // FIXME(182772)
-    ASSERT_UNUSED(rpId, !rpId.isEmpty());
-    ASSERT_UNUSED(username, !username.isEmpty());
-    ASSERT_UNUSED(hash, !hash.isEmpty());
-    completionHandler(NULL, NULL, [NSError errorWithDomain:@"com.apple.WebKit.WebAuthN" code:1 userInfo:nil]);
-#else
-    // Apple Attestation
-    ASSERT(hash.size() <= 32);
-
-    RetainPtr<SecAccessControlRef> accessControlRef;
-    {
-        CFErrorRef errorRef = nullptr;
-        accessControlRef = adoptCF(SecAccessControlCreateWithFlags(NULL, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence, &errorRef));
-        auto retainError = adoptCF(errorRef);
-        if (errorRef) {
-            LOG_ERROR("Couldn't create ACL: %@", (NSError *)errorRef);
-            completionHandler(NULL, NULL, [NSError errorWithDomain:@"com.apple.WebKit.WebAuthN" code:1 userInfo:nil]);
-            return;
-        }
-    }
-
-    String label(username);
-    label.append("@" + rpId);
-    NSDictionary *options = @{
-        kMAOptionsBAAKeychainLabel: label,
-        // FIXME(rdar://problem/38489134): Need a formal name.
-        kMAOptionsBAAKeychainAccessGroup: @"com.apple.safari.WebAuthN.credentials",
-        kMAOptionsBAAIgnoreExistingKeychainItems: @(YES),
-        // FIXME(rdar://problem/38489134): Determine a proper lifespan.
-        kMAOptionsBAAValidity: @(1440), // Last one day.
-        kMAOptionsBAASCRTAttestation: @(NO),
-        kMAOptionsBAANonce: [NSData dataWithBytes:hash.data() length:hash.size()],
-        kMAOptionsBAAAccessControls: (id)accessControlRef.get(),
-        kMAOptionsBAAOIDSToInclude: @[kMAOptionsBAAOIDNonce]
-    };
-
-    // FIXME(183652): Reduce prompt for biometrics
-    DeviceIdentityIssueClientCertificateWithCompletion(NULL, options, completionHandler);
-#endif
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(WEB_AUTHN)
index 23f82d2..f4aaa84 100644 (file)
@@ -1,3 +1,15 @@
+2018-09-25  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Make AuthenticatorManager
+        https://bugs.webkit.org/show_bug.cgi?id=189279
+        <rdar://problem/44116792>
+
+        Reviewed by Chris Dumez.
+
+        It moves linking to DeviceIdentity.framework to WebKit.
+
+        * PAL.xcodeproj/project.pbxproj:
+
 2018-09-25  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [iOS] Fix the open source iOS 12 build after r236445
index c3253df..185668f 100644 (file)
                31308B1420A21705003FB929 /* SystemPreviewSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 31308B1320A21705003FB929 /* SystemPreviewSPI.h */; };
                570AB8F120AE2E8D00B8BE87 /* SecKeyProxySPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 570AB8F020AE2E8D00B8BE87 /* SecKeyProxySPI.h */; };
                570AB8F920AF6E3D00B8BE87 /* NSXPCConnectionSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 570AB8F820AF6E3D00B8BE87 /* NSXPCConnectionSPI.h */; };
-               57F12518205787D7001AB8A6 /* DeviceIdentitySPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 57F12517205787C8001AB8A6 /* DeviceIdentitySPI.h */; };
                7A1656441F97B2B900BA3CE4 /* NSKeyedArchiverSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A1656431F97B2B800BA3CE4 /* NSKeyedArchiverSPI.h */; };
                7A3A6A8020CADB4700317AAE /* NSImageSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A3A6A7F20CADB4600317AAE /* NSImageSPI.h */; };
                A10265891F56747A00B4C844 /* HIToolboxSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = A10265881F56747A00B4C844 /* HIToolboxSPI.h */; };
                37119A7820CCB5FF002C6DC9 /* WebKitTargetConditionals.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WebKitTargetConditionals.xcconfig; sourceTree = "<group>"; };
                570AB8F020AE2E8D00B8BE87 /* SecKeyProxySPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecKeyProxySPI.h; sourceTree = "<group>"; };
                570AB8F820AF6E3D00B8BE87 /* NSXPCConnectionSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSXPCConnectionSPI.h; sourceTree = "<group>"; };
-               57F12517205787C8001AB8A6 /* DeviceIdentitySPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceIdentitySPI.h; sourceTree = "<group>"; };
                7A1656431F97B2B800BA3CE4 /* NSKeyedArchiverSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSKeyedArchiverSPI.h; sourceTree = "<group>"; };
                7A3A6A7F20CADB4600317AAE /* NSImageSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSImageSPI.h; sourceTree = "<group>"; };
                93E5909C1F93BF1E0067F8CF /* UnencodableHandling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnencodableHandling.h; sourceTree = "<group>"; };
                                0C2DA1231F3BEB4900DBC317 /* CFNSURLConnectionSPI.h */,
                                0C2DA1241F3BEB4900DBC317 /* CoreTextSPI.h */,
                                0C2DA1251F3BEB4900DBC317 /* DataDetectorsCoreSPI.h */,
-                               57F12517205787C8001AB8A6 /* DeviceIdentitySPI.h */,
                                CE5673862151A7B9002F92D7 /* IOKitSPI.h */,
                                0C2DA1261F3BEB4900DBC317 /* IOPMLibSPI.h */,
                                0C2DA1271F3BEB4900DBC317 /* IOPSLibSPI.h */,
                                0C77858A1F45130F00F4EBB6 /* DataDetectorsSPI.h in Headers */,
                                0C5AF91A1F43A4C7002EAC02 /* DataDetectorsUISPI.h in Headers */,
                                A1175B571F6B470500C4B9F0 /* DefaultSearchProvider.h in Headers */,
-                               57F12518205787D7001AB8A6 /* DeviceIdentitySPI.h in Headers */,
                                0C2D9E731EEF5AF600DBC317 /* ExportMacros.h in Headers */,
                                F44291601FA5261E002CC93E /* FileSizeFormatter.h in Headers */,
                                0C5AF91B1F43A4C7002EAC02 /* GraphicsServicesSPI.h in Headers */,
index 8642d07..4dbb467 100644 (file)
@@ -2428,6 +2428,7 @@ JSAudioProcessingEvent.cpp
 JSAuthenticatorAssertionResponse.cpp
 JSAuthenticatorAttestationResponse.cpp
 JSAuthenticatorResponse.cpp
+JSAuthenticatorTransport.cpp
 JSBarProp.cpp
 JSBasicCredential.cpp
 JSBeforeLoadEvent.cpp
index d7c0ac7..2af1a2f 100644 (file)
@@ -25,7 +25,6 @@ Modules/mediasession/WebMediaSessionManager.cpp
 
 Modules/plugins/QuickTimePluginReplacement.mm
 Modules/plugins/YouTubePluginReplacement.cpp
-Modules/webauthn/cocoa/LocalAuthenticator.mm
 Modules/webdatabase/cocoa/DatabaseManagerCocoa.mm
 
 accessibility/ios/AccessibilityObjectIOS.mm
@@ -196,7 +195,6 @@ platform/cocoa/FileMonitorCocoa.mm
 platform/cocoa/FileSystemCocoa.mm
 platform/cocoa/KeyEventCocoa.mm
 platform/cocoa/LocalizedStringsCocoa.mm
-platform/cocoa/LocalAuthenticationSoftLink.mm
 platform/cocoa/MIMETypeRegistryCocoa.mm
 platform/cocoa/NetworkExtensionContentFilter.mm
 platform/cocoa/ParentalControlsContentFilter.mm
index cca3157..25da566 100644 (file)
                571252691E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h in Headers */ = {isa = PBXBuildFile; fileRef = 571252681E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h */; };
                571F21891DA57C54005C9EFD /* JSSubtleCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 571F21881DA57C54005C9EFD /* JSSubtleCrypto.h */; };
                572093D31DDCEB9A00310AB0 /* CryptoAlgorithmAesCbcCfbParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 572093D21DDCEB9A00310AB0 /* CryptoAlgorithmAesCbcCfbParams.h */; };
-               57212152205365650062AA1F /* LocalAuthenticationSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 5721214E20535D710062AA1F /* LocalAuthenticationSoftLink.h */; };
                5721A9871ECE53B10081295A /* CryptoDigestAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = 5721A9861ECE53B10081295A /* CryptoDigestAlgorithm.h */; };
                5721A98B1ECE57040081295A /* CryptoAlgorithmRsaPssParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5721A9881ECE57040081295A /* CryptoAlgorithmRsaPssParams.h */; };
                572A7F211C6E5719009C6149 /* SimulatedClick.h in Headers */ = {isa = PBXBuildFile; fileRef = 572A7F201C6E5719009C6149 /* SimulatedClick.h */; };
                57303C4620105D2F00355965 /* AuthenticatorCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C4320105B3D00355965 /* AuthenticatorCoordinator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                573489391DAC6B6E00DC0667 /* CryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */; };
                5739E12F1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */; };
-               574F55E0204F3ACE002948C6 /* LocalAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 574F55DE204F3744002948C6 /* LocalAuthenticator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                574F55E1204F3B23002948C6 /* COSEConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 574F55DC204F3732002948C6 /* COSEConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5750A9751E68D00000705C4A /* CryptoKeyEC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9731E68D00000705C4A /* CryptoKeyEC.h */; };
                5750A97E1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A97D1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h */; };
                57DCED672140775B0016B847 /* JSMockAuthenticatorCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED622140763C0016B847 /* JSMockAuthenticatorCoordinator.h */; };
                57DCED69214077640016B847 /* JSMockAuthenticatorCoordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57DCED632140763C0016B847 /* JSMockAuthenticatorCoordinator.cpp */; };
                57DCED74214305F00016B847 /* PublicKeyCredentialData.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED72214305F00016B847 /* PublicKeyCredentialData.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               57DCED9021487FF70016B847 /* AuthenticatorTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED8C21487EDB0016B847 /* AuthenticatorTransport.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               57DCED98214882160016B847 /* JSAuthenticatorTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED92214880C60016B847 /* JSAuthenticatorTransport.h */; };
                57E1E5A31E8C91B500EE37C9 /* CryptoAlgorithmAES_CTR.h in Headers */ = {isa = PBXBuildFile; fileRef = 57E1E5A11E8C91B500EE37C9 /* CryptoAlgorithmAES_CTR.h */; };
                57E1E5A71E8DBD3E00EE37C9 /* CryptoAlgorithmAesCtrParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 57E1E5A61E8DBD3E00EE37C9 /* CryptoAlgorithmAesCtrParams.h */; };
                57E1E5AD1E8DD09B00EE37C9 /* JSAesCtrParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 57E1E5AB1E8DD09B00EE37C9 /* JSAesCtrParams.h */; };
                571F218A1DA57C7A005C9EFD /* JSSubtleCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSubtleCrypto.cpp; sourceTree = "<group>"; };
                572093D11DDCEA4B00310AB0 /* AesCbcCfbParams.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AesCbcCfbParams.idl; sourceTree = "<group>"; };
                572093D21DDCEB9A00310AB0 /* CryptoAlgorithmAesCbcCfbParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAesCbcCfbParams.h; sourceTree = "<group>"; };
-               5721214E20535D710062AA1F /* LocalAuthenticationSoftLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalAuthenticationSoftLink.h; sourceTree = "<group>"; };
-               57212150205361D20062AA1F /* LocalAuthenticationSoftLink.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalAuthenticationSoftLink.mm; sourceTree = "<group>"; };
                5721A9831ECE4FB90081295A /* CryptoAlgorithmRSA_PSSMac.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRSA_PSSMac.cpp; sourceTree = "<group>"; };
                5721A9861ECE53B10081295A /* CryptoDigestAlgorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoDigestAlgorithm.h; sourceTree = "<group>"; };
                5721A9881ECE57040081295A /* CryptoAlgorithmRsaPssParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRsaPssParams.h; sourceTree = "<group>"; };
                574AC7531DAC367D00E9744C /* CryptoAlgorithmParameters.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CryptoAlgorithmParameters.idl; sourceTree = "<group>"; };
                574D42791D594FF6002CF50E /* GlobalCrypto.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GlobalCrypto.idl; sourceTree = "<group>"; };
                574F55DC204F3732002948C6 /* COSEConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COSEConstants.h; sourceTree = "<group>"; };
-               574F55DE204F3744002948C6 /* LocalAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalAuthenticator.h; sourceTree = "<group>"; };
-               574F55DF204F3744002948C6 /* LocalAuthenticator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalAuthenticator.mm; sourceTree = "<group>"; };
                574F55E2204F3CBF002948C6 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; };
                5750A9721E68D00000705C4A /* CryptoKeyEC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoKeyEC.cpp; sourceTree = "<group>"; };
                5750A9731E68D00000705C4A /* CryptoKeyEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoKeyEC.h; sourceTree = "<group>"; };
                57DCED622140763C0016B847 /* JSMockAuthenticatorCoordinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMockAuthenticatorCoordinator.h; sourceTree = "<group>"; };
                57DCED632140763C0016B847 /* JSMockAuthenticatorCoordinator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMockAuthenticatorCoordinator.cpp; sourceTree = "<group>"; };
                57DCED72214305F00016B847 /* PublicKeyCredentialData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PublicKeyCredentialData.h; sourceTree = "<group>"; };
+               57DCED8C21487EDB0016B847 /* AuthenticatorTransport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuthenticatorTransport.h; sourceTree = "<group>"; };
+               57DCED8E21487EDB0016B847 /* AuthenticatorTransport.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AuthenticatorTransport.idl; sourceTree = "<group>"; };
+               57DCED91214880C60016B847 /* JSAuthenticatorTransport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAuthenticatorTransport.cpp; sourceTree = "<group>"; };
+               57DCED92214880C60016B847 /* JSAuthenticatorTransport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAuthenticatorTransport.h; sourceTree = "<group>"; };
                57E1E5A01E8C91B500EE37C9 /* CryptoAlgorithmAES_CTR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmAES_CTR.cpp; sourceTree = "<group>"; };
                57E1E5A11E8C91B500EE37C9 /* CryptoAlgorithmAES_CTR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAES_CTR.h; sourceTree = "<group>"; };
                57E1E5A61E8DBD3E00EE37C9 /* CryptoAlgorithmAesCtrParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAesCtrParams.h; sourceTree = "<group>"; };
                                576082702021513F00116678 /* AuthenticatorCoordinatorClient.h */,
                                57303BCF20087A8300355965 /* AuthenticatorResponse.h */,
                                57303BD120087A8300355965 /* AuthenticatorResponse.idl */,
+                               57DCED8C21487EDB0016B847 /* AuthenticatorTransport.h */,
+                               57DCED8E21487EDB0016B847 /* AuthenticatorTransport.idl */,
                                574F55DC204F3732002948C6 /* COSEConstants.h */,
                                57D8462C1FEAF68F00CA3682 /* PublicKeyCredential.cpp */,
                                57D8462B1FEAF68F00CA3682 /* PublicKeyCredential.h */,
                                57303C212009AEF600355965 /* JSAuthenticatorAttestationResponse.h */,
                                57303BDE20095B2700355965 /* JSAuthenticatorResponse.cpp */,
                                57303BDD20095B2600355965 /* JSAuthenticatorResponse.h */,
+                               57DCED91214880C60016B847 /* JSAuthenticatorTransport.cpp */,
+                               57DCED92214880C60016B847 /* JSAuthenticatorTransport.h */,
                                57D846311FEAFC2F00CA3682 /* JSPublicKeyCredential.cpp */,
                                57D846301FEAFC2F00CA3682 /* JSPublicKeyCredential.h */,
                                57303C142009A25700355965 /* JSPublicKeyCredentialCreationOptions.cpp */,
                                514B3F750C722055000530DF /* FileSystemCocoa.mm */,
                                A5C974CF11485FF10066F2AB /* KeyEventCocoa.h */,
                                A5C974D011485FF10066F2AB /* KeyEventCocoa.mm */,
-                               5721214E20535D710062AA1F /* LocalAuthenticationSoftLink.h */,
-                               57212150205361D20062AA1F /* LocalAuthenticationSoftLink.mm */,
                                1A4832B21A953BA6008B4DFE /* LocalizedStringsCocoa.mm */,
                                C53D39331C97892D007F3AE9 /* MIMETypeRegistryCocoa.mm */,
                                A19D93491AA11B1E00B46C24 /* NetworkExtensionContentFilter.h */,
                                57303C4620105D2F00355965 /* AuthenticatorCoordinator.h in Headers */,
                                5760827220215A5500116678 /* AuthenticatorCoordinatorClient.h in Headers */,
                                57303BD220087A8300355965 /* AuthenticatorResponse.h in Headers */,
+                               57DCED9021487FF70016B847 /* AuthenticatorTransport.h in Headers */,
                                A501920E132EBF2E008BFE55 /* Autocapitalize.h in Headers */,
                                A5A7AA43132F0ECC00D3A3C2 /* AutocapitalizeTypes.h in Headers */,
                                7C1843FE1C8B7283002EB973 /* Autofill.h in Headers */,
                                57303C2F2009B7E100355965 /* JSAuthenticatorAssertionResponse.h in Headers */,
                                57303C222009AF0300355965 /* JSAuthenticatorAttestationResponse.h in Headers */,
                                57303BE120095D6100355965 /* JSAuthenticatorResponse.h in Headers */,
+                               57DCED98214882160016B847 /* JSAuthenticatorTransport.h in Headers */,
                                BC124F000C26447A009E2349 /* JSBarProp.h in Headers */,
                                57C7A69F1E57917800C67D71 /* JSBasicCredential.h in Headers */,
                                BC946348107A936600857193 /* JSBeforeLoadEvent.h in Headers */,
                                656D37320ADBA5DE00A4554D /* LoaderNSURLExtras.h in Headers */,
                                51E6821016387302003BBF3C /* LoaderStrategy.h in Headers */,
                                8A12E35D11FA33280025836A /* LoadTiming.h in Headers */,
-                               57212152205365650062AA1F /* LocalAuthenticationSoftLink.h in Headers */,
-                               574F55E0204F3ACE002948C6 /* LocalAuthenticator.h in Headers */,
                                06E81ED70AB5D5E900C87837 /* LocalCurrentGraphicsContext.h in Headers */,
                                445775E520472F73008DCE5D /* LocalDefaultSystemAppearance.h in Headers */,
                                F5973DE015CFB2030027F804 /* LocaleMac.h in Headers */,
index 265bccc..696c310 100644 (file)
@@ -34,7 +34,7 @@ struct ExceptionData {
     ExceptionCode code;
     String message;
 
-    ExceptionData isolatedCopy() const;
+    WEBCORE_EXPORT ExceptionData isolatedCopy() const;
 
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static bool decode(Decoder&, ExceptionData&);
diff --git a/Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.mm b/Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.mm
deleted file mode 100644 (file)
index 3e3f295..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-
-#import <LocalAuthentication/LocalAuthentication.h>
-#import <wtf/SoftLinking.h>
-
-SOFT_LINK_FRAMEWORK_FOR_SOURCE(WebCore, LocalAuthentication)
-
-SOFT_LINK_CLASS_FOR_SOURCE(WebCore, LocalAuthentication, LAContext)
index c9694d2..478d190 100644 (file)
 #include <string.h>
 #include <wtf/MainThread.h>
 
-using namespace WebCore;
-
 @interface WebCoreSharedBufferData : NSData
 {
-    RefPtr<const SharedBuffer::DataSegment> sharedBufferDataSegment;
+    RefPtr<const WebCore::SharedBuffer::DataSegment> sharedBufferDataSegment;
 }
 
-- (id)initWithSharedBufferDataSegment:(const SharedBuffer::DataSegment&)dataSegment;
+- (id)initWithSharedBufferDataSegment:(const WebCore::SharedBuffer::DataSegment&)dataSegment;
 @end
 
 @implementation WebCoreSharedBufferData
@@ -59,7 +57,7 @@ using namespace WebCore;
     [super dealloc];
 }
 
-- (id)initWithSharedBufferDataSegment:(const SharedBuffer::DataSegment&)dataSegment
+- (id)initWithSharedBufferDataSegment:(const WebCore::SharedBuffer::DataSegment&)dataSegment
 {
     self = [super init];
     
index ff39282..409f622 100644 (file)
@@ -45,7 +45,7 @@
 #import <wtf/NeverDestroyed.h>
 #import <wtf/SoftLinking.h>
 
-using namespace WebCore;
+namespace WebCore {
 
 VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement()
     : EventListener(EventListener::CPPEventListenerType)
@@ -274,4 +274,6 @@ void VideoFullscreenModelVideoElement::didExitPictureInPicture()
         client->didExitPictureInPicture();
 }
 
+} // namespace WebCore
+
 #endif
index 2af0342..d97ccb3 100644 (file)
 #import <pal/spi/cocoa/QuartzCoreSPI.h>
 #import <wtf/text/WTFString.h>
 
-using namespace WebCore;
+namespace WebCore {
 
 static NSString * const WKExplicitBeginTimeFlag = @"WKPlatformCAAnimationExplicitBeginTimeFlag";
 
-bool WebCore::hasExplicitBeginTime(CAAnimation *animation)
+bool hasExplicitBeginTime(CAAnimation *animation)
 {
     return [[animation valueForKey:WKExplicitBeginTimeFlag] boolValue];
 }
 
-void WebCore::setHasExplicitBeginTime(CAAnimation *animation, bool value)
+void setHasExplicitBeginTime(CAAnimation *animation, bool value)
 {
     [animation setValue:[NSNumber numberWithBool:value] forKey:WKExplicitBeginTimeFlag];
 }
     
-NSString* WebCore::toCAFillModeType(PlatformCAAnimation::FillModeType type)
+NSString* toCAFillModeType(PlatformCAAnimation::FillModeType type)
 {
     switch (type) {
     case PlatformCAAnimation::NoFillMode:
@@ -69,7 +69,7 @@ static PlatformCAAnimation::FillModeType fromCAFillModeType(NSString* string)
     return PlatformCAAnimation::Forwards;
 }
 
-NSString* WebCore::toCAValueFunctionType(PlatformCAAnimation::ValueFunctionType type)
+NSString* toCAValueFunctionType(PlatformCAAnimation::ValueFunctionType type)
 {
     switch (type) {
     case PlatformCAAnimation::NoValueFunction: return @"";
@@ -126,7 +126,7 @@ static PlatformCAAnimation::ValueFunctionType fromCAValueFunctionType(NSString*
     return PlatformCAAnimation::NoValueFunction;
 }
 
-CAMediaTimingFunction* WebCore::toCAMediaTimingFunction(const TimingFunction* timingFunction, bool reverse)
+CAMediaTimingFunction* toCAMediaTimingFunction(const TimingFunction* timingFunction, bool reverse)
 {
     ASSERT(timingFunction);
     if (is<CubicBezierTimingFunction>(timingFunction)) {
@@ -378,7 +378,7 @@ void PlatformCAAnimationCocoa::setFromValue(float value)
     [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSNumber numberWithDouble:value]];
 }
 
-void PlatformCAAnimationCocoa::setFromValue(const WebCore::TransformationMatrix& value)
+void PlatformCAAnimationCocoa::setFromValue(const TransformationMatrix& value)
 {
     if (!isBasicAnimation())
         return;
@@ -399,7 +399,7 @@ void PlatformCAAnimationCocoa::setFromValue(const FloatPoint3D& value)
     [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array];
 }
 
-void PlatformCAAnimationCocoa::setFromValue(const WebCore::Color& value)
+void PlatformCAAnimationCocoa::setFromValue(const Color& value)
 {
     if (!isBasicAnimation())
         return;
@@ -435,7 +435,7 @@ void PlatformCAAnimationCocoa::setToValue(float value)
     [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSNumber numberWithDouble:value]];
 }
 
-void PlatformCAAnimationCocoa::setToValue(const WebCore::TransformationMatrix& value)
+void PlatformCAAnimationCocoa::setToValue(const TransformationMatrix& value)
 {
     if (!isBasicAnimation())
         return;
@@ -456,7 +456,7 @@ void PlatformCAAnimationCocoa::setToValue(const FloatPoint3D& value)
     [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array];
 }
 
-void PlatformCAAnimationCocoa::setToValue(const WebCore::Color& value)
+void PlatformCAAnimationCocoa::setToValue(const Color& value)
 {
     if (!isBasicAnimation())
         return;
@@ -498,7 +498,7 @@ void PlatformCAAnimationCocoa::setValues(const Vector<float>& value)
     [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
 }
 
-void PlatformCAAnimationCocoa::setValues(const Vector<WebCore::TransformationMatrix>& value)
+void PlatformCAAnimationCocoa::setValues(const Vector<TransformationMatrix>& value)
 {
     if (animationType() != Keyframe)
         return;
@@ -529,7 +529,7 @@ void PlatformCAAnimationCocoa::setValues(const Vector<FloatPoint3D>& value)
     [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array];
 }
 
-void PlatformCAAnimationCocoa::setValues(const Vector<WebCore::Color>& value)
+void PlatformCAAnimationCocoa::setValues(const Vector<Color>& value)
 {
     if (animationType() != Keyframe)
         return;
@@ -602,3 +602,5 @@ void PlatformCAAnimationCocoa::copyTimingFunctionsFrom(const PlatformCAAnimation
     CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(downcast<PlatformCAAnimationCocoa>(value).m_animation.get());
     [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:[other timingFunctions]];
 }
+
+} // namespace WebCore
index 3ab39df..2aac155 100644 (file)
@@ -33,7 +33,7 @@
 #import <pal/spi/cocoa/QuartzCoreSPI.h>
 #import <wtf/BlockObjCExceptions.h>
 
-using namespace WebCore;
+namespace WebCore {
 
 // FIXME: Should share these values with CSSFilter::build() (https://bugs.webkit.org/show_bug.cgi?id=76008).
 static const double sepiaFullConstants[3][3] = {
@@ -692,3 +692,5 @@ const char* PlatformCAFilters::animatedFilterPropertyName(FilterOperation::Opera
     }
 #endif
 }
+
+} // namespace WebCore
index fb2aa1e..ce02e09 100644 (file)
@@ -66,7 +66,7 @@ SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
 
 SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVPlayerLayer)
 
-using namespace WebCore;
+namespace WebCore {
 
 Ref<PlatformCALayer> PlatformCALayerCocoa::create(LayerType layerType, PlatformCALayerClient* owner)
 {
@@ -97,13 +97,15 @@ static MonotonicTime mediaTimeToCurrentTime(CFTimeInterval t)
     return MonotonicTime::now() + Seconds(t - CACurrentMediaTime());
 }
 
+} // namespace WebCore
+
 // Delegate for animationDidStart callback
 @interface WebAnimationDelegate : NSObject {
-    PlatformCALayer* m_owner;
+    WebCore::PlatformCALayer* m_owner;
 }
 
 - (void)animationDidStart:(CAAnimation *)anim;
-- (void)setOwner:(PlatformCALayer*)owner;
+- (void)setOwner:(WebCore::PlatformCALayer*)owner;
 
 @end
 
@@ -111,6 +113,7 @@ static MonotonicTime mediaTimeToCurrentTime(CFTimeInterval t)
 
 - (void)animationDidStart:(CAAnimation *)animation
 {
+    using namespace WebCore;
 #if PLATFORM(IOS)
     WebThreadLock();
 #endif
@@ -141,6 +144,7 @@ static MonotonicTime mediaTimeToCurrentTime(CFTimeInterval t)
 
 - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
 {
+    using namespace WebCore;
 #if PLATFORM(IOS)
     WebThreadLock();
 #endif
@@ -163,13 +167,15 @@ static MonotonicTime mediaTimeToCurrentTime(CFTimeInterval t)
         m_owner->animationEnded(animationKey);
 }
 
-- (void)setOwner:(PlatformCALayer*)owner
+- (void)setOwner:(WebCore::PlatformCALayer*)owner
 {
     m_owner = owner;
 }
 
 @end
 
+namespace WebCore {
+
 void PlatformCALayerCocoa::setOwner(PlatformCALayerClient* owner)
 {
     PlatformCALayer::setOwner(owner);
@@ -1262,3 +1268,5 @@ AVPlayerLayer *PlatformCALayerCocoa::avPlayerLayer() const
     ASSERT_NOT_REACHED();
     return nil;
 }
+
+} // namespace WebCore
index 4b47b77..bc0eb4b 100644 (file)
@@ -29,8 +29,6 @@
 #import "GraphicsContextCG.h"
 #import <QuartzCore/QuartzCore.h>
 
-using namespace WebCore;
-
 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=146250
 // These should provide the system recipes for the layers
 // with the appropriate tinting, blending and blurring.
@@ -51,7 +49,7 @@ using namespace WebCore;
 #endif
 
     CGFloat components[4] = { 0.8, 0.8, 0.8, 0.8 };
-    [super setBackgroundColor:adoptCF(CGColorCreate(sRGBColorSpaceRef(), components)).get()];
+    [super setBackgroundColor:adoptCF(CGColorCreate(WebCore::sRGBColorSpaceRef(), components)).get()];
 
     return self;
 }
@@ -77,7 +75,7 @@ using namespace WebCore;
 #endif
 
     CGFloat components[4] = { 0.2, 0.2, 0.2, 0.8 };
-    [super setBackgroundColor:adoptCF(CGColorCreate(sRGBColorSpaceRef(), components)).get()];
+    [super setBackgroundColor:adoptCF(CGColorCreate(WebCore::sRGBColorSpaceRef(), components)).get()];
 
     return self;
 }
index 10d9b5e..c191f39 100644 (file)
@@ -30,8 +30,6 @@
 #import "TileController.h"
 #import <wtf/MainThread.h>
 
-using namespace WebCore;
-
 @implementation WebTiledBackingLayer
 
 - (id)init
@@ -61,7 +59,7 @@ using namespace WebCore;
     return nil;
 }
 
-- (TileController*)createTileController:(PlatformCALayer*)rootLayer
+- (WebCore::TileController*)createTileController:(WebCore::PlatformCALayer*)rootLayer
 {
     ASSERT(!_tileController);
     _tileController = std::make_unique<WebCore::TileController>(rootLayer);
@@ -100,7 +98,7 @@ using namespace WebCore;
 
 - (void)setNeedsDisplayInRect:(CGRect)rect
 {
-    _tileController->setNeedsDisplayInRect(enclosingIntRect(rect));
+    _tileController->setNeedsDisplayInRect(WebCore::enclosingIntRect(rect));
 }
 
 - (void)setDrawsAsynchronously:(BOOL)acceleratesDrawing
@@ -157,7 +155,7 @@ using namespace WebCore;
 
 - (void)setBorderColor:(CGColorRef)borderColor
 {
-    _tileController->setTileDebugBorderColor(Color(borderColor));
+    _tileController->setTileDebugBorderColor(WebCore::Color(borderColor));
 }
 
 - (void)setBorderWidth:(CGFloat)borderWidth
index 69b3094..ac1f9d0 100644 (file)
@@ -555,10 +555,11 @@ Internals::Internals(Document& document)
 #endif
 
 #if ENABLE(WEB_AUTHN)
+    // FIXME(189283)
     if (document.page()) {
         auto mockAuthenticatorCoordinator = std::make_unique<MockAuthenticatorCoordinator>();
         m_mockAuthenticatorCoordinator = makeWeakPtr(mockAuthenticatorCoordinator.get());
-        document.page()->authenticatorCoordinator().setClient(WTFMove(mockAuthenticatorCoordinator));
+//        document.page()->authenticatorCoordinator().setClient(WTFMove(mockAuthenticatorCoordinator));
     }
 #endif
 }
index d2e7ce3..c60bde2 100644 (file)
@@ -51,6 +51,8 @@ set(WebKit_INCLUDE_DIRECTORIES
     "${WEBKIT_DIR}/UIProcess/RemoteLayerTree"
     "${WEBKIT_DIR}/UIProcess/Storage"
     "${WEBKIT_DIR}/UIProcess/UserContent"
+    "${WEBKIT_DIR}/UIProcess/WebAuthentication"
+    "${WEBKIT_DIR}/UIProcess/WebAuthentication/Mock"
     "${WEBKIT_DIR}/UIProcess/WebStorage"
     "${WEBKIT_DIR}/UIProcess/WebsiteData"
     "${WEBKIT_DIR}/WebProcess"
index 3167913..69c8356 100644 (file)
@@ -1,3 +1,159 @@
+2018-09-25  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Make AuthenticatorManager
+        https://bugs.webkit.org/show_bug.cgi?id=189279
+        <rdar://problem/44116792>
+
+        Reviewed by Chris Dumez.
+
+        This patch introduces AuthenticatorManager which is the central of WebAuthentication that 1) handles
+        web requests, 2) discovers authenticators, 3) manages authetnicators and 4) in the future interacts with UI.
+        The lifetime of the AuthenticatorManager is managed by WebsiteDataStore such that it is almost a singleton
+        per UI Process.
+
+        1) Requests come from WebAuthenticatorCoordinatorProxy and then cached in AuthenticatorManager which will
+        then distribute requests whenever a new authenticator is discovered.
+
+        2) An ABC AuthenticatorTransportService is provided as an interface for AuthenticatorManager to invoke
+        startDiscovery. Actual work will be done in corresponding derived classes, say, LocalService. LocalService
+        is the one that discover attached platform authenticators, for example, TouchID or FaceID.
+
+        Eache service is unique per AuthetnicatorManager, which means we will have at most 4 services, Local, USB,
+        NFC, and BLE. The latter three will be implemented soon. Also, AuthenticatorManager serves as an observer to
+        *Service, so the latter can inform the former whenever an authenticator is added or removed.
+
+        When a new authenticator is discovered, the corresponding service will create an Authetnicator object that
+        binds to the physical authenticator device through a *Connection object. There is no ABC for connection for
+        now as I forsee every *Connection will be quite different. The *Connection object is the one that send/receive
+        messages from the physicla device. So far, a LocalConnection is provided even though normally local authenticators
+        are attached. This class is provided solely for separating UI and network traffic from LocalAuthenticator's
+        request handling process. So we can override them in a mock test environment. I will talk about this in the
+        next section.
+
+        3) An ABC Authenticator is provided as an interface for AuthenticatorManager to distribute requests on. Requests
+        will then be handled by the derived classes, say, LocalAuthenticator. Each authenticator object is a FSM that
+        works asynchronously.
+
+        For LocalAuthenticator, it has 4 states for MakeCredential: Init => RequestReceived => UserConsented => Attested => End,
+        and 3 states for GetAssertion: Init => RequestReceived => UserConsented => End. In the transit from RequestReceived to
+        UserConsented, it will invoke LocalConnection to talk to LocalAuthentication.framework that prompt users for TouchID
+        or FaceID. And then the transit from UserConsented => Attested, it will invoke LocalConnection to talk to
+        DeviceIdentity.framework that does Apple attestation. Most of the work are from the original LocalAuthenticator
+        implementation, and this patch converts it to a FSM and simplify the callback and threading model.
+
+        When a respond is ready, each authenticator will notify their observer which is the AuthenticatorManager.
+        AuthenticatorManager will only reply to Web Process whenever there is a valid respond or a terminating error. Otherwise,
+        the request will time out. I will explore the time out mechanism in a more detailed manner in Bug 189642.
+
+        The above is a briefing of the AuthetnicatorManager architecture in functional. The asynchronous model is explained here:
+        1) Since most discovery and request handling processes are asynchronous, I enforced them to be executed asyncrhonous in
+        the interface of the ABC.
+        2) There is no dedicated secondary threads here. However, underlying framework might decide to perform works on a dedicated
+        thread and then execute the provided callback. Whenever such situation happens, the policy here is to wrap the actual callback
+        into a callback that will post the actual callback back to the main thread and pass the wrapping callback to the APIs. Hence,
+        weak pointers in the actual callback are guaranteed to work.
+        3) Callbacks are used only if it is one way, and they are CompletionHandlers.
+        4) Potential multi ways asynchronous operations are encapsulated in regarding Observer interfaces.
+
+        Finally, let me explain how the mock test works:
+        1) Mock testing is done in WebKitTestRunner instead of Internals because a considerable large portion of work is in UIProcess
+        instead of WebProcess, says, the AuthenticatorManager.
+        2) The basic idea is to override functionality of *Connection classes and then make them thin such that we can get the best
+        possible coverage in auto tests.
+        3) In order to enable layout tests to configure the Mock*Connection classes, a MockWebAuthenticationConfiguration struct is
+        provided. A corresponding JS dictionary will be created by each test and passed from the TestRunner to the connection object.
+        4) To bridge the above tunnel, a MockAuthenticatorManager is constructed. It is instrumented to return every error.
+        5) Also, Mock*Service classes are made to mock the discovery process as well.
+        6) Noted, every mock overrided methods are made thin.
+
+        * CMakeLists.txt:
+        * Configurations/WebKit.xcconfig:
+        * Platform/spi/Cocoa/DeviceIdentitySPI.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        * SourcesCocoa.txt:
+        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
+        (WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):
+        * UIProcess/API/C/WKWebsiteDataStoreRef.h:
+        * UIProcess/WebAuthentication/Authenticator.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        (WebKit::Authenticator::handleRequest):
+        (WebKit::Authenticator::receiveRespond const):
+        * UIProcess/WebAuthentication/Authenticator.h: Renamed from Source/WebCore/Modules/webauthn/cocoa/LocalAuthenticator.h.
+        (WebKit::Authenticator::setObserver):
+        (WebKit::Authenticator::observer const):
+        (WebKit::Authenticator::requestData const):
+        * UIProcess/WebAuthentication/AuthenticatorManager.cpp: Added.
+        (WebKit::AuthenticatorManagerInternal::collectTransports):
+        (WebKit::AuthenticatorManager::makeCredential):
+        (WebKit::AuthenticatorManager::getAssertion):
+        (WebKit::AuthenticatorManager::clearState):
+        (WebKit::AuthenticatorManager::authenticatorAdded):
+        (WebKit::AuthenticatorManager::respondReceived):
+        (WebKit::AuthenticatorManager::createService const):
+        (WebKit::AuthenticatorManager::respondReceivedInternal):
+        (WebKit::AuthenticatorManager::startDiscovery):
+        * UIProcess/WebAuthentication/AuthenticatorManager.h: Added.
+        (WebKit::AuthenticatorManager::pendingCompletionHandler):
+        * UIProcess/WebAuthentication/AuthenticatorTransportService.cpp: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        (WebKit::AuthenticatorTransportService::create):
+        (WebKit::AuthenticatorTransportService::createMock):
+        (WebKit::AuthenticatorTransportService::AuthenticatorTransportService):
+        (WebKit::AuthenticatorTransportService::startDiscovery const):
+        * UIProcess/WebAuthentication/AuthenticatorTransportService.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        (WebKit::AuthenticatorTransportService::observer const):
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm: Added.
+        (WebKit::LocalAuthenticatorInternal::buildAuthData):
+        (WebKit::LocalAuthenticatorInternal::transportsContain):
+        (WebKit::LocalAuthenticatorInternal::produceHashSet):
+        (WebKit::LocalAuthenticatorInternal::toVector):
+        (WebKit::LocalAuthenticator::LocalAuthenticator):
+        (WebKit::LocalAuthenticator::makeCredential):
+        (WebKit::LocalAuthenticator::continueMakeCredentialAfterUserConsented):
+        (WebKit::LocalAuthenticator::continueMakeCredentialAfterAttested):
+        (WebKit::LocalAuthenticator::getAssertion):
+        (WebKit::LocalAuthenticator::continueGetAssertionAfterUserConsented):
+        * UIProcess/WebAuthentication/Cocoa/LocalConnection.h: Copied from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        * UIProcess/WebAuthentication/Cocoa/LocalConnection.mm: Added.
+        (WebKit::LocalConnection::getUserConsent const):
+        (WebKit::LocalConnection::getAttestation const):
+        * UIProcess/WebAuthentication/Cocoa/LocalService.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/Cocoa/LocalService.mm: Renamed from Source/WebCore/PAL/pal/spi/cocoa/DeviceIdentitySPI.h.
+        (WebKit::LocalService::LocalService):
+        (WebKit::LocalService::isAvailable):
+        (WebKit::LocalService::startDiscoveryInternal const):
+        (WebKit::LocalService::platformStartDiscovery const):
+        (WebKit::LocalService::createLocalConnection const):
+        * UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        (WebKit::MockAuthenticatorManager::MockAuthenticatorManager):
+        (WebKit::MockAuthenticatorManager::createService const):
+        (WebKit::MockAuthenticatorManager::respondReceivedInternal):
+        * UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/Mock/MockLocalConnection.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/Mock/MockLocalConnection.mm: Added.
+        (WebKit::MockLocalConnection::MockLocalConnection):
+        (WebKit::MockLocalConnection::getUserConsent const):
+        (WebKit::MockLocalConnection::getAttestation const):
+        * UIProcess/WebAuthentication/Mock/MockLocalService.cpp: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        (WebKit::MockLocalService::MockLocalService):
+        (WebKit::MockLocalService::platformStartDiscovery const):
+        (WebKit::MockLocalService::createLocalConnection const):
+        * UIProcess/WebAuthentication/Mock/MockLocalService.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h: Copied from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/WebAuthenticationRequestData.h: Renamed from Source/WebCore/platform/cocoa/LocalAuthenticationSoftLink.h.
+        * UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp:
+        (WebKit::WebAuthenticatorCoordinatorProxy::WebAuthenticatorCoordinatorProxy):
+        (WebKit::WebAuthenticatorCoordinatorProxy::makeCredential):
+        (WebKit::WebAuthenticatorCoordinatorProxy::getAssertion):
+        (WebKit::WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailable):
+        (WebKit::WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailableReply): Deleted.
+        * UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::WebsiteDataStore):
+        (WebKit::WebsiteDataStore::setMockWebAuthenticationConfiguration):
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+        (WebKit::WebsiteDataStore::authenticatorManager):
+        * WebKit.xcodeproj/project.pbxproj:
+
 2018-09-25  Chris Dumez  <cdumez@apple.com>
 
         Revert some of the changes in r236471
index fcaac38..10c6b26 100644 (file)
@@ -62,6 +62,9 @@ WK_CORE_PREDICTION_LDFLAGS_YES = $(WK_MACOS_WEAK_FRAMEWORK) CorePrediction;
 WK_CORE_SERVICES_LDFLAGS = $(WK_CORE_SERVICES_LDFLAGS_$(WK_PLATFORM_NAME));
 WK_CORE_SERVICES_LDFLAGS_macosx = -framework CoreServices;
 
+WK_DEVICE_IDENTITY_LDFLAGS = $(WK_DEVICE_IDENTITY_LDFLAGS_$(WK_HAVE_DEVICE_IDENTITY));
+WK_DEVICE_IDENTITY_LDFLAGS_YES = -framework DeviceIdentity;
+
 WK_GRAPHICS_SERVICES_LDFLAGS = $(WK_GRAPHICS_SERVICES_LDFLAGS_$(WK_COCOA_TOUCH));
 WK_GRAPHICS_SERVICES_LDFLAGS_cocoatouch = -framework GraphicsServices;
 
@@ -118,7 +121,7 @@ WK_UIKIT_LDFLAGS_cocoatouch = -framework UIKit;
 WK_URL_FORMATTING_LDFLAGS = $(WK_URL_FORMATTING_LDFLAGS_$(WK_HAVE_URL_FORMATTING));
 WK_URL_FORMATTING_LDFLAGS_YES = -framework URLFormatting;
 
-FRAMEWORK_AND_LIBRARY_LDFLAGS = -lobjc -framework CFNetwork -framework CoreAudio -framework CoreFoundation -framework CoreGraphics -framework CoreText -framework Foundation -framework ImageIO -framework IOKit -framework WebKitLegacy -lnetwork $(WK_ACCESSIBILITY_LDFLAGS) $(WK_APPKIT_LDFLAGS) $(WK_ASSERTION_SERVICES_LDFLAGS) $(WK_CARBON_LDFLAGS) $(WK_CORE_PDF_LDFLAGS) $(WK_CORE_PREDICTION_LDFLAGS) $(WK_CORE_SERVICES_LDFLAGS) $(WK_GRAPHICS_SERVICES_LDFLAGS) $(WK_IOSURFACE_LDFLAGS) $(WK_LIBSANDBOX_LDFLAGS) $(WK_LIBWEBRTC_LDFLAGS) $(WK_MOBILE_CORE_SERVICES_LDFLAGS) $(WK_MOBILE_GESTALT_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_PDFKIT_LDFLAGS) $(WK_PROXIMITY_NETWORKING_LDFLAGS) $(WK_SAFE_BROWSING_LDFLAGS) $(WK_UIKIT_LDFLAGS) $(WK_URL_FORMATTING_LDFLAGS);
+FRAMEWORK_AND_LIBRARY_LDFLAGS = -lobjc -framework CFNetwork -framework CoreAudio -framework CoreFoundation -framework CoreGraphics -framework CoreText -framework Foundation -framework ImageIO -framework IOKit -framework WebKitLegacy -lnetwork $(WK_ACCESSIBILITY_LDFLAGS) $(WK_APPKIT_LDFLAGS) $(WK_ASSERTION_SERVICES_LDFLAGS) $(WK_CARBON_LDFLAGS) $(WK_CORE_PDF_LDFLAGS) $(WK_CORE_PREDICTION_LDFLAGS) $(WK_CORE_SERVICES_LDFLAGS) $(WK_DEVICE_IDENTITY_LDFLAGS) $(WK_GRAPHICS_SERVICES_LDFLAGS) $(WK_IOSURFACE_LDFLAGS) $(WK_LIBSANDBOX_LDFLAGS) $(WK_LIBWEBRTC_LDFLAGS) $(WK_MOBILE_CORE_SERVICES_LDFLAGS) $(WK_MOBILE_GESTALT_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_PDFKIT_LDFLAGS) $(WK_PROXIMITY_NETWORKING_LDFLAGS) $(WK_SAFE_BROWSING_LDFLAGS) $(WK_UIKIT_LDFLAGS) $(WK_URL_FORMATTING_LDFLAGS);
 
 // Prevent C++ standard library basic_stringstream, operator new, delete and their related exception types from being exported as weak symbols.
 UNEXPORTED_SYMBOL_LDFLAGS = -Wl,-unexported_symbol -Wl,__ZTISt9bad_alloc -Wl,-unexported_symbol -Wl,__ZTISt9exception -Wl,-unexported_symbol -Wl,__ZTSSt9bad_alloc -Wl,-unexported_symbol -Wl,__ZTSSt9exception -Wl,-unexported_symbol -Wl,__ZdlPvS_ -Wl,-unexported_symbol -Wl,__ZnwmPv -Wl,-unexported_symbol -Wl,__Znwm -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEC2EOS4_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEC1EOS4_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEaSEDn -Wl,-unexported_symbol -Wl,__ZNKSt3__18functionIFvN7WebCore12PolicyActionEEEclES2_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEE4swapERS4_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEC1ERKS4_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEC2ERKS4_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEED1Ev -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEED2Ev -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvN7WebCore12PolicyActionEEEaSERKS4_ -Wl,-unexported_symbol -Wl,__ZTVNSt3__117bad_function_callE -Wl,-unexported_symbol -Wl,__ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_istreamIcS2_EE -Wl,-unexported_symbol -Wl,__ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_14basic_iostreamIcS2_EE -Wl,-unexported_symbol -Wl,__ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE16_NS_13basic_ostreamIcS2_EE -Wl,-unexported_symbol -Wl,__ZTTNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE -Wl,-unexported_symbol -Wl,__ZTVNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEEE -Wl,-unexported_symbol -Wl,__ZTVNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE -Wl,-unexported_symbol -Wl,__ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE8_NS_13basic_ostreamIcS2_EE;
@@ -155,6 +158,9 @@ WK_FRAMEWORK_HEADER_POSTPROCESSING_DISABLED[sdk=iphone*12.0*] = YES;
 WK_RELOCATABLE_FRAMEWORK_LDFLAGS = $(WK_RELOCATABLE_FRAMEWORK_LDFLAGS_$(WK_RELOCATABLE_FRAMEWORKS));
 WK_RELOCATABLE_FRAMEWORK_LDFLAGS_YES = -Wl,-not_for_dyld_shared_cache;
 
+WK_HAVE_DEVICE_IDENTITY = $(WK_HAVE_DEVICE_IDENTITY_$(PLATFORM_NAME));
+WK_HAVE_DEVICE_IDENTITY_iphoneos = YES;
+
 WK_HAVE_URL_FORMATTING = $(WK_HAVE_URL_FORMATTING_$(WK_PLATFORM_NAME));
 WK_HAVE_URL_FORMATTING_iphoneos = $(WK_HAVE_URL_FORMATTING$(WK_IOS_12));
 WK_HAVE_URL_FORMATTING_iosmac = $(WK_HAVE_URL_FORMATTING$(WK_IOS_12));
index dfb005d..b372680 100644 (file)
@@ -455,6 +455,17 @@ UIProcess/RemoteLayerTree/RemoteLayerTreeScrollingPerformanceData.mm
 UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp
 UIProcess/RemoteLayerTree/RemoteScrollingTree.cpp
 
+UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
+UIProcess/WebAuthentication/Cocoa/LocalConnection.mm
+UIProcess/WebAuthentication/Cocoa/LocalService.mm
+
+UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp
+UIProcess/WebAuthentication/Mock/MockLocalConnection.mm
+UIProcess/WebAuthentication/Mock/MockLocalService.cpp
+
+UIProcess/WebAuthentication/AuthenticatorManager.cpp
+UIProcess/WebAuthentication/AuthenticatorTransportService.cpp
+UIProcess/WebAuthentication/Authenticator.cpp
 UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp
 
 UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm
index 0ef2944..4a61c95 100644 (file)
 
 #include "APIArray.h"
 #include "APIWebsiteDataStore.h"
+#include "MockWebAuthenticationConfiguration.h"
 #include "WKAPICast.h"
+#include "WKDictionary.h"
+#include "WKNumber.h"
+#include "WKRetainPtr.h"
 #include "WKSecurityOriginRef.h"
 #include "WKString.h"
 #include "WebResourceLoadStatisticsStore.h"
@@ -566,3 +570,18 @@ void WKWebsiteDataStoreSetServiceWorkerRegistrationDirectory(WKWebsiteDataStoreR
 {
     WebKit::toImpl(dataStoreRef)->websiteDataStore().setServiceWorkerRegistrationDirectory(WebKit::toImpl(serviceWorkerRegistrationDirectory)->string());
 }
+
+
+void WKWebsiteDataStoreSetWebAuthenticationMockConfiguration(WKWebsiteDataStoreRef dataStoreRef, WKDictionaryRef configurationRef)
+{
+#if ENABLE(WEB_AUTHN)
+    auto localRef = static_cast<WKDictionaryRef>(WKDictionaryGetItemForKey(configurationRef, adoptWK(WKStringCreateWithUTF8CString("Local")).get()));
+
+    MockWebAuthenticationConfiguration configuration;
+    configuration.local.acceptAuthentication = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(localRef, adoptWK(WKStringCreateWithUTF8CString("AcceptAuthentication")).get())));
+    configuration.local.acceptAttestation = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(localRef, adoptWK(WKStringCreateWithUTF8CString("AcceptAttestation")).get())));
+    configuration.local.privateKeyBase64 = WebKit::toImpl(static_cast<WKStringRef>(WKDictionaryGetItemForKey(localRef, adoptWK(WKStringCreateWithUTF8CString("PrivateKeyBase64")).get())))->string();
+
+    WebKit::toImpl(dataStoreRef)->websiteDataStore().setMockWebAuthenticationConfiguration(WTFMove(configuration));
+#endif
+}
index d7d899e..ece8a35 100644 (file)
@@ -114,6 +114,8 @@ WK_EXPORT void WKWebsiteDataStoreGetFetchCacheSizeForOrigin(WKWebsiteDataStoreRe
 WK_EXPORT WKStringRef WKWebsiteDataStoreCopyServiceWorkerRegistrationDirectory(WKWebsiteDataStoreRef dataStoreRef);
 WK_EXPORT void WKWebsiteDataStoreSetServiceWorkerRegistrationDirectory(WKWebsiteDataStoreRef dataStoreRef, WKStringRef serviceWorkerRegistrationDirectory);
 
+WK_EXPORT void WKWebsiteDataStoreSetWebAuthenticationMockConfiguration(WKWebsiteDataStoreRef dataStoreRef, WKDictionaryRef configuration);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Authenticator.cpp b/Source/WebKit/UIProcess/WebAuthentication/Authenticator.cpp
new file mode 100644 (file)
index 0000000..1600bbf
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Authenticator.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+void Authenticator::handleRequest(const WebAuthenticationRequestData& data)
+{
+    m_pendingRequestData = data;
+    // Enforce asynchronous execution of makeCredential/getAssertion.
+    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
+        if (!weakThis)
+            return;
+        if (weakThis->m_pendingRequestData.isCreationRequest)
+            weakThis->makeCredential();
+        else
+            weakThis->getAssertion();
+    });
+}
+
+void Authenticator::receiveRespond(Respond&& respond) const
+{
+    ASSERT(RunLoop::isMain());
+    if (!m_observer)
+        return;
+    m_observer->respondReceived(WTFMove(respond));
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
 
 #if ENABLE(WEB_AUTHN)
 
+#include "WebAuthenticationRequestData.h"
+#include <WebCore/ExceptionData.h>
+#include <WebCore/PublicKeyCredentialData.h>
 #include <wtf/Forward.h>
-#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
 #include <wtf/WeakPtr.h>
 
-namespace WebCore {
+namespace WebKit {
 
-struct ExceptionData;
-struct PublicKeyCredentialCreationOptions;
-struct PublicKeyCredentialData;
-struct PublicKeyCredentialRequestOptions;
+class Authenticator : public RefCounted<Authenticator>, public CanMakeWeakPtr<Authenticator> {
+public:
+    using Respond = Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>;
 
-using Callback = Function<void(Variant<PublicKeyCredentialData, ExceptionData>&&)>;
+    class Observer : public CanMakeWeakPtr<Observer> {
+    public:
+        virtual ~Observer() = default;
+        virtual void respondReceived(Respond&&) = 0;
+    };
 
-typedef void (^CompletionBlock)(SecKeyRef _Nullable referenceKey, NSArray * _Nullable certificates, NSError * _Nullable error);
+    virtual ~Authenticator() = default;
 
-// FIXME(182769): LocalAuthenticator should belongs to WebKit. However, we need unit tests.
-class WEBCORE_EXPORT LocalAuthenticator : public CanMakeWeakPtr<LocalAuthenticator> {
-    WTF_MAKE_NONCOPYABLE(LocalAuthenticator);
-public:
-    LocalAuthenticator();
-    virtual ~LocalAuthenticator() = default;
+    void setObserver(Observer& observer) { m_observer = makeWeakPtr(observer); }
 
-    void makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions&, Callback&&);
-    void getAssertion(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions&, Callback&&);
-    bool isAvailable() const;
+    // This operation is guaranteed to execute asynchronously.
+    void handleRequest(const WebAuthenticationRequestData&);
 
 protected:
-    // Apple Attestation is moved into this virtual method such that it can be overrided by self attestation for testing.
-    virtual void issueClientCertificate(const String& rpId, const String& username, const Vector<uint8_t>& hash, CompletionBlock _Nonnull) const;
+    Authenticator() = default;
+
+    Observer* observer() const { return m_observer.get(); }
+    const WebAuthenticationRequestData& requestData() const { return m_pendingRequestData; }
+
+    void receiveRespond(Respond&&) const;
+
+private:
+    virtual void makeCredential() = 0;
+    virtual void getAssertion() = 0;
+
+    WeakPtr<Observer> m_observer;
+    WebAuthenticationRequestData m_pendingRequestData;
 };
 
-} // namespace WebCore
+} // namespace WebKit
 
 #endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
new file mode 100644 (file)
index 0000000..7355a32
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AuthenticatorManager.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include <WebCore/AuthenticatorTransport.h>
+#include <WebCore/PublicKeyCredentialCreationOptions.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+namespace AuthenticatorManagerInternal {
+
+const size_t maxTransportNumber = 1;
+
+// FIXME(188623, 188624, 188625): Support USB, NFC and BLE authenticators.
+static AuthenticatorManager::TransportSet collectTransports(const std::optional<PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria>& authenticatorSelection)
+{
+    AuthenticatorManager::TransportSet result;
+    if (!authenticatorSelection) {
+        auto addResult = result.add(AuthenticatorTransport::Internal);
+        ASSERT_UNUSED(addResult, addResult.isNewEntry);
+        return result;
+    }
+
+    if (authenticatorSelection.value().authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::Platform) {
+        auto addResult = result.add(AuthenticatorTransport::Internal);
+        ASSERT_UNUSED(addResult, addResult.isNewEntry);
+        return result;
+    }
+    if (authenticatorSelection.value().authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::CrossPlatform)
+        return result;
+
+    ASSERT_NOT_REACHED();
+    return result;
+}
+
+// FIXME(188623, 188624, 188625): Support USB, NFC and BLE authenticators.
+// The goal is to find a union of different transports from allowCredentials.
+// If it is not specified or any of its credentials doesn't specify its own. We should discover all.
+// This is a variant of Step. 18.*.4 from https://www.w3.org/TR/webauthn/#discover-from-external-source
+// as of 7 August 2018.
+static AuthenticatorManager::TransportSet collectTransports(const Vector<PublicKeyCredentialDescriptor>& allowCredentials)
+{
+    AuthenticatorManager::TransportSet result;
+    if (allowCredentials.isEmpty()) {
+        auto addResult = result.add(AuthenticatorTransport::Internal);
+        ASSERT_UNUSED(addResult, addResult.isNewEntry);
+        return result;
+    }
+
+    for (auto& allowCredential : allowCredentials) {
+        if (allowCredential.transports.isEmpty()) {
+            result.add(AuthenticatorTransport::Internal);
+            return result;
+        }
+        if (!result.contains(AuthenticatorTransport::Internal) && allowCredential.transports.contains(AuthenticatorTransport::Internal))
+            result.add(AuthenticatorTransport::Internal);
+        if (result.size() >= maxTransportNumber)
+            return result;
+    }
+
+    ASSERT(result.size() < maxTransportNumber);
+    return result;
+}
+
+} // namespace AuthenticatorManagerInternal
+
+void AuthenticatorManager::makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions& options, Callback&& callback)
+{
+    using namespace AuthenticatorManagerInternal;
+
+    if (m_pendingCompletionHandler) {
+        callback(ExceptionData { NotAllowedError, "A request is pending."_s });
+        return;
+    }
+
+    // 1. Save request for async operations.
+    m_pendingRequestData = { hash, true, options, { } };
+    m_pendingCompletionHandler = WTFMove(callback);
+
+    // 2. Get available transports and start discovering authenticators on them.
+    startDiscovery(collectTransports(options.authenticatorSelection));
+}
+
+void AuthenticatorManager::getAssertion(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions& options, Callback&& callback)
+{
+    using namespace AuthenticatorManagerInternal;
+
+    if (m_pendingCompletionHandler) {
+        callback(ExceptionData { NotAllowedError, "A request is pending."_s });
+        return;
+    }
+
+    // 1. Save request for async operations.
+    m_pendingRequestData = { hash, false, { }, options };
+    m_pendingCompletionHandler = WTFMove(callback);
+
+    // 2. Get available transports and start discovering authenticators on them.
+    ASSERT(m_services.isEmpty());
+    startDiscovery(collectTransports(options.allowCredentials));
+}
+
+void AuthenticatorManager::clearState()
+{
+    m_pendingRequestData = { };
+    ASSERT(!m_pendingCompletionHandler);
+    m_services.clear();
+    m_authenticators.clear();
+}
+
+void AuthenticatorManager::authenticatorAdded(Ref<Authenticator>&& authenticator)
+{
+    ASSERT(RunLoop::isMain());
+    authenticator->setObserver(*this);
+    authenticator->handleRequest(m_pendingRequestData);
+    auto addResult = m_authenticators.add(WTFMove(authenticator));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+}
+
+void AuthenticatorManager::respondReceived(Respond&& respond)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(m_pendingCompletionHandler);
+    // FIXME(189642)
+    if (WTF::holds_alternative<PublicKeyCredentialData>(respond)) {
+        m_pendingCompletionHandler(WTFMove(respond));
+        clearState();
+        return;
+    }
+    respondReceivedInternal(WTFMove(respond));
+}
+
+UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(WebCore::AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
+{
+    return AuthenticatorTransportService::create(transport, observer);
+}
+
+void AuthenticatorManager::respondReceivedInternal(Respond&&)
+{
+}
+
+void AuthenticatorManager::startDiscovery(const TransportSet& transports)
+{
+    using namespace AuthenticatorManagerInternal;
+
+    ASSERT(m_services.isEmpty() && transports.size() <= maxTransportNumber);
+    for (auto& transport : transports) {
+        auto service = createService(transport, *this);
+        service->startDiscovery();
+        m_services.append(WTFMove(service));
+    }
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h
new file mode 100644 (file)
index 0000000..503bc6b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "Authenticator.h"
+#include "AuthenticatorTransportService.h"
+#include "WebAuthenticationRequestData.h"
+#include <WebCore/ExceptionData.h>
+#include <WebCore/PublicKeyCredentialData.h>
+#include <wtf/CompletionHandler.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+
+class AuthenticatorManager : public AuthenticatorTransportService::Observer, public Authenticator::Observer {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(AuthenticatorManager);
+public:
+    using Respond = Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>;
+    using Callback = CompletionHandler<void(Respond&&)>;
+    using TransportSet = HashSet<WebCore::AuthenticatorTransport, WTF::IntHash<WebCore::AuthenticatorTransport>, WTF::StrongEnumHashTraits<WebCore::AuthenticatorTransport>>;
+
+    AuthenticatorManager() = default;
+    virtual ~AuthenticatorManager() = default;
+
+    void makeCredential(const Vector<uint8_t>& hash, const WebCore::PublicKeyCredentialCreationOptions&, Callback&&);
+    void getAssertion(const Vector<uint8_t>& hash, const WebCore::PublicKeyCredentialRequestOptions&, Callback&&);
+
+    virtual bool isMock() const { return false; }
+
+protected:
+    Callback& pendingCompletionHandler() { return m_pendingCompletionHandler; }
+    void clearState();
+
+private:
+    // AuthenticatorTransportService::Observer
+    void authenticatorAdded(Ref<Authenticator>&&) final;
+
+    // Authenticator::Observer
+    void respondReceived(Respond&&) final;
+
+    // Overriden by MockAuthenticatorManager.
+    virtual UniqueRef<AuthenticatorTransportService> createService(WebCore::AuthenticatorTransport, AuthenticatorTransportService::Observer&) const;
+    // Overriden to return every exception for tests to confirm.
+    virtual void respondReceivedInternal(Respond&&);
+
+    void startDiscovery(const TransportSet&);
+
+    // Request: We only allow one request per time.
+    WebAuthenticationRequestData m_pendingRequestData;
+    Callback m_pendingCompletionHandler;
+
+    Vector<UniqueRef<AuthenticatorTransportService>> m_services;
+    HashSet<Ref<Authenticator>> m_authenticators;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp
new file mode 100644 (file)
index 0000000..314d4a4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AuthenticatorTransportService.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "LocalService.h"
+#include "MockLocalService.h"
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+UniqueRef<AuthenticatorTransportService> AuthenticatorTransportService::create(WebCore::AuthenticatorTransport transport, Observer& observer)
+{
+    ASSERT(transport == WebCore::AuthenticatorTransport::Internal);
+    return makeUniqueRef<LocalService>(observer);
+}
+
+UniqueRef<AuthenticatorTransportService> AuthenticatorTransportService::createMock(WebCore::AuthenticatorTransport transport, Observer& observer, const MockWebAuthenticationConfiguration& configuration)
+{
+    ASSERT(transport == WebCore::AuthenticatorTransport::Internal);
+    return makeUniqueRef<MockLocalService>(observer, configuration);
+}
+
+AuthenticatorTransportService::AuthenticatorTransportService(Observer& observer)
+    : m_observer(makeWeakPtr(observer))
+{
+}
+
+void AuthenticatorTransportService::startDiscovery() const
+{
+    // Enforce asynchronous execution of makeCredential.
+    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
+        if (!weakThis)
+            return;
+        weakThis->startDiscoveryInternal();
+    });
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h
new file mode 100644 (file)
index 0000000..05d59b3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <WebCore/AuthenticatorTransport.h>
+#include <wtf/UniqueRef.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebKit {
+
+class Authenticator;
+
+struct MockWebAuthenticationConfiguration;
+
+class AuthenticatorTransportService : public CanMakeWeakPtr<AuthenticatorTransportService> {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(AuthenticatorTransportService);
+public:
+    class Observer : public CanMakeWeakPtr<Observer> {
+    public:
+        virtual ~Observer() = default;
+
+        virtual void authenticatorAdded(Ref<Authenticator>&&) = 0;
+    };
+
+    static UniqueRef<AuthenticatorTransportService> create(WebCore::AuthenticatorTransport, Observer&);
+    static UniqueRef<AuthenticatorTransportService> createMock(WebCore::AuthenticatorTransport, Observer&, const MockWebAuthenticationConfiguration&);
+
+    virtual ~AuthenticatorTransportService() = default;
+
+    // This operation is guaranteed to execute asynchronously.
+    void startDiscovery() const;
+
+protected:
+    explicit AuthenticatorTransportService(Observer&);
+
+    Observer* observer() const { return m_observer.get(); }
+
+private:
+    virtual void startDiscoveryInternal() const = 0;
+
+    WeakPtr<Observer> m_observer;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
@@ -25,9 +25,8 @@
 
 #pragma once
 
-#import <LocalAuthentication/LocalAuthentication.h>
 #import <wtf/SoftLinking.h>
 
-SOFT_LINK_FRAMEWORK_FOR_HEADER(WebCore, LocalAuthentication)
+SOFT_LINK_FRAMEWORK(LocalAuthentication);
 
-SOFT_LINK_CLASS_FOR_HEADER(WebCore, LocalAuthentication, LAContext)
+SOFT_LINK_CLASS(LocalAuthentication, LAContext);
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h
new file mode 100644 (file)
index 0000000..9468335
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "Authenticator.h"
+#include "LocalConnection.h"
+#include <wtf/UniqueRef.h>
+
+OBJC_CLASS LAContext;
+
+namespace WebKit {
+
+class LocalAuthenticator final : public Authenticator {
+public:
+    // Here is the FSM.
+    // MakeCredential: Init => RequestReceived => UserConsented => Attested => End
+    // GetAssertion: Init => RequestReceived => UserConsented => End
+    enum class State {
+        Init,
+        RequestReceived,
+        UserConsented,
+        Attested,
+    };
+
+    static Ref<LocalAuthenticator> create(UniqueRef<LocalConnection>&& connection)
+    {
+        return adoptRef(*new LocalAuthenticator(WTFMove(connection)));
+    }
+
+private:
+    explicit LocalAuthenticator(UniqueRef<LocalConnection>&&);
+
+    void makeCredential() final;
+    void continueMakeCredentialAfterUserConsented(LocalConnection::UserConsent);
+    void continueMakeCredentialAfterAttested(SecKeyRef, NSArray *certificates, NSError *);
+
+    void getAssertion() final;
+    void continueGetAssertionAfterUserConsented(LocalConnection::UserConsent, LAContext *, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& userhandle);
+
+    State m_state { State::Init };
+    UniqueRef<LocalConnection> m_connection;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
new file mode 100644 (file)
index 0000000..88d6046
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LocalAuthenticator.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#import <Security/SecItem.h>
+#import <WebCore/CBORWriter.h>
+#import <WebCore/COSEConstants.h>
+#import <WebCore/ExceptionData.h>
+#import <WebCore/PublicKeyCredentialCreationOptions.h>
+#import <WebCore/PublicKeyCredentialData.h>
+#import <WebCore/PublicKeyCredentialRequestOptions.h>
+#import <pal/crypto/CryptoDigest.h>
+#import <wtf/HashSet.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/Vector.h>
+#import <wtf/text/StringHash.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+namespace LocalAuthenticatorInternal {
+
+// See https://www.w3.org/TR/webauthn/#flags.
+const uint8_t makeCredentialFlags = 0b01000101; // UP, UV and AT are set.
+const uint8_t getAssertionFlags = 0b00000101; // UP and UV are set.
+// FIXME(rdar://problem/38320512): Define Apple AAGUID.
+const uint8_t AAGUID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 16 bytes
+// Credential ID is currently SHA-1 of the corresponding public key.
+// FIXME(183534): Assume little endian here.
+const union {
+    uint16_t integer;
+    uint8_t bytes[2];
+} credentialIdLength = {0x0014};
+const size_t ES256KeySizeInBytes = 32;
+const size_t authDataPrefixFixedSize = 37; // hash(32) + flags(1) + counter(4)
+
+#if PLATFORM(IOS)
+// https://www.w3.org/TR/webauthn/#sec-authenticator-data
+static Vector<uint8_t> buildAuthData(const String& rpId, const uint8_t flags, uint32_t counter, const Vector<uint8_t>& optionalAttestedCredentialData)
+{
+    Vector<uint8_t> authData;
+    authData.reserveInitialCapacity(authDataPrefixFixedSize + optionalAttestedCredentialData.size());
+
+    // RP ID hash
+    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
+    // FIXME(183534): Test IDN.
+    ASSERT(rpId.isAllASCII());
+    auto asciiRpId = rpId.ascii();
+    crypto->addBytes(asciiRpId.data(), asciiRpId.length());
+    authData = crypto->computeHash();
+
+    // FLAGS
+    authData.append(flags);
+
+    // COUNTER
+    // FIXME(183534): Assume little endian here.
+    union {
+        uint32_t integer;
+        uint8_t bytes[4];
+    } counterUnion;
+    counterUnion.integer = counter;
+    authData.append(counterUnion.bytes, sizeof(counterUnion.bytes));
+
+    // ATTESTED CRED. DATA
+    authData.appendVector(optionalAttestedCredentialData);
+
+    return authData;
+}
+
+static inline bool emptyTransportsOrContain(const Vector<AuthenticatorTransport>& transports, AuthenticatorTransport target)
+{
+    return transports.isEmpty() ? true : transports.contains(target);
+}
+
+static inline HashSet<String> produceHashSet(const Vector<PublicKeyCredentialDescriptor>& credentialDescriptors)
+{
+    HashSet<String> result;
+    for (auto& credentialDescriptor : credentialDescriptors) {
+        if (emptyTransportsOrContain(credentialDescriptor.transports, AuthenticatorTransport::Internal)
+            && credentialDescriptor.type == PublicKeyCredentialType::PublicKey
+            && credentialDescriptor.idVector.size() == credentialIdLength.integer)
+            result.add(String(reinterpret_cast<const char*>(credentialDescriptor.idVector.data()), credentialDescriptor.idVector.size()));
+    }
+    return result;
+}
+
+static inline Vector<uint8_t> toVector(NSData *data)
+{
+    Vector<uint8_t> result;
+    result.append(reinterpret_cast<const uint8_t*>(data.bytes), data.length);
+    return result;
+}
+#endif // !PLATFORM(IOS)
+
+} // LocalAuthenticatorInternal
+
+LocalAuthenticator::LocalAuthenticator(UniqueRef<LocalConnection>&& connection)
+    : m_connection(WTFMove(connection))
+{
+}
+
+void LocalAuthenticator::makeCredential()
+{
+    // FIXME(182772)
+    using namespace LocalAuthenticatorInternal;
+    ASSERT(m_state == State::Init);
+    m_state = State::RequestReceived;
+
+#if PLATFORM(IOS)
+    // The following implements https://www.w3.org/TR/webauthn/#op-make-cred as of 5 December 2017.
+    // Skip Step 4-5 as requireResidentKey and requireUserVerification are enforced.
+    // Skip Step 9 as extensions are not supported yet.
+    // Step 8 is implicitly captured by all UnknownError exception receiveResponds.
+    // Step 2.
+    bool canFullfillPubKeyCredParams = false;
+    for (auto& pubKeyCredParam : requestData().creationOptions.pubKeyCredParams) {
+        if (pubKeyCredParam.type == PublicKeyCredentialType::PublicKey && pubKeyCredParam.alg == COSE::ES256) {
+            canFullfillPubKeyCredParams = true;
+            break;
+        }
+    }
+    if (!canFullfillPubKeyCredParams) {
+        receiveRespond(ExceptionData { NotSupportedError, "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters."_s });
+        return;
+    }
+
+    // Step 3.
+    HashSet<String> excludeCredentialIds = produceHashSet(requestData().creationOptions.excludeCredentials);
+    if (!excludeCredentialIds.isEmpty()) {
+        // Search Keychain for the RP ID.
+        NSDictionary *query = @{
+            (id)kSecClass: (id)kSecClassKey,
+            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+            (id)kSecAttrLabel: requestData().creationOptions.rp.id,
+            (id)kSecReturnAttributes: @YES,
+            (id)kSecMatchLimit: (id)kSecMatchLimitAll,
+        };
+        CFTypeRef attributesArrayRef = nullptr;
+        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef);
+        if (status && status != errSecItemNotFound) {
+            LOG_ERROR("Couldn't query Keychain: %d", status);
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+        auto retainAttributesArray = adoptCF(attributesArrayRef);
+
+        for (NSDictionary *nsAttributes in (NSArray *)attributesArrayRef) {
+            NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel];
+            if (excludeCredentialIds.contains(String(reinterpret_cast<const char*>(nsCredentialId.bytes), nsCredentialId.length))) {
+                receiveRespond(ExceptionData { NotAllowedError, "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator."_s });
+                return;
+            }
+        }
+    }
+
+    // Step 6.
+    // FIXME(rdar://problem/35900593): Update to a formal UI.
+    // Get user consent.
+    auto callback = [weakThis = makeWeakPtr(*this)](LocalConnection::UserConsent consent) {
+        ASSERT(RunLoop::isMain());
+        if (!weakThis)
+            return;
+
+        weakThis->continueMakeCredentialAfterUserConsented(consent);
+    };
+    m_connection->getUserConsent(
+        String::format("Allow %s to create a public key credential for %s", requestData().creationOptions.rp.id.utf8().data(), requestData().creationOptions.user.name.utf8().data()),
+        WTFMove(callback));
+#endif // !PLATFORM(IOS)
+}
+
+void LocalAuthenticator::continueMakeCredentialAfterUserConsented(LocalConnection::UserConsent consent)
+{
+    // FIXME(182772)
+    ASSERT(m_state == State::RequestReceived);
+    m_state = State::UserConsented;
+
+#if PLATFORM(IOS)
+    if (consent == LocalConnection::UserConsent::No) {
+        receiveRespond(ExceptionData { NotAllowedError, "Couldn't get user consent."_s });
+        return;
+    }
+
+    // Step 7.5.
+    // Userhandle is stored in kSecAttrApplicationTag attribute.
+    // Failures after this point could block users' accounts forever. Should we follow the spec?
+    NSDictionary* deleteQuery = @{
+        (id)kSecClass: (id)kSecClassKey,
+        (id)kSecAttrLabel: requestData().creationOptions.rp.id,
+        (id)kSecAttrApplicationTag: [NSData dataWithBytes:requestData().creationOptions.user.idVector.data() length:requestData().creationOptions.user.idVector.size()],
+    };
+    OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
+    if (status && status != errSecItemNotFound) {
+        LOG_ERROR("Couldn't detele older credential: %d", status);
+        receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+        return;
+    }
+
+    // Step 7.1, 13. Apple Attestation
+    auto callback = [weakThis = makeWeakPtr(*this)](SecKeyRef _Nullable privateKey, NSArray * _Nullable certificates, NSError * _Nullable error) {
+        ASSERT(RunLoop::isMain());
+        if (!weakThis)
+            return;
+        weakThis->continueMakeCredentialAfterAttested(privateKey, certificates, error);
+    };
+    m_connection->getAttestation(requestData().creationOptions.rp.id, requestData().creationOptions.user.name, requestData().hash, WTFMove(callback));
+#endif // !PLATFORM(IOS)
+}
+
+void LocalAuthenticator::continueMakeCredentialAfterAttested(SecKeyRef privateKey, NSArray *certificates, NSError *error)
+{
+    // FIXME(182772)
+    using namespace LocalAuthenticatorInternal;
+
+    ASSERT(m_state == State::UserConsented);
+    m_state = State::Attested;
+
+#if PLATFORM(IOS)
+    if (error) {
+        LOG_ERROR("Couldn't attest: %@", error);
+        receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+        return;
+    }
+    // Attestation Certificate and Attestation Issuing CA
+    ASSERT(certificates && ([certificates count] == 2));
+
+    // Step 7.2-7.4.
+    // FIXME(183533): A single kSecClassKey item couldn't store all meta data. The following schema is a tentative solution
+    // to accommodate the most important meta data, i.e. RP ID, Credential ID, and userhandle.
+    // kSecAttrLabel: RP ID
+    // kSecAttrApplicationLabel: Credential ID (auto-gen by Keychain)
+    // kSecAttrApplicationTag: userhandle
+    // Noted, the current DeviceIdentity.Framework would only allow us to pass the kSecAttrLabel as the inital attribute
+    // for the Keychain item. Since that's the only clue we have to locate the unique item, we use the pattern username@rp.id
+    // as the initial value.
+    // Also noted, the vale of kSecAttrApplicationLabel is automatically generated by the Keychain, which is a SHA-1 hash of
+    // the public key. We borrow it directly for now to workaround the stated limitations.
+    // Update the Keychain item to the above schema.
+    // FIXME(183533): DeviceIdentity.Framework would insert certificates into Keychain as well. We should update those as well.
+    Vector<uint8_t> credentialId;
+    {
+        // -rk is added by DeviceIdentity.Framework.
+        String label = makeString(requestData().creationOptions.user.name, "@", requestData().creationOptions.rp.id, "-rk");
+        NSDictionary *credentialIdQuery = @{
+            (id)kSecClass: (id)kSecClassKey,
+            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+            (id)kSecAttrLabel: label,
+            (id)kSecReturnAttributes: @YES
+        };
+        CFTypeRef attributesRef = nullptr;
+        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)credentialIdQuery, &attributesRef);
+        if (status) {
+            LOG_ERROR("Couldn't get Credential ID: %d", status);
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+        auto retainAttributes = adoptCF(attributesRef);
+
+        NSDictionary *nsAttributes = (NSDictionary *)attributesRef;
+        credentialId = toVector(nsAttributes[(id)kSecAttrApplicationLabel]);
+
+        NSDictionary *updateQuery = @{
+            (id)kSecClass: (id)kSecClassKey,
+            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+            (id)kSecAttrApplicationLabel: nsAttributes[(id)kSecAttrApplicationLabel],
+        };
+        NSDictionary *updateParams = @{
+            (id)kSecAttrLabel: requestData().creationOptions.rp.id,
+            (id)kSecAttrApplicationTag: [NSData dataWithBytes:requestData().creationOptions.user.idVector.data() length:requestData().creationOptions.user.idVector.size()],
+        };
+        status = SecItemUpdate((__bridge CFDictionaryRef)updateQuery, (__bridge CFDictionaryRef)updateParams);
+        if (status) {
+            LOG_ERROR("Couldn't update the Keychain item: %d", status);
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+    }
+
+    // Step 10.
+    // FIXME(183533): store the counter.
+    uint32_t counter = 0;
+
+    // FIXME(183534): attestedCredentialData could throttle.
+    // Step 11. https://www.w3.org/TR/webauthn/#attested-credential-data
+    Vector<uint8_t> attestedCredentialData;
+    {
+        // aaguid
+        attestedCredentialData.append(AAGUID, sizeof(AAGUID));
+
+        // credentialIdLength
+        ASSERT(credentialId.size() == credentialIdLength.integer);
+        // FIXME(183534): Assume little endian here.
+        attestedCredentialData.append(credentialIdLength.bytes, sizeof(uint16_t));
+
+        // credentialId
+        attestedCredentialData.appendVector(credentialId);
+
+        // credentialPublicKey
+        RetainPtr<CFDataRef> publicKeyDataRef;
+        {
+            auto publicKey = adoptCF(SecKeyCopyPublicKey(privateKey));
+            CFErrorRef errorRef = nullptr;
+            publicKeyDataRef = adoptCF(SecKeyCopyExternalRepresentation(publicKey.get(), &errorRef));
+            auto retainError = adoptCF(errorRef);
+            if (errorRef) {
+                LOG_ERROR("Couldn't export the public key: %@", (NSError*)errorRef);
+                receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+                return;
+            }
+            ASSERT(((NSData *)publicKeyDataRef.get()).length == (1 + 2 * ES256KeySizeInBytes)); // 04 | X | Y
+        }
+
+        // COSE Encoding
+        // FIXME(183535): Improve CBOR encoder to work with bytes directly.
+        Vector<uint8_t> x(ES256KeySizeInBytes);
+        [(NSData *)publicKeyDataRef.get() getBytes: x.data() range:NSMakeRange(1, ES256KeySizeInBytes)];
+        Vector<uint8_t> y(ES256KeySizeInBytes);
+        [(NSData *)publicKeyDataRef.get() getBytes: y.data() range:NSMakeRange(1 + ES256KeySizeInBytes, ES256KeySizeInBytes)];
+        cbor::CBORValue::MapValue publicKeyMap;
+        publicKeyMap[cbor::CBORValue(COSE::kty)] = cbor::CBORValue(COSE::EC2);
+        publicKeyMap[cbor::CBORValue(COSE::alg)] = cbor::CBORValue(COSE::ES256);
+        publicKeyMap[cbor::CBORValue(COSE::crv)] = cbor::CBORValue(COSE::P_256);
+        publicKeyMap[cbor::CBORValue(COSE::x)] = cbor::CBORValue(WTFMove(x));
+        publicKeyMap[cbor::CBORValue(COSE::y)] = cbor::CBORValue(WTFMove(y));
+        auto cosePublicKey = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(publicKeyMap)));
+        if (!cosePublicKey) {
+            LOG_ERROR("Couldn't encode the public key into COSE binaries.");
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+        attestedCredentialData.appendVector(cosePublicKey.value());
+    }
+
+    // Step 12.
+    auto authData = buildAuthData(requestData().creationOptions.rp.id, makeCredentialFlags, counter, attestedCredentialData);
+
+    // Step 13. Apple Attestation Cont'
+    // Assemble the attestation object:
+    // https://www.w3.org/TR/webauthn/#attestation-object
+    cbor::CBORValue::MapValue attestationStatementMap;
+    {
+        Vector<uint8_t> signature;
+        {
+            CFErrorRef errorRef = nullptr;
+            // FIXME(183652): Reduce prompt for biometrics
+            auto signatureRef = adoptCF(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)[NSData dataWithBytes:authData.data() length:authData.size()], &errorRef));
+            auto retainError = adoptCF(errorRef);
+            if (errorRef) {
+                LOG_ERROR("Couldn't generate the signature: %@", (NSError*)errorRef);
+                receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+                return;
+            }
+            signature = toVector((NSData *)signatureRef.get());
+        }
+        attestationStatementMap[cbor::CBORValue("alg")] = cbor::CBORValue(COSE::ES256);
+        attestationStatementMap[cbor::CBORValue("sig")] = cbor::CBORValue(signature);
+        Vector<cbor::CBORValue> cborArray;
+        for (size_t i = 0; i < [certificates count]; i++)
+            cborArray.append(cbor::CBORValue(toVector((NSData *)adoptCF(SecCertificateCopyData((__bridge SecCertificateRef)certificates[i])).get())));
+        attestationStatementMap[cbor::CBORValue("x5c")] = cbor::CBORValue(WTFMove(cborArray));
+    }
+
+    cbor::CBORValue::MapValue attestationObjectMap;
+    attestationObjectMap[cbor::CBORValue("authData")] = cbor::CBORValue(authData);
+    attestationObjectMap[cbor::CBORValue("fmt")] = cbor::CBORValue("Apple");
+    attestationObjectMap[cbor::CBORValue("attStmt")] = cbor::CBORValue(WTFMove(attestationStatementMap));
+    auto attestationObject = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(attestationObjectMap)));
+    if (!attestationObject) {
+        LOG_ERROR("Couldn't encode the attestation object.");
+        receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+        return;
+    }
+
+    receiveRespond(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.value().data(), attestationObject.value().size()), nullptr, nullptr, nullptr });
+#endif // !PLATFORM(IOS)
+}
+
+void LocalAuthenticator::getAssertion()
+{
+    // FIXME(182772)
+    using namespace LocalAuthenticatorInternal;
+    ASSERT(m_state == State::Init);
+    m_state = State::RequestReceived;
+
+#if PLATFORM(IOS)
+    // The following implements https://www.w3.org/TR/webauthn/#op-get-assertion as of 5 December 2017.
+    // Skip Step 2 as requireUserVerification is enforced.
+    // Skip Step 8 as extensions are not supported yet.
+    // Step 12 is implicitly captured by all UnknownError exception callbacks.
+    // Step 3-5. Unlike the spec, if an allow list is provided and there is no intersection between existing ones and the allow list, we always return NotAllowedError.
+    HashSet<String> allowCredentialIds = produceHashSet(requestData().requestOptions.allowCredentials);
+    if (!requestData().requestOptions.allowCredentials.isEmpty() && allowCredentialIds.isEmpty()) {
+        receiveRespond(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });
+        return;
+    }
+
+    // Search Keychain for the RP ID.
+    NSDictionary *query = @{
+        (id)kSecClass: (id)kSecClassKey,
+        (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+        (id)kSecAttrLabel: requestData().requestOptions.rpId,
+        (id)kSecReturnAttributes: @YES,
+        (id)kSecMatchLimit: (id)kSecMatchLimitAll
+    };
+    CFTypeRef attributesArrayRef = nullptr;
+    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef);
+    if (status && status != errSecItemNotFound) {
+        LOG_ERROR("Couldn't query Keychain: %d", status);
+        receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+        return;
+    }
+    auto retainAttributesArray = adoptCF(attributesArrayRef);
+
+    NSArray *intersectedCredentialsAttributes = nil;
+    if (requestData().requestOptions.allowCredentials.isEmpty())
+        intersectedCredentialsAttributes = (NSArray *)attributesArrayRef;
+    else {
+        NSMutableArray *result = [NSMutableArray arrayWithCapacity:allowCredentialIds.size()];
+        for (NSDictionary *nsAttributes in (NSArray *)attributesArrayRef) {
+            NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel];
+            if (allowCredentialIds.contains(String(reinterpret_cast<const char*>(nsCredentialId.bytes), nsCredentialId.length)))
+                [result addObject:nsAttributes];
+        }
+        intersectedCredentialsAttributes = result;
+    }
+    if (!intersectedCredentialsAttributes.count) {
+        receiveRespond(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });
+        return;
+    }
+
+    // Step 6.
+    // FIXME(rdar://problem/35900534): We don't have an UI to prompt users for selecting intersectedCredentials, and therefore we always use the first one for now.
+    NSDictionary *selectedCredentialAttributes = intersectedCredentialsAttributes[0];
+
+    // Step 7. Get user consent.
+    // FIXME(rdar://problem/35900593): Update to a formal UI.
+    auto callback = [
+        weakThis = makeWeakPtr(*this),
+        credentialId = toVector(selectedCredentialAttributes[(id)kSecAttrApplicationLabel]),
+        userhandle = toVector(selectedCredentialAttributes[(id)kSecAttrApplicationTag])
+    ](LocalConnection::UserConsent consent, LAContext *context) {
+        ASSERT(RunLoop::isMain());
+        if (!weakThis)
+            return;
+
+        weakThis->continueGetAssertionAfterUserConsented(consent, context, credentialId, userhandle);
+    };
+    m_connection->getUserConsent(
+        String::format("Log into %s with %s.", requestData().requestOptions.rpId.utf8().data(), selectedCredentialAttributes[(id)kSecAttrApplicationTag]),
+        (__bridge SecAccessControlRef)selectedCredentialAttributes[(id)kSecAttrAccessControl],
+        WTFMove(callback));
+#endif // !PLATFORM(IOS)
+}
+
+void LocalAuthenticator::continueGetAssertionAfterUserConsented(LocalConnection::UserConsent consent, LAContext *context, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& userhandle)
+{
+    // FIXME(182772)
+    using namespace LocalAuthenticatorInternal;
+    ASSERT(m_state == State::RequestReceived);
+    m_state = State::UserConsented;
+
+#if PLATFORM(IOS)
+    if (consent == LocalConnection::UserConsent::No) {
+        receiveRespond(ExceptionData { NotAllowedError, "Couldn't get user consent."_s });
+        return;
+    }
+
+    // Step 9-10.
+    // FIXME(183533): Due to the stated Keychain limitations, we can't save the counter value.
+    // Therefore, it is always zero.
+    uint32_t counter = 0;
+    auto authData = buildAuthData(requestData().requestOptions.rpId, getAssertionFlags, counter, { });
+
+    // Step 11.
+    Vector<uint8_t> signature;
+    {
+        NSDictionary *query = @{
+            (id)kSecClass: (id)kSecClassKey,
+            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+            (id)kSecAttrApplicationLabel: [NSData dataWithBytes:credentialId.data() length:credentialId.size()],
+            (id)kSecUseAuthenticationContext: context,
+            (id)kSecReturnRef: @YES,
+        };
+        CFTypeRef privateKeyRef = nullptr;
+        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &privateKeyRef);
+        if (status) {
+            LOG_ERROR("Couldn't get the private key reference: %d", status);
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+        auto privateKey = adoptCF(privateKeyRef);
+
+        NSMutableData *dataToSign = [NSMutableData dataWithBytes:authData.data() length:authData.size()];
+        [dataToSign appendBytes:requestData().hash.data() length:requestData().hash.size()];
+
+        CFErrorRef errorRef = nullptr;
+        // FIXME: Converting CFTypeRef to SecKeyRef is quite subtle here.
+        auto signatureRef = adoptCF(SecKeyCreateSignature((__bridge SecKeyRef)((id)privateKeyRef), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, &errorRef));
+        auto retainError = adoptCF(errorRef);
+        if (errorRef) {
+            LOG_ERROR("Couldn't generate the signature: %@", (NSError*)errorRef);
+            receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s });
+            return;
+        }
+        signature = toVector((NSData *)signatureRef.get());
+    }
+
+    // Step 13.
+    receiveRespond(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), false, nullptr, nullptr, ArrayBuffer::create(authData.data(), authData.size()), ArrayBuffer::create(signature.data(), signature.size()), ArrayBuffer::create(userhandle.data(), userhandle.size()) });
+#endif // !PLATFORM(IOS)
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h
new file mode 100644 (file)
index 0000000..cefdd1f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <wtf/CompletionHandler.h>
+
+OBJC_CLASS LAContext;
+
+namespace WebKit {
+
+// Local authenticators normally doesn't need to establish connections
+// between the platform and themselves as they are attached.
+// However, such abstraction is still provided to isolate operations
+// that are not allowed in auto test environment such that some mocking
+// mechnism can override them.
+class LocalConnection {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(LocalConnection);
+public:
+    enum class UserConsent {
+        No,
+        Yes
+    };
+
+    using AttestationCallback = CompletionHandler<void(SecKeyRef, NSArray *, NSError *)>;
+    using UserConsentCallback = CompletionHandler<void(UserConsent)>;
+    using UserConsentContextCallback = CompletionHandler<void(UserConsent, LAContext *)>;
+
+    LocalConnection() = default;
+    virtual ~LocalConnection() = default;
+
+    // Overrided by MockLocalConnection.
+    virtual void getUserConsent(const String& reason, UserConsentCallback&&) const;
+    virtual void getUserConsent(const String& reason, SecAccessControlRef, UserConsentContextCallback&&) const;
+    virtual void getAttestation(const String& rpId, const String& username, const Vector<uint8_t>& hash, AttestationCallback&&) const;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm
new file mode 100644 (file)
index 0000000..0483e29
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "LocalConnection.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#import "DeviceIdentitySPI.h"
+#import <LocalAuthentication/LocalAuthentication.h>
+#import <WebCore/ExceptionData.h>
+#import <wtf/BlockPtr.h>
+
+#import "LocalAuthenticationSoftLink.h"
+
+namespace WebKit {
+
+void LocalConnection::getUserConsent(const String& reason, UserConsentCallback&& completionHandler) const
+{
+    // FIXME(182772)
+#if PLATFORM(IOS)
+    auto context = adoptNS([allocLAContextInstance() init]);
+    auto reply = BlockPtr<void(BOOL, NSError *)>::fromCallable([completionHandler = WTFMove(completionHandler)] (BOOL success, NSError *error) mutable {
+        ASSERT(!RunLoop::isMain());
+
+        UserConsent consent = UserConsent::Yes;
+        if (!success || error) {
+            LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
+            consent = UserConsent::No;
+        }
+        RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), consent]() mutable {
+            completionHandler(consent);
+        });
+    });
+    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:reply.get()];
+#endif
+}
+
+void LocalConnection::getUserConsent(const String& reason, SecAccessControlRef accessControl, UserConsentContextCallback&& completionHandler) const
+{
+    // FIXME(182772)
+#if PLATFORM(IOS)
+    auto context = adoptNS([allocLAContextInstance() init]);
+    auto reply = BlockPtr<void(BOOL, NSError *)>::fromCallable([context, completionHandler = WTFMove(completionHandler)] (BOOL success, NSError *error) mutable {
+        ASSERT(!RunLoop::isMain());
+
+        UserConsent consent = UserConsent::Yes;
+        if (!success || error) {
+            LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
+            consent = UserConsent::No;
+        }
+        RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), consent, context = WTFMove(context)]() mutable {
+            completionHandler(consent, context.get());
+        });
+    });
+    [context evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign localizedReason:reason reply:reply.get()];
+#endif
+}
+
+void LocalConnection::getAttestation(const String& rpId, const String& username, const Vector<uint8_t>& hash, AttestationCallback&& completionHandler) const
+{
+    // DeviceIdentity.Framework is not avaliable in iOS simulator.
+#if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
+    // Apple Attestation
+    ASSERT(hash.size() <= 32);
+
+    RetainPtr<SecAccessControlRef> accessControlRef;
+    {
+        CFErrorRef errorRef = nullptr;
+        accessControlRef = adoptCF(SecAccessControlCreateWithFlags(NULL, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence, &errorRef));
+        auto retainError = adoptCF(errorRef);
+        if (errorRef) {
+            LOG_ERROR("Couldn't create ACL: %@", (NSError *)errorRef);
+            completionHandler(NULL, NULL, [NSError errorWithDomain:@"com.apple.WebKit.WebAuthN" code:1 userInfo:nil]);
+            return;
+        }
+    }
+
+    String label = makeString(username, "@", rpId);
+    NSDictionary *options = @{
+        kMAOptionsBAAKeychainLabel: label,
+        // FIXME(rdar://problem/38489134): Need a formal name.
+        kMAOptionsBAAKeychainAccessGroup: @"com.apple.safari.WebAuthN.credentials",
+        kMAOptionsBAAIgnoreExistingKeychainItems: @(YES),
+        // FIXME(rdar://problem/38489134): Determine a proper lifespan.
+        kMAOptionsBAAValidity: @(1440), // Last one day.
+        kMAOptionsBAASCRTAttestation: @(NO),
+        kMAOptionsBAANonce: [NSData dataWithBytes:hash.data() length:hash.size()],
+        kMAOptionsBAAAccessControls: (id)accessControlRef.get(),
+        kMAOptionsBAAOIDSToInclude: @[kMAOptionsBAAOIDNonce]
+    };
+
+    // FIXME(183652): Reduce prompt for biometrics
+    DeviceIdentityIssueClientCertificateWithCompletion(dispatch_get_main_queue(), options, BlockPtr<void(SecKeyRef, NSArray *, NSError *)>::fromCallable(WTFMove(completionHandler)).get());
+#endif
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.h b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.h
new file mode 100644 (file)
index 0000000..70cd6fb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "AuthenticatorTransportService.h"
+
+namespace WebKit {
+
+class LocalConnection;
+
+class LocalService : public AuthenticatorTransportService {
+public:
+    explicit LocalService(Observer&);
+
+    static bool isAvailable();
+
+private:
+    void startDiscoveryInternal() const final;
+    // Overrided by MockLocalService.
+    virtual bool platformStartDiscovery() const;
+    virtual UniqueRef<LocalConnection> createLocalConnection() const;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.mm
new file mode 100644 (file)
index 0000000..2fa3b4e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "LocalService.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#import "LocalAuthenticator.h"
+#import "LocalConnection.h"
+
+#import "LocalAuthenticationSoftLink.h"
+
+namespace WebKit {
+
+LocalService::LocalService(Observer& observer)
+    : AuthenticatorTransportService(observer)
+{
+}
+
+bool LocalService::isAvailable()
+{
+// FIXME(182772)
+#if !PLATFORM(IOS)
+    return false;
+#else
+    auto context = adoptNS([allocLAContextInstance() init]);
+    NSError *error = nil;
+    if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
+        LOG_ERROR("Couldn't find local authenticators: %@", error);
+        return false;
+    }
+    return true;
+#endif
+}
+
+void LocalService::startDiscoveryInternal() const
+{
+    if (!platformStartDiscovery())
+        return;
+
+    if (observer())
+        observer()->authenticatorAdded(LocalAuthenticator::create(createLocalConnection()));
+}
+
+bool LocalService::platformStartDiscovery() const
+{
+    return LocalService::isAvailable();
+}
+
+UniqueRef<LocalConnection> LocalService::createLocalConnection() const
+{
+    return makeUniqueRef<LocalConnection>();
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp
new file mode 100644 (file)
index 0000000..7e269b8
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockAuthenticatorManager.h"
+
+#if ENABLE(WEB_AUTHN)
+
+namespace WebKit {
+
+MockAuthenticatorManager::MockAuthenticatorManager(MockWebAuthenticationConfiguration&& configuration)
+    : m_testConfiguration(WTFMove(configuration))
+{
+}
+
+UniqueRef<AuthenticatorTransportService> MockAuthenticatorManager::createService(WebCore::AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
+{
+    return AuthenticatorTransportService::createMock(transport, observer, m_testConfiguration);
+}
+
+void MockAuthenticatorManager::respondReceivedInternal(Respond&& respond)
+{
+    pendingCompletionHandler()(WTFMove(respond));
+    clearState();
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.h
new file mode 100644 (file)
index 0000000..85d8009
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "AuthenticatorManager.h"
+#include "MockWebAuthenticationConfiguration.h"
+
+namespace WebKit {
+
+class MockAuthenticatorManager final : public AuthenticatorManager {
+public:
+    explicit MockAuthenticatorManager(MockWebAuthenticationConfiguration&&);
+
+    bool isMock() const final { return true; }
+    void setTestConfiguration(MockWebAuthenticationConfiguration&& configuration) { m_testConfiguration = WTFMove(configuration); }
+
+private:
+    UniqueRef<AuthenticatorTransportService> createService(WebCore::AuthenticatorTransport, AuthenticatorTransportService::Observer&) const final;
+    void respondReceivedInternal(Respond&&) final;
+
+    MockWebAuthenticationConfiguration m_testConfiguration;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h
new file mode 100644 (file)
index 0000000..9524fbc
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "LocalConnection.h"
+#include "MockWebAuthenticationConfiguration.h"
+
+namespace WebKit {
+
+class MockLocalConnection final : public LocalConnection {
+public:
+    explicit MockLocalConnection(const MockWebAuthenticationConfiguration&);
+
+    void getUserConsent(const String& reason, UserConsentCallback&&) const final;
+    void getUserConsent(const String& reason, SecAccessControlRef, UserConsentContextCallback&&) const final;
+    void getAttestation(const String& rpId, const String& username, const Vector<uint8_t>& hash, AttestationCallback&&) const final;
+
+private:
+    MockWebAuthenticationConfiguration m_configuration;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm
new file mode 100644 (file)
index 0000000..627c91f
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "MockLocalConnection.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#import <WebCore/ExceptionData.h>
+#import <wtf/RunLoop.h>
+#import <wtf/text/WTFString.h>
+
+#import "LocalAuthenticationSoftLink.h"
+
+namespace WebKit {
+
+namespace MockLocalConnectionInternal {
+const char* const testAttestationCertificateBase64 =
+    "MIIB6jCCAZCgAwIBAgIGAWHAxcjvMAoGCCqGSM49BAMCMFMxJzAlBgNVBAMMHkJh"
+    "c2ljIEF0dGVzdGF0aW9uIFVzZXIgU3ViIENBMTETMBEGA1UECgwKQXBwbGUgSW5j"
+    "LjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0xODAyMjMwMzM3MjJaFw0xODAyMjQw"
+    "MzQ3MjJaMGoxIjAgBgNVBAMMGTAwMDA4MDEwLTAwMEE0OUEyMzBBMDIxM0ExGjAY"
+    "BgNVBAsMEUJBQSBDZXJ0aWZpY2F0aW9uMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMw"
+    "EQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvCje"
+    "Pzr6Sg76XMoHuGabPaG6zjpLFL8Zd8/74Hh5PcL2Zq+o+f7ENXX+7nEXXYt0S8Ux"
+    "5TIRw4hgbfxXQbWLEqM5MDcwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBPAw"
+    "FwYJKoZIhvdjZAgCBAowCKEGBAR0ZXN0MAoGCCqGSM49BAMCA0gAMEUCIAlK8A8I"
+    "k43TbvKuYGHZs1DTgpTwmKTBvIUw5bwgZuYnAiEAtuJjDLKbGNJAJFMi5deEBqno"
+    "pBTCqbfbDJccfyQpjnY=";
+const char* const testAttestationIssuingCACertificateBase64 =
+    "MIICIzCCAaigAwIBAgIIeNjhG9tnDGgwCgYIKoZIzj0EAwIwUzEnMCUGA1UEAwwe"
+    "QmFzaWMgQXR0ZXN0YXRpb24gVXNlciBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ"
+    "bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTE3MDQyMDAwNDIwMFoXDTMyMDMy"
+    "MjAwMDAwMFowUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBTdWIg"
+    "Q0ExMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkw"
+    "EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoSZ/1t9eBAEVp5a8PrXacmbGb8zNC1X3"
+    "StLI9YO6Y0CL7blHmSGmjGWTwD4Q+i0J2BY3+bPHTGRyA9jGB3MSbaNmMGQwEgYD"
+    "VR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSD5aMhnrB0w/lhkP2XTiMQdqSj"
+    "8jAdBgNVHQ4EFgQU5mWf1DYLTXUdQ9xmOH/uqeNSD80wDgYDVR0PAQH/BAQDAgEG"
+    "MAoGCCqGSM49BAMCA2kAMGYCMQC3M360LLtJS60Z9q3vVjJxMgMcFQ1roGTUcKqv"
+    "W+4hJ4CeJjySXTgq6IEHn/yWab4CMQCm5NnK6SOSK+AqWum9lL87W3E6AA1f2TvJ"
+    "/hgok/34jr93nhS87tOQNdxDS8zyiqw=";
+}
+
+MockLocalConnection::MockLocalConnection(const MockWebAuthenticationConfiguration& configuration)
+    : m_configuration(configuration)
+{
+}
+
+void MockLocalConnection::getUserConsent(const String&, UserConsentCallback&& callback) const
+{
+    // Mock async operations.
+    RunLoop::main().dispatch([configuration = m_configuration, callback = WTFMove(callback)]() mutable {
+        if (!configuration.local.acceptAuthentication) {
+            callback(UserConsent::No);
+            return;
+        }
+        callback(UserConsent::Yes);
+    });
+}
+
+void MockLocalConnection::getUserConsent(const String&, SecAccessControlRef, UserConsentContextCallback&& callback) const
+{
+    // Mock async operations.
+    RunLoop::main().dispatch([configuration = m_configuration, callback = WTFMove(callback)]() mutable {
+        if (!configuration.local.acceptAuthentication) {
+            callback(UserConsent::No, nil);
+            return;
+        }
+        callback(UserConsent::Yes, adoptNS([allocLAContextInstance() init]).get());
+    });
+}
+
+void MockLocalConnection::getAttestation(const String& rpId, const String& username, const Vector<uint8_t>& hash, AttestationCallback&& callback) const
+{
+    using namespace MockLocalConnectionInternal;
+
+    // Mock async operations.
+    RunLoop::main().dispatch([configuration = m_configuration, rpId, username, hash, callback = WTFMove(callback)]() mutable {
+        if (!configuration.local.acceptAttestation) {
+            callback(NULL, NULL, [NSError errorWithDomain:NSOSStatusErrorDomain code:-1 userInfo:nil]);
+            return;
+        }
+
+        // Get Key and add it to Keychain.
+        NSDictionary* options = @{
+            (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
+            (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+            (id)kSecAttrKeySizeInBits: @256,
+        };
+        CFErrorRef errorRef = nullptr;
+        auto key = adoptCF(SecKeyCreateWithData(
+            (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:configuration.local.privateKeyBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
+            (__bridge CFDictionaryRef)options,
+            &errorRef
+        ));
+        ASSERT(!errorRef);
+
+        // Mock what DeviceIdentity would do.
+        String label = makeString(username, "@", rpId, "-rk");
+        NSDictionary* addQuery = @{
+            (id)kSecValueRef: (id)key.get(),
+            (id)kSecClass: (id)kSecClassKey,
+            (id)kSecAttrLabel: (id)label,
+        };
+        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
+        ASSERT_UNUSED(status, !status);
+
+        // Construct dummy certificates. The content of certificates is not important. We need them to present to
+        // check the CBOR encoding procedure.
+        auto attestationCertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:[NSString stringWithCString:testAttestationCertificateBase64 encoding:NSASCIIStringEncoding] options:NSDataBase64DecodingIgnoreUnknownCharacters]).get()));
+        auto attestationIssuingCACertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:[NSString stringWithCString:testAttestationIssuingCACertificateBase64 encoding:NSASCIIStringEncoding] options:NSDataBase64DecodingIgnoreUnknownCharacters]).get()));
+
+        callback(key.get(), [NSArray arrayWithObjects: (__bridge id)attestationCertificate.get(), (__bridge id)attestationIssuingCACertificate.get(), nil], NULL);
+    });
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.cpp b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.cpp
new file mode 100644 (file)
index 0000000..f0e7999
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockLocalService.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#import "LocalAuthenticator.h"
+#import "MockLocalConnection.h"
+#import <wtf/RunLoop.h>
+
+namespace WebKit {
+
+MockLocalService::MockLocalService(Observer& observer, const MockWebAuthenticationConfiguration& configuration)
+    : LocalService(observer)
+    , m_configuration(configuration)
+{
+}
+
+bool MockLocalService::platformStartDiscovery() const
+{
+    // FIXME(189642): we should test false case.
+    return true;
+}
+
+UniqueRef<LocalConnection> MockLocalService::createLocalConnection() const
+{
+    return makeUniqueRef<MockLocalConnection>(m_configuration);
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalService.h
new file mode 100644 (file)
index 0000000..7eb8f21
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "LocalService.h"
+#include "MockWebAuthenticationConfiguration.h"
+
+namespace WebKit {
+
+struct MockWebAuthenticationConfiguration;
+
+class MockLocalService final : public LocalService {
+public:
+    MockLocalService(Observer&, const MockWebAuthenticationConfiguration&);
+
+private:
+    bool platformStartDiscovery() const final;
+    UniqueRef<LocalConnection> createLocalConnection() const final;
+
+    MockWebAuthenticationConfiguration m_configuration;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h
new file mode 100644 (file)
index 0000000..074fcac
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+namespace WebKit {
+
+struct MockWebAuthenticationConfiguration {
+    struct Local {
+        bool acceptAuthentication { false };
+        bool acceptAttestation { false };
+        String privateKeyBase64;
+    };
+
+    Local local;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h b/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h
new file mode 100644 (file)
index 0000000..48d891f
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <WebCore/PublicKeyCredentialCreationOptions.h>
+#include <WebCore/PublicKeyCredentialRequestOptions.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+
+struct WebAuthenticationRequestData {
+    Vector<uint8_t> hash;
+    // FIXME: Maybe we could make an ABC of Options and then use safe casting here.
+    bool isCreationRequest { true };
+    WebCore::PublicKeyCredentialCreationOptions creationOptions;
+    WebCore::PublicKeyCredentialRequestOptions requestOptions;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
index 1223948..1da5ec4 100644 (file)
 
 #if ENABLE(WEB_AUTHN)
 
+#include "AuthenticatorManager.h"
+#include "LocalService.h"
 #include "WebAuthenticatorCoordinatorMessages.h"
 #include "WebAuthenticatorCoordinatorProxyMessages.h"
 #include "WebPageProxy.h"
 #include "WebProcessProxy.h"
+#include "WebsiteDataStore.h"
 #include <WebCore/ExceptionData.h>
-#include <WebCore/LocalAuthenticator.h>
 #include <WebCore/PublicKeyCredentialData.h>
+#include <wtf/MainThread.h>
 
 namespace WebKit {
 
@@ -42,7 +45,6 @@ WebAuthenticatorCoordinatorProxy::WebAuthenticatorCoordinatorProxy(WebPageProxy&
     : m_webPageProxy(webPageProxy)
 {
     m_webPageProxy.process().addMessageReceiver(Messages::WebAuthenticatorCoordinatorProxy::messageReceiverName(), m_webPageProxy.pageID(), *this);
-    m_authenticator = std::make_unique<WebCore::LocalAuthenticator>();
 }
 
 WebAuthenticatorCoordinatorProxy::~WebAuthenticatorCoordinatorProxy()
@@ -52,13 +54,8 @@ WebAuthenticatorCoordinatorProxy::~WebAuthenticatorCoordinatorProxy()
 
 void WebAuthenticatorCoordinatorProxy::makeCredential(const Vector<uint8_t>& hash, const WebCore::PublicKeyCredentialCreationOptions& options)
 {
-    // FIXME(182767)
-    if (!m_authenticator) {
-        requestReply({ }, { WebCore::NotAllowedError, "No avaliable authenticators."_s });
-        return;
-    }
-    // FIXME(183534): Weak pointers doesn't work in another thread because of race condition.
     auto callback = [weakThis = makeWeakPtr(*this)] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
+        ASSERT(RunLoop::isMain());
         if (!weakThis)
             return;
 
@@ -68,16 +65,13 @@ void WebAuthenticatorCoordinatorProxy::makeCredential(const Vector<uint8_t>& has
             weakThis->requestReply({ }, exception);
         });
     };
-    m_authenticator->makeCredential(hash, options, WTFMove(callback));
+    m_webPageProxy.websiteDataStore().authenticatorManager().makeCredential(hash, options, WTFMove(callback));
 }
 
 void WebAuthenticatorCoordinatorProxy::getAssertion(const Vector<uint8_t>& hash, const WebCore::PublicKeyCredentialRequestOptions& options)
 {
-    // FIXME(182767)
-    if (!m_authenticator)
-        requestReply({ }, { WebCore::NotAllowedError, "No avaliable authenticators."_s });
-    // FIXME(183534): Weak pointers doesn't work in another thread because of race condition.
     auto callback = [weakThis = makeWeakPtr(*this)] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
+        ASSERT(RunLoop::isMain());
         if (!weakThis)
             return;
 
@@ -87,16 +81,12 @@ void WebAuthenticatorCoordinatorProxy::getAssertion(const Vector<uint8_t>& hash,
             weakThis->requestReply({ }, exception);
         });
     };
-    m_authenticator->getAssertion(hash, options, WTFMove(callback));
+    m_webPageProxy.websiteDataStore().authenticatorManager().getAssertion(hash, options, WTFMove(callback));
 }
 
 void WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailable(uint64_t messageId)
 {
-    if (!m_authenticator) {
-        isUserVerifyingPlatformAuthenticatorAvailableReply(messageId, false);
-        return;
-    }
-    isUserVerifyingPlatformAuthenticatorAvailableReply(messageId, m_authenticator->isAvailable());
+    m_webPageProxy.send(Messages::WebAuthenticatorCoordinator::IsUserVerifyingPlatformAuthenticatorAvailableReply(messageId, LocalService::isAvailable()));
 }
 
 void WebAuthenticatorCoordinatorProxy::requestReply(const WebCore::PublicKeyCredentialData& data, const WebCore::ExceptionData& exception)
@@ -104,11 +94,6 @@ void WebAuthenticatorCoordinatorProxy::requestReply(const WebCore::PublicKeyCred
     m_webPageProxy.send(Messages::WebAuthenticatorCoordinator::RequestReply(data, exception));
 }
 
-void WebAuthenticatorCoordinatorProxy::isUserVerifyingPlatformAuthenticatorAvailableReply(uint64_t messageId, bool result)
-{
-    m_webPageProxy.send(Messages::WebAuthenticatorCoordinator::IsUserVerifyingPlatformAuthenticatorAvailableReply(messageId, result));
-}
-
 } // namespace WebKit
 
 #endif // ENABLE(WEB_AUTHN)
index 0175aac..ba1aef5 100644 (file)
@@ -33,8 +33,6 @@
 #include <wtf/WeakPtr.h>
 
 namespace WebCore {
-class LocalAuthenticator;
-
 struct ExceptionData;
 struct PublicKeyCredentialCreationOptions;
 struct PublicKeyCredentialData;
@@ -62,10 +60,8 @@ private:
 
     // Senders.
     void requestReply(const WebCore::PublicKeyCredentialData&, const WebCore::ExceptionData&);
-    void isUserVerifyingPlatformAuthenticatorAvailableReply(uint64_t messageId, bool);
 
     WebPageProxy& m_webPageProxy;
-    std::unique_ptr<WebCore::LocalAuthenticator> m_authenticator;
 };
 
 } // namespace WebKit
index fa9aa95..2232a45 100644 (file)
@@ -29,6 +29,8 @@
 #include "APIProcessPoolConfiguration.h"
 #include "APIWebsiteDataRecord.h"
 #include "APIWebsiteDataStore.h"
+#include "AuthenticatorManager.h"
+#include "MockAuthenticatorManager.h"
 #include "NetworkProcessMessages.h"
 #include "StorageManager.h"
 #include "StorageProcessCreationParameters.h"
@@ -96,6 +98,9 @@ WebsiteDataStore::WebsiteDataStore(Configuration configuration, PAL::SessionID s
     , m_configuration(WTFMove(configuration))
     , m_storageManager(StorageManager::create(m_configuration.localStorageDirectory))
     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
+#if ENABLE(WEB_AUTHN)
+    , m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
+#endif
 {
     WTF::setProcessPrivileges(allPrivileges());
     maybeRegisterWithSessionIDMap();
@@ -108,6 +113,9 @@ WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
     : m_sessionID(sessionID)
     , m_configuration()
     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
+#if ENABLE(WEB_AUTHN)
+    , m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
+#endif
 {
     maybeRegisterWithSessionIDMap();
     platformInitialize();
@@ -1651,4 +1659,13 @@ void WebsiteDataStore::addSecKeyProxyStore(Ref<SecKeyProxyStore>&& store)
 }
 #endif
 
+#if ENABLE(WEB_AUTHN)
+void WebsiteDataStore::setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&& configuration)
+{
+    if (!m_authenticatorManager->isMock())
+        m_authenticatorManager = makeUniqueRef<MockAuthenticatorManager>(WTFMove(configuration));
+    static_cast<MockAuthenticatorManager*>(&m_authenticatorManager)->setTestConfiguration(WTFMove(configuration));
+}
+#endif
+
 }
index 5569c9c..2fde687 100644 (file)
@@ -37,6 +37,7 @@
 #include <wtf/OptionSet.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/UniqueRef.h>
 #include <wtf/WeakPtr.h>
 #include <wtf/WorkQueue.h>
 #include <wtf/text/WTFString.h>
@@ -51,6 +52,7 @@ class SecurityOrigin;
 
 namespace WebKit {
 
+class AuthenticatorManager;
 class SecKeyProxyStore;
 class StorageManager;
 class WebPageProxy;
@@ -58,6 +60,7 @@ class WebProcessPool;
 class WebResourceLoadStatisticsStore;
 enum class WebsiteDataFetchOption;
 enum class WebsiteDataType;
+struct MockWebAuthenticationConfiguration;
 struct StorageProcessCreationParameters;
 struct WebsiteDataRecord;
 struct WebsiteDataStoreParameters;
@@ -189,6 +192,11 @@ public:
     void addSecKeyProxyStore(Ref<SecKeyProxyStore>&&);
 #endif
 
+#if ENABLE(WEB_AUTHN)
+    AuthenticatorManager& authenticatorManager() { return m_authenticatorManager.get(); }
+    void setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&&);
+#endif
+
 private:
     explicit WebsiteDataStore(PAL::SessionID);
     explicit WebsiteDataStore(Configuration, PAL::SessionID);
@@ -247,6 +255,10 @@ private:
 #if HAVE(SEC_KEY_PROXY)
     Vector<Ref<SecKeyProxyStore>> m_secKeyProxyStores;
 #endif
+
+#if ENABLE(WEB_AUTHN)
+    UniqueRef<AuthenticatorManager> m_authenticatorManager;
+#endif
 };
 
 }
index d126507..e62ca6a 100644 (file)
                53BA47D11DC2EF5E004DF4AD /* NetworkDataTaskBlob.h in Headers */ = {isa = PBXBuildFile; fileRef = 539EB5471DC2EE40009D48CF /* NetworkDataTaskBlob.h */; };
                53DEA3661DDE423100E82648 /* json.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 53DEA3651DDE422E00E82648 /* json.hpp */; };
                570AB8F320AE3BD700B8BE87 /* SecKeyProxyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 570AB8F220AE3BD700B8BE87 /* SecKeyProxyStore.h */; };
+               578DC2982155A0020074E815 /* LocalAuthenticationSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 578DC2972155A0010074E815 /* LocalAuthenticationSoftLink.h */; };
                57B4B46020B504AC00D4AD79 /* ClientCertificateAuthenticationXPCConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B4B45E20B504AB00D4AD79 /* ClientCertificateAuthenticationXPCConstants.h */; };
                57DCED6E2142EE5E0016B847 /* WebAuthenticatorCoordinatorMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57DCED6B2142EAE20016B847 /* WebAuthenticatorCoordinatorMessageReceiver.cpp */; };
                57DCED6F2142EE630016B847 /* WebAuthenticatorCoordinatorMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED6A2142EAE20016B847 /* WebAuthenticatorCoordinatorMessages.h */; };
                57DCED702142EE680016B847 /* WebAuthenticatorCoordinatorProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57DCED6C2142EAF90016B847 /* WebAuthenticatorCoordinatorProxyMessageReceiver.cpp */; };
                57DCED712142EE6C0016B847 /* WebAuthenticatorCoordinatorProxyMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED6D2142EAFA0016B847 /* WebAuthenticatorCoordinatorProxyMessages.h */; };
+               57DCEDAB214C60090016B847 /* DeviceIdentitySPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDAA214B9B430016B847 /* DeviceIdentitySPI.h */; };
+               57DCEDAC214C60270016B847 /* LocalAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDA12149C1E20016B847 /* LocalAuthenticator.h */; };
+               57DCEDAD214C602C0016B847 /* LocalConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDA7214A568B0016B847 /* LocalConnection.h */; };
+               57DCEDAE214C60330016B847 /* LocalService.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED9A2148B0830016B847 /* LocalService.h */; };
+               57DCEDAF214C603B0016B847 /* AuthenticatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED842147363A0016B847 /* AuthenticatorManager.h */; };
+               57DCEDB0214C60420016B847 /* AuthenticatorTransportService.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED8A214853130016B847 /* AuthenticatorTransportService.h */; };
+               57DCEDB1214C60480016B847 /* Authenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCED8B21485BD70016B847 /* Authenticator.h */; };
+               57DCEDB2214C604C0016B847 /* WebAuthenticationRequestData.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDA62149F9DA0016B847 /* WebAuthenticationRequestData.h */; };
+               57DCEDB3214C60530016B847 /* WebAuthenticatorCoordinatorProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 57608295202BD8BA00116678 /* WebAuthenticatorCoordinatorProxy.h */; };
+               57DCEDBF214F0DCF0016B847 /* MockWebAuthenticationConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDBE214CA01B0016B847 /* MockWebAuthenticationConfiguration.h */; };
+               57DCEDC3214F114C0016B847 /* MockLocalService.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC1214F114C0016B847 /* MockLocalService.h */; };
+               57DCEDC7214F18300016B847 /* MockLocalConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC5214F18300016B847 /* MockLocalConnection.h */; };
+               57DCEDCB214F4E420016B847 /* MockAuthenticatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */; };
                5C0B17781E7C880E00E9123C /* NetworkSocketStreamMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */; };
                5C0B17791E7C882100E9123C /* WebSocketStreamMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B17761E7C879C00E9123C /* WebSocketStreamMessageReceiver.cpp */; };
                5C1426ED1C23F80900D41183 /* NetworkProcessCreationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1426E31C23F80500D41183 /* NetworkProcessCreationParameters.h */; };
                57608295202BD8BA00116678 /* WebAuthenticatorCoordinatorProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAuthenticatorCoordinatorProxy.h; sourceTree = "<group>"; };
                57608296202BD8BA00116678 /* WebAuthenticatorCoordinatorProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebAuthenticatorCoordinatorProxy.cpp; sourceTree = "<group>"; };
                57608299202BDAE200116678 /* WebAuthenticatorCoordinatorProxy.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebAuthenticatorCoordinatorProxy.messages.in; sourceTree = "<group>"; };
+               578DC2972155A0010074E815 /* LocalAuthenticationSoftLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalAuthenticationSoftLink.h; sourceTree = "<group>"; };
                57B4B45D20B504AB00D4AD79 /* AuthenticationManagerCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AuthenticationManagerCocoa.mm; path = Authentication/cocoa/AuthenticationManagerCocoa.mm; sourceTree = "<group>"; };
                57B4B45E20B504AB00D4AD79 /* ClientCertificateAuthenticationXPCConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClientCertificateAuthenticationXPCConstants.h; path = Authentication/cocoa/ClientCertificateAuthenticationXPCConstants.h; sourceTree = "<group>"; };
                57DCED6A2142EAE20016B847 /* WebAuthenticatorCoordinatorMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAuthenticatorCoordinatorMessages.h; sourceTree = "<group>"; };
                57DCED6B2142EAE20016B847 /* WebAuthenticatorCoordinatorMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebAuthenticatorCoordinatorMessageReceiver.cpp; sourceTree = "<group>"; };
                57DCED6C2142EAF90016B847 /* WebAuthenticatorCoordinatorProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebAuthenticatorCoordinatorProxyMessageReceiver.cpp; sourceTree = "<group>"; };
                57DCED6D2142EAFA0016B847 /* WebAuthenticatorCoordinatorProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAuthenticatorCoordinatorProxyMessages.h; sourceTree = "<group>"; };
+               57DCED842147363A0016B847 /* AuthenticatorManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuthenticatorManager.h; sourceTree = "<group>"; };
+               57DCED852147363A0016B847 /* AuthenticatorManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AuthenticatorManager.cpp; sourceTree = "<group>"; };
+               57DCED8A214853130016B847 /* AuthenticatorTransportService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuthenticatorTransportService.h; sourceTree = "<group>"; };
+               57DCED8B21485BD70016B847 /* Authenticator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Authenticator.h; sourceTree = "<group>"; };
+               57DCED9921489F4D0016B847 /* AuthenticatorTransportService.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AuthenticatorTransportService.cpp; sourceTree = "<group>"; };
+               57DCED9A2148B0830016B847 /* LocalService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalService.h; sourceTree = "<group>"; };
+               57DCEDA02148FA0F0016B847 /* LocalService.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalService.mm; sourceTree = "<group>"; };
+               57DCEDA12149C1E20016B847 /* LocalAuthenticator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalAuthenticator.h; sourceTree = "<group>"; };
+               57DCEDA32149DFF50016B847 /* LocalAuthenticator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalAuthenticator.mm; sourceTree = "<group>"; };
+               57DCEDA42149E64A0016B847 /* Authenticator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Authenticator.cpp; sourceTree = "<group>"; };
+               57DCEDA62149F9DA0016B847 /* WebAuthenticationRequestData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAuthenticationRequestData.h; sourceTree = "<group>"; };
+               57DCEDA7214A568B0016B847 /* LocalConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalConnection.h; sourceTree = "<group>"; };
+               57DCEDA8214A568B0016B847 /* LocalConnection.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalConnection.mm; sourceTree = "<group>"; };
+               57DCEDAA214B9B430016B847 /* DeviceIdentitySPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceIdentitySPI.h; sourceTree = "<group>"; };
+               57DCEDBE214CA01B0016B847 /* MockWebAuthenticationConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockWebAuthenticationConfiguration.h; sourceTree = "<group>"; };
+               57DCEDC1214F114C0016B847 /* MockLocalService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockLocalService.h; sourceTree = "<group>"; };
+               57DCEDC2214F114C0016B847 /* MockLocalService.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MockLocalService.cpp; sourceTree = "<group>"; };
+               57DCEDC5214F18300016B847 /* MockLocalConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockLocalConnection.h; sourceTree = "<group>"; };
+               57DCEDC6214F18300016B847 /* MockLocalConnection.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MockLocalConnection.mm; sourceTree = "<group>"; };
+               57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAuthenticatorManager.h; sourceTree = "<group>"; };
+               57DCEDCD214F51680016B847 /* MockAuthenticatorManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockAuthenticatorManager.cpp; sourceTree = "<group>"; };
                5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocketStreamMessageReceiver.cpp; sourceTree = "<group>"; };
                5C0B17751E7C879C00E9123C /* NetworkSocketStreamMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocketStreamMessages.h; sourceTree = "<group>"; };
                5C0B17761E7C879C00E9123C /* WebSocketStreamMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketStreamMessageReceiver.cpp; sourceTree = "<group>"; };
                                1A5705101BE410E500874AF1 /* BlockSPI.h */,
                                37C21CAD1E994C0C0029D5F9 /* CorePredictionSPI.h */,
                                A1FB68261F6E51C100C43F9F /* CrashReporterClientSPI.h */,
+                               57DCEDAA214B9B430016B847 /* DeviceIdentitySPI.h */,
                                3754D5441B3A29FD003A4C7F /* NSInvocationSPI.h */,
                                37B47E2C1D64DB76005F4EFF /* objcSPI.h */,
                                0E97D74C200E8FF300BF6643 /* SafeBrowsingSPI.h */,
                57608294202BD84900116678 /* WebAuthentication */ = {
                        isa = PBXGroup;
                        children = (
+                               57DCED9E2148F9D10016B847 /* Cocoa */,
+                               57DCEDBD214C9FA90016B847 /* Mock */,
+                               57DCEDA42149E64A0016B847 /* Authenticator.cpp */,
+                               57DCED8B21485BD70016B847 /* Authenticator.h */,
+                               57DCED852147363A0016B847 /* AuthenticatorManager.cpp */,
+                               57DCED842147363A0016B847 /* AuthenticatorManager.h */,
+                               57DCED9921489F4D0016B847 /* AuthenticatorTransportService.cpp */,
+                               57DCED8A214853130016B847 /* AuthenticatorTransportService.h */,
+                               57DCEDA62149F9DA0016B847 /* WebAuthenticationRequestData.h */,
                                57608296202BD8BA00116678 /* WebAuthenticatorCoordinatorProxy.cpp */,
                                57608295202BD8BA00116678 /* WebAuthenticatorCoordinatorProxy.h */,
                                57608299202BDAE200116678 /* WebAuthenticatorCoordinatorProxy.messages.in */,
                        name = cocoa;
                        sourceTree = "<group>";
                };
+               57DCED9E2148F9D10016B847 /* Cocoa */ = {
+                       isa = PBXGroup;
+                       children = (
+                               578DC2972155A0010074E815 /* LocalAuthenticationSoftLink.h */,
+                               57DCEDA12149C1E20016B847 /* LocalAuthenticator.h */,
+                               57DCEDA32149DFF50016B847 /* LocalAuthenticator.mm */,
+                               57DCEDA7214A568B0016B847 /* LocalConnection.h */,
+                               57DCEDA8214A568B0016B847 /* LocalConnection.mm */,
+                               57DCED9A2148B0830016B847 /* LocalService.h */,
+                               57DCEDA02148FA0F0016B847 /* LocalService.mm */,
+                       );
+                       path = Cocoa;
+                       sourceTree = "<group>";
+               };
+               57DCEDBD214C9FA90016B847 /* Mock */ = {
+                       isa = PBXGroup;
+                       children = (
+                               57DCEDCD214F51680016B847 /* MockAuthenticatorManager.cpp */,
+                               57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */,
+                               57DCEDC5214F18300016B847 /* MockLocalConnection.h */,
+                               57DCEDC6214F18300016B847 /* MockLocalConnection.mm */,
+                               57DCEDC2214F114C0016B847 /* MockLocalService.cpp */,
+                               57DCEDC1214F114C0016B847 /* MockLocalService.h */,
+                               57DCEDBE214CA01B0016B847 /* MockWebAuthenticationConfiguration.h */,
+                       );
+                       path = Mock;
+                       sourceTree = "<group>";
+               };
                5C1426F11C23F81700D41183 /* Downloads */ = {
                        isa = PBXGroup;
                        children = (
                                512F589912A8838800629530 /* AuthenticationDecisionListener.h in Headers */,
                                518E8EF916B2091C00E91429 /* AuthenticationManager.h in Headers */,
                                512F58A312A883AD00629530 /* AuthenticationManagerMessages.h in Headers */,
+                               57DCEDB1214C60480016B847 /* Authenticator.h in Headers */,
+                               57DCEDAF214C603B0016B847 /* AuthenticatorManager.h in Headers */,
+                               57DCEDB0214C60420016B847 /* AuthenticatorTransportService.h in Headers */,
                                7CD102DA1866770600ED429D /* AutoCorrectionCallback.h in Headers */,
                                9955A6EF1C79810800EB6A93 /* Automation.json in Headers */,
                                9955A6F51C7986E000EB6A93 /* AutomationBackendDispatchers.h in Headers */,
                                C55F91711C59676E0029E92D /* DataDetectionResult.h in Headers */,
                                1AC75380183BE50F0072CB15 /* DataReference.h in Headers */,
                                BC032DA610F437D10058C15A /* Decoder.h in Headers */,
+                               57DCEDAB214C60090016B847 /* DeviceIdentitySPI.h in Headers */,
                                83891B6C1A68C30B0030F386 /* DiagnosticLoggingClient.h in Headers */,
                                C18173612058424700DFDA65 /* DisplayLink.h in Headers */,
                                5C1427021C23F84C00D41183 /* Download.h in Headers */,
                                41DC459C1E3DBB2800B11F51 /* LibWebRTCSocketClient.h in Headers */,
                                413075B21DE85F580039EC69 /* LibWebRTCSocketFactory.h in Headers */,
                                2D1087611D2C573E00B85F82 /* LoadParameters.h in Headers */,
+                               578DC2982155A0020074E815 /* LocalAuthenticationSoftLink.h in Headers */,
+                               57DCEDAC214C60270016B847 /* LocalAuthenticator.h in Headers */,
+                               57DCEDAD214C602C0016B847 /* LocalConnection.h in Headers */,
+                               57DCEDAE214C60330016B847 /* LocalService.h in Headers */,
                                1A1D8BA21731A36300141DA4 /* LocalStorageDatabase.h in Headers */,
                                1A8C728D1738477C000A6554 /* LocalStorageDatabaseTracker.h in Headers */,
                                51A7F2F3125BF820008AEB1D /* Logging.h in Headers */,
                                1A3EED0F161A535400AEB4F5 /* MessageReceiverMap.h in Headers */,
                                1AAB037A185A7C6A00EDF501 /* MessageSender.h in Headers */,
                                A13B3DA2207F39DE0090C58D /* MobileWiFiSPI.h in Headers */,
+                               57DCEDCB214F4E420016B847 /* MockAuthenticatorManager.h in Headers */,
+                               57DCEDC7214F18300016B847 /* MockLocalConnection.h in Headers */,
+                               57DCEDC3214F114C0016B847 /* MockLocalService.h in Headers */,
+                               57DCEDBF214F0DCF0016B847 /* MockWebAuthenticationConfiguration.h in Headers */,
                                C0E3AA7C1209E83C00A49D01 /* Module.h in Headers */,
                                2D50366B1BCDE17900E20BB3 /* NativeWebGestureEvent.h in Headers */,
                                263172CF18B469490065B9C3 /* NativeWebTouchEvent.h in Headers */,
                                1AF4CEF018BC481800BC2D34 /* VisitedLinkTableController.h in Headers */,
                                1A8E7D3D18C15149005A702A /* VisitedLinkTableControllerMessages.h in Headers */,
                                CEDA12E3152CD1B300D9E08D /* WebAlternativeTextClient.h in Headers */,
+                               57DCEDB2214C604C0016B847 /* WebAuthenticationRequestData.h in Headers */,
                                57DCED6F2142EE630016B847 /* WebAuthenticatorCoordinatorMessages.h in Headers */,
+                               57DCEDB3214C60530016B847 /* WebAuthenticatorCoordinatorProxy.h in Headers */,
                                57DCED712142EE6C0016B847 /* WebAuthenticatorCoordinatorProxyMessages.h in Headers */,
                                9955A6EC1C7980C200EB6A93 /* WebAutomationSession.h in Headers */,
                                99C3AE2D1DADA6AD00AF5C16 /* WebAutomationSessionMacros.h in Headers */,
index f6765b7..35dc1ab 100644 (file)
@@ -1,3 +1,37 @@
+2018-09-25  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Make AuthenticatorManager
+        https://bugs.webkit.org/show_bug.cgi?id=189279
+        <rdar://problem/44116792>
+
+        Reviewed by Chris Dumez.
+
+        Besides the functionality to set the WebAuthenticationMockConfiguration. Three operations are
+        added to manipulate Keychain: addTestKeyToKeychain, cleanUpKeychain and keyExistedInKeychain.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/ios/LocalAuthenticator.mm: Removed.
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setWebAuthenticationMockConfiguration):
+        (WTR::TestRunner::addTestKeyToKeychain):
+        (WTR::TestRunner::cleanUpKeychain):
+        (WTR::TestRunner::isKeyExisted):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::addTestKeyToKeychain):
+        (WTR::TestController::cleanUpKeychain):
+        (WTR::TestController::isKeyExisted):
+        (WTR::TestController::setWebAuthenticationMockConfiguration):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+        * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+        (WTR::TestController::addTestKeyToKeychain):
+        (WTR::TestController::cleanUpKeychain):
+        (WTR::TestController::keyExistedInKeychain):
+
 2018-09-25  Sihui Liu  <sihui_liu@apple.com>
 
         Move Service Worker Management from Storage Process to Network Process
index b30d459..77f9be6 100644 (file)
@@ -41,7 +41,6 @@
                0F139E791A42457000F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
                0F2C20B81DCD545000542D9E /* Time.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C20B71DCD544800542D9E /* Time.cpp */; };
                0F30CB5C1FCE1796004B5323 /* ConcurrentPtrHashSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F30CB5B1FCE1792004B5323 /* ConcurrentPtrHashSet.cpp */; };
-               4909EE3A2D09480C88982D56 /* Markable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC79F168BE454E579E417B05 /* Markable.cpp */; };
                0F3B94A71A77267400DE3272 /* WKWebViewEvaluateJavaScript.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */; };
                0F4FFA9E1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F4FFA9D1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm */; };
                0F5651F71FCE4DDC00310FBC /* NoHistoryItemScrollToFragment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F5651F61FCE4DDB00310FBC /* NoHistoryItemScrollToFragment.mm */; };
                46C519E81D3563FD00DAA51A /* LocalStorageNullEntries.localstorage-shm in Copy Resources */ = {isa = PBXBuildFile; fileRef = 46C519E41D35629600DAA51A /* LocalStorageNullEntries.localstorage-shm */; };
                46E66A901F0D75590026D83C /* WKWebViewDiagnosticLogging.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46E66A8F1F0D75590026D83C /* WKWebViewDiagnosticLogging.mm */; };
                46E816F81E79E29C00375ADC /* RestoreStateAfterTermination.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46E816F71E79E29100375ADC /* RestoreStateAfterTermination.mm */; };
+               4909EE3A2D09480C88982D56 /* Markable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC79F168BE454E579E417B05 /* Markable.cpp */; };
                4BFDFFA71314776C0061F24B /* HitTestResultNodeHandle_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFDFFA61314776C0061F24B /* HitTestResultNodeHandle_Bundle.cpp */; };
                510477721D298DDD009747EB /* IDBDeleteRecovery.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5104776F1D298D85009747EB /* IDBDeleteRecovery.sqlite3 */; };
                510477731D298DDD009747EB /* IDBDeleteRecovery.sqlite3-shm in Copy Resources */ = {isa = PBXBuildFile; fileRef = 510477701D298D85009747EB /* IDBDeleteRecovery.sqlite3-shm */; };
                57303BC9200824D300355965 /* CBORValueTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BAC2006C56000355965 /* CBORValueTest.cpp */; };
                57303BCA20082C0100355965 /* CBORWriterTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BAB2006C55400355965 /* CBORWriterTest.cpp */; };
                57303BCB2008376500355965 /* CBORReaderTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BC220071E2200355965 /* CBORReaderTest.cpp */; };
-               574F55CF204D37C5002948C6 /* LocalAuthenticator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 574F55CE204D3763002948C6 /* LocalAuthenticator.mm */; };
                574F55D2204D47F0002948C6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; };
                57599E211F07191900A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */; };
                57599E271F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57599E241F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 */; };
                        dstPath = TestWebKitAPI.resources;
                        dstSubfolderSpec = 7;
                        files = (
-                               C944160021430E8900B1EDDA /* audio-with-controls.html in Copy Resources */,
                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
                                379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
                                1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
                                7C9ED98B17A19F4B00E4DC33 /* attributedStringStrikethrough.html in Copy Resources */,
                                37137E4B21124D01002BEEA4 /* AttrStyle.html in Copy Resources */,
                                CD9E292E1C90C33F000BB800 /* audio-only.html in Copy Resources */,
+                               C944160021430E8900B1EDDA /* audio-with-controls.html in Copy Resources */,
                                CD57779C211CE91F001B371E /* audio-with-web-audio.html in Copy Resources */,
                                76E182DF154767E600F1FADD /* auto-submitting-form.html in Copy Resources */,
                                F41AB99F1EF4696B0083FA08 /* autofocus-contenteditable.html in Copy Resources */,
                0F17BBD415AF6C4D007AB753 /* WebCoreStatisticsWithNoWebProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebCoreStatisticsWithNoWebProcess.cpp; sourceTree = "<group>"; };
                0F2C20B71DCD544800542D9E /* Time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Time.cpp; sourceTree = "<group>"; };
                0F30CB5B1FCE1792004B5323 /* ConcurrentPtrHashSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConcurrentPtrHashSet.cpp; sourceTree = "<group>"; };
-               EC79F168BE454E579E417B05 /* Markable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Markable.cpp; sourceTree = "<group>"; };
                0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewEvaluateJavaScript.mm; sourceTree = "<group>"; };
                0F4FFA9D1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SnapshotViaRenderInContext.mm; sourceTree = "<group>"; };
                0F4FFAA01ED3D0DE00F7111F /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
                57303BAC2006C56000355965 /* CBORValueTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBORValueTest.cpp; sourceTree = "<group>"; };
                57303BC220071E2200355965 /* CBORReaderTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBORReaderTest.cpp; sourceTree = "<group>"; };
                5735F0251F3A4EA6000EE801 /* TestWebKitAPI-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TestWebKitAPI-iOS.entitlements"; sourceTree = "<group>"; };
-               574F55CE204D3763002948C6 /* LocalAuthenticator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalAuthenticator.mm; sourceTree = "<group>"; };
                574F55D0204D471C002948C6 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
                57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBStructuredCloneBackwardCompatibility.mm; sourceTree = "<group>"; };
                57599E231F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityWrite.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = IndexedDBStructuredCloneBackwardCompatibilityWrite.html; sourceTree = "<group>"; };
                E4A757D3178AEA5B00B5D7A4 /* Deque.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Deque.cpp; sourceTree = "<group>"; };
                E4C9ABC71B3DB1710040A987 /* RunLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RunLoop.cpp; sourceTree = "<group>"; };
                E5036F77211BC22800BFDBE2 /* color-drop.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "color-drop.html"; sourceTree = "<group>"; };
+               EC79F168BE454E579E417B05 /* Markable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Markable.cpp; sourceTree = "<group>"; };
                ECA680CD1E68CC0900731D20 /* StringUtilities.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringUtilities.mm; sourceTree = "<group>"; };
                F3FC3EE213678B7300126A65 /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; };
                F407FE381F1D0DE60017CF25 /* enormous.svg */ = {isa = PBXFileReference; lastKnownFileType = text; path = enormous.svg; sourceTree = "<group>"; };
                                F4D4F3B71E4E36E400BB2767 /* DragAndDropTestsIOS.mm */,
                                F4BC0B132146C849002A0478 /* FocusPreservationTests.mm */,
                                F45E15722112CE2900307E82 /* KeyboardInputTestsIOS.mm */,
-                               574F55CE204D3763002948C6 /* LocalAuthenticator.mm */,
                                7560917719259C59009EF06E /* MemoryCacheAddImageToCacheIOS.mm */,
                                F464AF9120BB66EA007F9B18 /* RenderingProgressTests.mm */,
                                F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */,
                A16F66B81C40E9E100BD4D24 /* Resources */ = {
                        isa = PBXGroup;
                        children = (
-                               C94415FF21430B6700B1EDDA /* audio-with-controls.html */,
                                C25CCA0C1E5140E50026CB8A /* AllAhem.svg */,
                                F4A9202E1FEE34C800F59590 /* apple-data-url.html */,
                                F47D30EB1ED28619000482E1 /* apple.gif */,
                                5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */,
                                F4856CA21E6498A8009D7EE7 /* attachment-element.html */,
                                3760C4F221124BD000233ACC /* AttrStyle.html */,
+                               C94415FF21430B6700B1EDDA /* audio-with-controls.html */,
                                CD57779A211CE6B7001B371E /* audio-with-web-audio.html */,
                                F41AB9981EF4692C0083FA08 /* autofocus-contenteditable.html */,
                                93CFA8661CEB9DE1000565A8 /* autofocused-text-input.html */,
                                5C838F7F1DB04F900082858F /* LoadInvalidURLRequest.mm in Sources */,
                                7C83E0C01D0A652700FEBCF3 /* LoadInvalidURLRequest.mm in Sources */,
                                7CCE7F001A411AE600447C4C /* LoadPageOnCrash.cpp in Sources */,
-                               574F55CF204D37C5002948C6 /* LocalAuthenticator.mm in Sources */,
                                51E6A8941D2F1C0A00C004B6 /* LocalStorageClear.mm in Sources */,
                                CA38459620AE17A900990D3B /* LocalStorageDatabaseTracker.mm in Sources */,
                                46C519DA1D355AB200DAA51A /* LocalStorageNullEntries.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/ios/LocalAuthenticator.mm b/Tools/TestWebKitAPI/Tests/ios/LocalAuthenticator.mm
deleted file mode 100644 (file)
index cd63d73..0000000
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-
-#if ENABLE(WEB_AUTHN)
-
-#if PLATFORM(IOS)
-
-#import "InstanceMethodSwizzler.h"
-#import "PlatformUtilities.h"
-#import <LocalAuthentication/LocalAuthentication.h>
-#import <Security/SecItem.h>
-#import <WebCore/CBORReader.h>
-#import <WebCore/COSEConstants.h>
-#import <WebCore/ExceptionData.h>
-#import <WebCore/LocalAuthenticator.h>
-#import <WebCore/PublicKeyCredentialCreationOptions.h>
-#import <WebCore/PublicKeyCredentialData.h>
-#import <WebCore/PublicKeyCredentialRequestOptions.h>
-#import <wtf/BlockPtr.h>
-#import <wtf/text/Base64.h>
-#import <wtf/text/WTFString.h>
-
-namespace TestWebKitAPI {
-
-const String testAttestationCertificateBase64 = String() +
-    "MIIB6jCCAZCgAwIBAgIGAWHAxcjvMAoGCCqGSM49BAMCMFMxJzAlBgNVBAMMHkJh" +
-    "c2ljIEF0dGVzdGF0aW9uIFVzZXIgU3ViIENBMTETMBEGA1UECgwKQXBwbGUgSW5j" +
-    "LjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0xODAyMjMwMzM3MjJaFw0xODAyMjQw" +
-    "MzQ3MjJaMGoxIjAgBgNVBAMMGTAwMDA4MDEwLTAwMEE0OUEyMzBBMDIxM0ExGjAY" +
-    "BgNVBAsMEUJBQSBDZXJ0aWZpY2F0aW9uMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMw" +
-    "EQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvCje" +
-    "Pzr6Sg76XMoHuGabPaG6zjpLFL8Zd8/74Hh5PcL2Zq+o+f7ENXX+7nEXXYt0S8Ux" +
-    "5TIRw4hgbfxXQbWLEqM5MDcwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBPAw" +
-    "FwYJKoZIhvdjZAgCBAowCKEGBAR0ZXN0MAoGCCqGSM49BAMCA0gAMEUCIAlK8A8I" +
-    "k43TbvKuYGHZs1DTgpTwmKTBvIUw5bwgZuYnAiEAtuJjDLKbGNJAJFMi5deEBqno" +
-    "pBTCqbfbDJccfyQpjnY=";
-const String testAttestationIssuingCACertificateBase64 = String() +
-    "MIICIzCCAaigAwIBAgIIeNjhG9tnDGgwCgYIKoZIzj0EAwIwUzEnMCUGA1UEAwwe" +
-    "QmFzaWMgQXR0ZXN0YXRpb24gVXNlciBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ" +
-    "bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTE3MDQyMDAwNDIwMFoXDTMyMDMy" +
-    "MjAwMDAwMFowUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBTdWIg" +
-    "Q0ExMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkw" +
-    "EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoSZ/1t9eBAEVp5a8PrXacmbGb8zNC1X3" +
-    "StLI9YO6Y0CL7blHmSGmjGWTwD4Q+i0J2BY3+bPHTGRyA9jGB3MSbaNmMGQwEgYD" +
-    "VR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSD5aMhnrB0w/lhkP2XTiMQdqSj" +
-    "8jAdBgNVHQ4EFgQU5mWf1DYLTXUdQ9xmOH/uqeNSD80wDgYDVR0PAQH/BAQDAgEG" +
-    "MAoGCCqGSM49BAMCA2kAMGYCMQC3M360LLtJS60Z9q3vVjJxMgMcFQ1roGTUcKqv" +
-    "W+4hJ4CeJjySXTgq6IEHn/yWab4CMQCm5NnK6SOSK+AqWum9lL87W3E6AA1f2TvJ" +
-    "/hgok/34jr93nhS87tOQNdxDS8zyiqw=";
-const String testCredentialIdBase64 = "SMSXHngF7hEOsElA73C3RY+8bR4=";
-const String testES256PrivateKeyBase64 = String() +
-    "BDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749VBJPgqUIwfhWHJ91nb7U" +
-    "PH76c0+WFOzZKslPyyFse4goGIW2R7k9VHLPEZl5nfnBgEVFh5zev+/xpHQIvuq6" +
-    "RQ==";
-const String testRpId = "localhost";
-const String testUsername = "username";
-const uint8_t testUserhandle[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x9};
-
-RetainPtr<SecKeyRef> getTestKey()
-{
-    NSDictionary* options = @{
-        (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
-        (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-        (id)kSecAttrKeySizeInBits: @256,
-    };
-    CFErrorRef errorRef = nullptr;
-    auto key = adoptCF(SecKeyCreateWithData(
-        (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:testES256PrivateKeyBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
-        (__bridge CFDictionaryRef)options,
-        &errorRef
-    ));
-    EXPECT_FALSE(errorRef);
-
-    return key;
-}
-
-void addTestKeyToKeychain()
-{
-    auto key = getTestKey();
-    NSDictionary* addQuery = @{
-        (id)kSecValueRef: (id)key.get(),
-        (id)kSecClass: (id)kSecClassKey,
-        (id)kSecAttrLabel: testRpId,
-        (id)kSecAttrApplicationTag: [NSData dataWithBytes:testUserhandle length:sizeof(testUserhandle)],
-    };
-    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
-    EXPECT_FALSE(status);
-}
-
-void cleanUpKeychain()
-{
-    // Cleanup the keychain.
-    NSDictionary* deleteQuery = @{
-        (id)kSecClass: (id)kSecClassKey,
-        (id)kSecAttrLabel: testRpId,
-    };
-    SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
-}
-
-class LACantEvaluatePolicySwizzler {
-public:
-    LACantEvaluatePolicySwizzler()
-        : m_swizzler([LAContext class], @selector(canEvaluatePolicy:error:), reinterpret_cast<IMP>(cantEvaluatePolicy))
-    {
-    }
-private:
-    static BOOL cantEvaluatePolicy()
-    {
-        return NO;
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class LACanEvaluatePolicySwizzler {
-public:
-    LACanEvaluatePolicySwizzler()
-        : m_swizzler([LAContext class], @selector(canEvaluatePolicy:error:), reinterpret_cast<IMP>(canEvaluatePolicy))
-    {
-    }
-private:
-    static BOOL canEvaluatePolicy()
-    {
-        return YES;
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class LAEvaluatePolicyFailedSwizzler {
-public:
-    LAEvaluatePolicyFailedSwizzler()
-        : m_swizzler([LAContext class], @selector(evaluatePolicy:localizedReason:reply:), reinterpret_cast<IMP>(evaluatePolicyFailed))
-    {
-    }
-private:
-    static void evaluatePolicyFailed(id, SEL, LAPolicy, NSString *, void (^reply)(BOOL, NSError *))
-    {
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-            Util::sleep(1); // mimic user interaction delay
-            reply(NO, nil);
-        });
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class LAEvaluatePolicyPassedSwizzler {
-public:
-    LAEvaluatePolicyPassedSwizzler()
-        : m_swizzler([LAContext class], @selector(evaluatePolicy:localizedReason:reply:), reinterpret_cast<IMP>(evaluatePolicyPassed))
-    {
-    }
-private:
-    static void evaluatePolicyPassed(id, SEL, LAPolicy, NSString *, void (^reply)(BOOL, NSError *))
-    {
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-            Util::sleep(1); // mimic user interaction delay
-            reply(YES, nil);
-        });
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class LAEvaluateAccessControlFailedSwizzler {
-public:
-    LAEvaluateAccessControlFailedSwizzler()
-        : m_swizzler([LAContext class], @selector(evaluateAccessControl:operation:localizedReason:reply:), reinterpret_cast<IMP>(evaluateAccessControlFailed))
-    {
-    }
-private:
-    static void evaluateAccessControlFailed(id, SEL, SecAccessControlRef, LAAccessControlOperation, NSString *, void (^reply)(BOOL, NSError *))
-    {
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-            Util::sleep(1); // mimic user interaction delay
-            reply(NO, nil);
-        });
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class LAEvaluateAccessControlPassedSwizzler {
-public:
-    LAEvaluateAccessControlPassedSwizzler()
-        : m_swizzler([LAContext class], @selector(evaluateAccessControl:operation:localizedReason:reply:), reinterpret_cast<IMP>(evaluateAccessControlPassed))
-    {
-    }
-private:
-    static void evaluateAccessControlPassed(id, SEL, SecAccessControlRef, LAAccessControlOperation, NSString *, void (^reply)(BOOL, NSError *))
-    {
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-            Util::sleep(1); // mimic user interaction delay
-            reply(YES, nil);
-        });
-    }
-    InstanceMethodSwizzler m_swizzler;
-};
-
-class TestLocalAuthenticator : public WebCore::LocalAuthenticator {
-public:
-    void setFailureFlag() { m_failureFlag = true; }
-
-protected:
-    void issueClientCertificate(const String& rpId, const String& username, const Vector<uint8_t>& hash, WebCore::CompletionBlock _Nonnull completion) const final
-    {
-        if (m_failureFlag) {
-            completion(NULL, NULL, [NSError errorWithDomain:NSOSStatusErrorDomain code:-1 userInfo:nil]);
-            return;
-        }
-
-        ASSERT_EQ(32ul, hash.size());
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), BlockPtr<void()>::fromCallable([rpId = rpId.isolatedCopy(), username = username.isolatedCopy(), completion = makeBlockPtr(completion)] {
-            Util::sleep(1); // mimic network delay
-
-            // Get Key and add it to Keychain
-            auto key = getTestKey();
-            String label(username);
-            label.append("@" + rpId + "-rk"); // mimic what DeviceIdentity would do.
-            NSDictionary* addQuery = @{
-                (id)kSecValueRef: (id)key.get(),
-                (id)kSecClass: (id)kSecClassKey,
-                (id)kSecAttrLabel: (id)label,
-            };
-            OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
-            ASSERT_FALSE(status);
-
-            // Construct dummy certificates
-            auto attestationCertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:testAttestationCertificateBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get()));
-            auto attestationIssuingCACertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:testAttestationIssuingCACertificateBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get()));
-
-            // Do self-attestation instead.
-            completion(key.get(), [NSArray arrayWithObjects: (__bridge id)attestationCertificate.get(), (__bridge id)attestationIssuingCACertificate.get(), nil], NULL);
-        }).get());
-    }
-
-private:
-    bool m_failureFlag { false };
-};
-
-// FIXME(182769): Convert the followings to proper API tests.
-TEST(LocalAuthenticator, MakeCredentialNotSupportedPubKeyCredParams)
-{
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, -35 }); // ES384
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, -257 }); // RS256
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotSupportedError, exception.code);
-            EXPECT_STREQ("The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialExcludeCredentialsMatch)
-{
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialDescriptor descriptor;
-    descriptor.type = WebCore::PublicKeyCredentialType::PublicKey;
-    WTF::base64Decode(testCredentialIdBase64, descriptor.idVector);
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.rp.id = testRpId;
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-    creationOptions.excludeCredentials.append(WTFMove(descriptor));
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator.", exception.message.ascii().data());
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialBiometricsNotEnrolled)
-{
-    LACantEvaluatePolicySwizzler swizzler;
-
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("No avaliable authenticators.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialBiometricsNotAuthenticated)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluatePolicyFailedSwizzler evaluatePolicyFailedSwizzler;
-
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("Couldn't get user consent.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialNotAttestated)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluatePolicyPassedSwizzler evaluatePolicyPassedSwizzler;
-
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    authenticator->setFailureFlag();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::UnknownError, exception.code);
-            EXPECT_STREQ("Unknown internal error.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialDeleteOlderCredenital)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluatePolicyPassedSwizzler evaluatePolicyPassedSwizzler;
-
-    // Insert the older credential
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.rp.id = testRpId;
-    creationOptions.user.name = testUsername;
-    creationOptions.user.idVector.append(testUserhandle, sizeof(testUserhandle));
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    authenticator->setFailureFlag();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            NSDictionary *query = @{
-                (id)kSecClass: (id)kSecClassKey,
-                (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-                (id)kSecAttrLabel: testRpId,
-                (id)kSecAttrApplicationTag: [NSData dataWithBytes:testUserhandle length:sizeof(testUserhandle)],
-            };
-            OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
-            EXPECT_EQ(errSecItemNotFound, status);
-            done = true;
-        });
-    };
-    authenticator->makeCredential({ }, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, MakeCredentialPassedWithSelfAttestation)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluatePolicyPassedSwizzler evaluatePolicyPassedSwizzler;
-
-    WebCore::PublicKeyCredentialCreationOptions creationOptions;
-    creationOptions.rp.id = testRpId;
-    creationOptions.user.name = testUsername;
-    creationOptions.user.idVector.append(testUserhandle, sizeof(testUserhandle));
-    creationOptions.pubKeyCredParams.append({ WebCore::PublicKeyCredentialType::PublicKey, COSE::ES256 });
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData& data) {
-            Vector<uint8_t> credentialId;
-            credentialId.append(reinterpret_cast<uint8_t*>(data.rawId->data()), data.rawId->byteLength());
-            Vector<uint8_t> attestationObject;
-            attestationObject.append(reinterpret_cast<uint8_t*>(data.attestationObject->data()), data.attestationObject->byteLength());
-
-            // Check Keychain
-            NSDictionary *query = @{
-                (id)kSecClass: (id)kSecClassKey,
-                (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
-                (id)kSecAttrLabel: testRpId,
-                (id)kSecAttrApplicationLabel: adoptNS([[NSData alloc] initWithBase64EncodedString:testCredentialIdBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
-                (id)kSecAttrApplicationTag: [NSData dataWithBytes:testUserhandle length:sizeof(testUserhandle)],
-            };
-            OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
-            EXPECT_FALSE(status);
-
-            // Check Credential ID
-            EXPECT_TRUE(WTF::base64Encode(credentialId.data(), credentialId.size()) == testCredentialIdBase64);
-
-            // Check Attestation Object
-            auto attestationObjectMap = cbor::CBORReader::read(attestationObject);
-            ASSERT_TRUE(!!attestationObjectMap);
-
-            // Check Authenticator Data.
-            auto& authData = attestationObjectMap->getMap().find(cbor::CBORValue("authData"))->second.getByteString();
-            size_t pos = 0;
-            uint8_t expectedRpIdHash[] = {
-                0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68,
-                0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b,
-                0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7,
-                0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63
-            };
-            EXPECT_FALSE(memcmp(authData.data() + pos, expectedRpIdHash, sizeof(expectedRpIdHash)));
-            pos += sizeof(expectedRpIdHash);
-
-            // FLAGS
-            EXPECT_EQ(69, authData[pos]);
-            pos++;
-
-            uint32_t counter = -1;
-            memcpy(&counter, authData.data() + pos, sizeof(uint32_t));
-            EXPECT_EQ(0u, counter);
-            pos += sizeof(uint32_t);
-
-            uint8_t expectedAAGUID[] = {
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-            };
-            EXPECT_FALSE(memcmp(authData.data() + pos, expectedAAGUID, sizeof(expectedAAGUID)));
-            pos += sizeof(expectedAAGUID);
-
-            uint16_t l = -1;
-            memcpy(&l, authData.data() + pos, sizeof(uint16_t));
-            EXPECT_EQ(20u, l);
-            pos += sizeof(uint16_t);
-
-            EXPECT_FALSE(memcmp(authData.data() + pos, credentialId.data(), l));
-            pos += l;
-
-            // Credential Public Key
-            // FIXME(183536): The CBOR reader doesn't support negative integer as map key. Thus we couldn't utilzie it.
-            EXPECT_STREQ("pQECAyYgASFYIDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749IlggVBJPgqUIwfhWHJ91nb7UPH76c0+WFOzZKslPyyFse4g=", WTF::base64Encode(authData.data() + pos, authData.size() - pos).ascii().data());
-
-            // Check Self Attestation
-            EXPECT_STREQ("Apple", attestationObjectMap->getMap().find(cbor::CBORValue("fmt"))->second.getString().ascii().data());
-
-            auto& attStmt = attestationObjectMap->getMap().find(cbor::CBORValue("attStmt"))->second.getMap();
-            EXPECT_EQ(COSE::ES256, attStmt.find(cbor::CBORValue("alg"))->second.getNegative());
-
-            auto& sig = attStmt.find(cbor::CBORValue("sig"))->second.getByteString();
-            auto privateKey = getTestKey();
-            EXPECT_TRUE(SecKeyVerifySignature(SecKeyCopyPublicKey(privateKey.get()), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)[NSData dataWithBytes:authData.data() length:authData.size()], (__bridge CFDataRef)[NSData dataWithBytes:sig.data() length:sig.size()], NULL));
-
-            // Check certificates
-            auto& x5c = attStmt.find(cbor::CBORValue("x5c"))->second.getArray();
-            auto& attestationCertificateData = x5c[0].getByteString();
-            auto attestationCertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)[NSData dataWithBytes:attestationCertificateData.data() length:attestationCertificateData.size()]));
-            CFStringRef commonName = nullptr;
-            status = SecCertificateCopyCommonName(attestationCertificate.get(), &commonName);
-            auto retainCommonName = adoptCF(commonName);
-            ASSERT(!status);
-            EXPECT_STREQ("00008010-000A49A230A0213A", [(NSString *)commonName cStringUsingEncoding: NSASCIIStringEncoding]);
-
-            auto& attestationIssuingCACertificateData = x5c[1].getByteString();
-            auto attestationIssuingCACertificate = adoptCF(SecCertificateCreateWithData(NULL, (__bridge CFDataRef)[NSData dataWithBytes:attestationIssuingCACertificateData.data() length:attestationIssuingCACertificateData.size()]));
-            commonName = nullptr;
-            status = SecCertificateCopyCommonName(attestationIssuingCACertificate.get(), &commonName);
-            retainCommonName = adoptCF(commonName);
-            ASSERT(!status);
-            EXPECT_STREQ("Basic Attestation User Sub CA1", [(NSString *)commonName cStringUsingEncoding: NSASCIIStringEncoding]);
-
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    Vector<uint8_t> hash(32);
-    authenticator->makeCredential(hash, creationOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionAllowCredentialsMismatch1)
-{
-    // Transports mismatched
-    WebCore::PublicKeyCredentialDescriptor descriptor;
-    descriptor.type = WebCore::PublicKeyCredentialType::PublicKey;
-    descriptor.transports.append(WebCore::PublicKeyCredentialDescriptor::AuthenticatorTransport::Usb);
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.allowCredentials.append(WTFMove(descriptor));
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("No matched credentials are found in the platform attached authenticator.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->getAssertion({ }, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionAllowCredentialsMismatch2)
-{
-    // No existing credential
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.rpId = testRpId;
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("No matched credentials are found in the platform attached authenticator.", exception.message.ascii().data());
-            done = true;
-        });
-    };
-    authenticator->getAssertion({ }, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionAllowCredentialsMismatch3)
-{
-    // Credential ID mismatched
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialDescriptor descriptor;
-    descriptor.type = WebCore::PublicKeyCredentialType::PublicKey;
-    WTF::base64Decode(testCredentialIdBase64, descriptor.idVector);
-    descriptor.idVector[19] = 0; // nuke the last byte.
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.rpId = testRpId;
-    requestOptions.allowCredentials.append(descriptor);
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("No matched credentials are found in the platform attached authenticator.", exception.message.ascii().data());
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    authenticator->getAssertion({ }, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionBiometricsNotEnrolled)
-{
-    LACantEvaluatePolicySwizzler swizzler;
-
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.rpId = testRpId;
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("No avaliable authenticators.", exception.message.ascii().data());
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    authenticator->getAssertion({ }, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionBiometricsNotAuthenticated)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluateAccessControlFailedSwizzler evaluateAccessControlFailedSwizzler;
-
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.rpId = testRpId;
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData&) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_EQ(WebCore::NotAllowedError, exception.code);
-            EXPECT_STREQ("Couldn't get user consent.", exception.message.ascii().data());
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    authenticator->getAssertion({ }, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-TEST(LocalAuthenticator, GetAssertionPassed)
-{
-    LACanEvaluatePolicySwizzler canEvaluatePolicySwizzler;
-    LAEvaluateAccessControlPassedSwizzler evaluateAccessControlPassedSwizzler;
-
-    addTestKeyToKeychain();
-
-    WebCore::PublicKeyCredentialRequestOptions requestOptions;
-    requestOptions.rpId = testRpId;
-
-    Vector<uint8_t> hash(32);
-
-    bool done = false;
-    std::unique_ptr<TestLocalAuthenticator> authenticator = std::make_unique<TestLocalAuthenticator>();
-    auto callback = [&done, hash] (Variant<WebCore::PublicKeyCredentialData, WebCore::ExceptionData>&& result) {
-        WTF::switchOn(result, [&](const WebCore::PublicKeyCredentialData& data) {
-            Vector<uint8_t> credentialId;
-            credentialId.append(reinterpret_cast<uint8_t*>(data.rawId->data()), data.rawId->byteLength());
-            Vector<uint8_t> authData;
-            authData.append(reinterpret_cast<uint8_t*>(data.authenticatorData->data()), data.authenticatorData->byteLength());
-            Vector<uint8_t> signature;
-            signature.append(reinterpret_cast<uint8_t*>(data.signature->data()), data.signature->byteLength());
-            Vector<uint8_t> userhandle;
-            userhandle.append(reinterpret_cast<uint8_t*>(data.userHandle->data()), data.userHandle->byteLength());
-
-            // Check Credential ID
-            EXPECT_TRUE(WTF::base64Encode(credentialId.data(), credentialId.size()) == testCredentialIdBase64);
-
-            // Check Authenticator Data.
-            size_t pos = 0;
-            uint8_t expectedRpIdHash[] = {
-                0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68,
-                0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b,
-                0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7,
-                0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63
-            };
-            EXPECT_FALSE(memcmp(authData.data() + pos, expectedRpIdHash, sizeof(expectedRpIdHash)));
-            pos += sizeof(expectedRpIdHash);
-
-            // FLAGS
-            EXPECT_EQ(5, authData[pos]);
-            pos++;
-
-            uint32_t counter = -1;
-            memcpy(&counter, authData.data() + pos, sizeof(uint32_t));
-            EXPECT_EQ(0u, counter);
-
-            // Check signature
-            auto privateKey = getTestKey();
-            Vector<uint8_t> dataToSign(authData);
-            dataToSign.appendVector(hash);
-            EXPECT_TRUE(SecKeyVerifySignature(SecKeyCopyPublicKey(privateKey.get()), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)[NSData dataWithBytes:dataToSign.data() length:dataToSign.size()], (__bridge CFDataRef)[NSData dataWithBytes:signature.data() length:signature.size()], NULL));
-
-            // Check User Handle
-            EXPECT_EQ(userhandle.size(), sizeof(testUserhandle));
-            EXPECT_FALSE(memcmp(userhandle.data(), testUserhandle, sizeof(testUserhandle)));
-
-            cleanUpKeychain();
-            done = true;
-        }, [&](const  WebCore::ExceptionData& exception) {
-            EXPECT_FALSE(true);
-            cleanUpKeychain();
-            done = true;
-        });
-    };
-    authenticator->getAssertion(hash, requestOptions, WTFMove(callback));
-
-    TestWebKitAPI::Util::run(&done);
-}
-
-} // namespace TestWebKitAPI
-
-#endif // PLATFORM(IOS)
-
-#endif // ENABLE(WEB_AUTHN)
index 13de720..bf78851 100644 (file)
@@ -351,4 +351,10 @@ interface TestRunner {
     readonly attribute unsigned long userScriptInjectedCount;
 
     void sendDisplayConfigurationChangedMessageForTesting();
+
+    // WebAuthN
+    void setWebAuthenticationMockConfiguration(object configuration);
+    void addTestKeyToKeychain(DOMString privateKeyBase64, DOMString attrLabel, DOMString applicationTagBase64);
+    void cleanUpKeychain(DOMString attrLabel);
+    boolean keyExistsInKeychain(DOMString attrLabel, DOMString applicationTagBase64);
 };
index 2c6168b..f3604b7 100644 (file)
@@ -2348,4 +2348,142 @@ void TestRunner::sendDisplayConfigurationChangedMessageForTesting()
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
 }
 
+// WebAuthN
+void TestRunner::setWebAuthenticationMockConfiguration(JSValueRef configurationValue)
+{
+    auto& injectedBundle = InjectedBundle::singleton();
+    WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
+    JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+    if (!JSValueIsObject(context, configurationValue))
+        return;
+    JSObjectRef configuration = JSValueToObject(context, configurationValue, 0);
+
+    JSRetainPtr<JSStringRef> localPropertyName(Adopt, JSStringCreateWithUTF8CString("local"));
+    JSValueRef localValue = JSObjectGetProperty(context, configuration, localPropertyName.get(), 0);
+    if (!JSValueIsObject(context, localValue))
+        return;
+    JSObjectRef local = JSValueToObject(context, localValue, 0);
+
+    JSRetainPtr<JSStringRef> acceptAuthenticationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAuthentication"));
+    JSValueRef acceptAuthenticationValue = JSObjectGetProperty(context, local, acceptAuthenticationPropertyName.get(), 0);
+    if (!JSValueIsBoolean(context, acceptAuthenticationValue))
+        return;
+    bool acceptAuthentication = JSValueToBoolean(context, acceptAuthenticationValue);
+
+    JSRetainPtr<JSStringRef> acceptAttestationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAttestation"));
+    JSValueRef acceptAttestationValue = JSObjectGetProperty(context, local, acceptAttestationPropertyName.get(), 0);
+    if (!JSValueIsBoolean(context, acceptAttestationValue))
+        return;
+    bool acceptAttestation = JSValueToBoolean(context, acceptAttestationValue);
+
+    JSRetainPtr<JSStringRef> privateKeyBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("privateKeyBase64"));
+    JSValueRef privateKeyBase64Value = JSObjectGetProperty(context, local, privateKeyBase64PropertyName.get(), 0);
+    if (!JSValueIsString(context, privateKeyBase64Value))
+        return;
+
+    Vector<WKRetainPtr<WKStringRef>> localKeys;
+    Vector<WKRetainPtr<WKTypeRef>> localValues;
+    localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("AcceptAuthentication") });
+    localValues.append(adoptWK(WKBooleanCreate(acceptAuthentication)).get());
+    localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("AcceptAttestation") });
+    localValues.append(adoptWK(WKBooleanCreate(acceptAttestation)).get());
+    localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("PrivateKeyBase64") });
+    localValues.append(toWK(adopt(JSValueToStringCopy(context, privateKeyBase64Value, 0)).get()));
+
+    Vector<WKStringRef> rawLocalKeys;
+    Vector<WKTypeRef> rawLocalValues;
+    rawLocalKeys.resize(localKeys.size());
+    rawLocalValues.resize(localValues.size());
+    for (size_t i = 0; i < localKeys.size(); ++i) {
+        rawLocalKeys[i] = localKeys[i].get();
+        rawLocalValues[i] = localValues[i].get();
+    }
+
+    Vector<WKRetainPtr<WKStringRef>> configurationKeys;
+    Vector<WKRetainPtr<WKTypeRef>> configurationValues;
+    configurationKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("Local") });
+    configurationValues.append({ AdoptWK, WKDictionaryCreate(rawLocalKeys.data(), rawLocalValues.data(), rawLocalKeys.size()) });
+
+    Vector<WKStringRef> rawConfigurationKeys;
+    Vector<WKTypeRef> rawConfigurationValues;
+    rawConfigurationKeys.resize(configurationKeys.size());
+    rawConfigurationValues.resize(configurationValues.size());
+    for (size_t i = 0; i < configurationKeys.size(); ++i) {
+        rawConfigurationKeys[i] = configurationKeys[i].get();
+        rawConfigurationValues[i] = configurationValues[i].get();
+    }
+
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetWebAuthenticationMockConfiguration"));
+    WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawConfigurationKeys.data(), rawConfigurationValues.data(), rawConfigurationKeys.size()));
+    
+    WKBundlePostSynchronousMessage(injectedBundle.bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::addTestKeyToKeychain(JSStringRef privateKeyBase64, JSStringRef attrLabel, JSStringRef applicationTagBase64)
+{
+    Vector<WKRetainPtr<WKStringRef>> keys;
+    Vector<WKRetainPtr<WKTypeRef>> values;
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("PrivateKey") });
+    values.append(toWK(privateKeyBase64));
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AttrLabel") });
+    values.append(toWK(attrLabel));
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ApplicationTag") });
+    values.append(toWK(applicationTagBase64));
+
+    Vector<WKStringRef> rawKeys;
+    Vector<WKTypeRef> rawValues;
+    rawKeys.resize(keys.size());
+    rawValues.resize(values.size());
+
+    fo