7aad4c699cc6c7612bd86d7983df4ec534842b30
[WebKit-https.git] / Source / WebKit / UIProcess / WebAuthentication / Cocoa / LocalConnection.mm
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "LocalConnection.h"
28
29 #if ENABLE(WEB_AUTHN)
30
31 #import "DeviceIdentitySPI.h"
32 #import <WebCore/ExceptionData.h>
33 #import <wtf/BlockPtr.h>
34 #import <wtf/RunLoop.h>
35
36 #import "LocalAuthenticationSoftLink.h"
37
38 namespace WebKit {
39
40 void LocalConnection::getUserConsent(const String& reason, UserConsentCallback&& completionHandler) const
41 {
42     // FIXME(182772)
43 #if PLATFORM(IOS_FAMILY)
44     auto context = adoptNS([allocLAContextInstance() init]);
45     auto reply = makeBlockPtr([completionHandler = WTFMove(completionHandler)] (BOOL success, NSError *error) mutable {
46         ASSERT(!RunLoop::isMain());
47
48         UserConsent consent = UserConsent::Yes;
49         if (!success || error) {
50             LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
51             consent = UserConsent::No;
52         }
53         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), consent]() mutable {
54             completionHandler(consent);
55         });
56     });
57     [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:reply.get()];
58 #endif
59 }
60
61 void LocalConnection::getUserConsent(const String& reason, SecAccessControlRef accessControl, UserConsentContextCallback&& completionHandler) const
62 {
63     // FIXME(182772)
64 #if PLATFORM(IOS_FAMILY)
65     auto context = adoptNS([allocLAContextInstance() init]);
66     auto reply = makeBlockPtr([context, completionHandler = WTFMove(completionHandler)] (BOOL success, NSError *error) mutable {
67         ASSERT(!RunLoop::isMain());
68
69         UserConsent consent = UserConsent::Yes;
70         if (!success || error) {
71             LOG_ERROR("Couldn't authenticate with biometrics: %@", error);
72             consent = UserConsent::No;
73         }
74         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), consent, context = WTFMove(context)]() mutable {
75             completionHandler(consent, context.get());
76         });
77     });
78     [context evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign localizedReason:reason reply:reply.get()];
79 #endif
80 }
81
82 void LocalConnection::getAttestation(const String& rpId, const String& username, const Vector<uint8_t>& hash, AttestationCallback&& completionHandler) const
83 {
84     // DeviceIdentity.Framework is not avaliable in iOS simulator.
85 #if PLATFORM(IOS_FAMILY) && !PLATFORM(IOS_FAMILY_SIMULATOR)
86     // Apple Attestation
87     ASSERT(hash.size() <= 32);
88
89     RetainPtr<SecAccessControlRef> accessControlRef;
90     {
91         CFErrorRef errorRef = nullptr;
92         accessControlRef = adoptCF(SecAccessControlCreateWithFlags(NULL, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence, &errorRef));
93         auto retainError = adoptCF(errorRef);
94         if (errorRef) {
95             LOG_ERROR("Couldn't create ACL: %@", (NSError *)errorRef);
96             completionHandler(NULL, NULL, [NSError errorWithDomain:@"com.apple.WebKit.WebAuthN" code:1 userInfo:nil]);
97             return;
98         }
99     }
100
101     String label = makeString(username, "@", rpId);
102     NSDictionary *options = @{
103         kMAOptionsBAAKeychainLabel: label,
104         // FIXME(rdar://problem/38489134): Need a formal name.
105         kMAOptionsBAAKeychainAccessGroup: @"com.apple.safari.WebAuthN.credentials",
106         kMAOptionsBAAIgnoreExistingKeychainItems: @YES,
107         // FIXME(rdar://problem/38489134): Determine a proper lifespan.
108         kMAOptionsBAAValidity: @(1440), // Last one day.
109         kMAOptionsBAASCRTAttestation: @NO,
110         kMAOptionsBAANonce: [NSData dataWithBytes:hash.data() length:hash.size()],
111         kMAOptionsBAAAccessControls: (id)accessControlRef.get(),
112         kMAOptionsBAAOIDSToInclude: @[kMAOptionsBAAOIDNonce]
113     };
114
115     // FIXME(183652): Reduce prompt for biometrics
116     DeviceIdentityIssueClientCertificateWithCompletion(dispatch_get_main_queue(), options, makeBlockPtr(WTFMove(completionHandler)).get());
117 #endif
118 }
119
120 } // namespace WebKit
121
122 #endif // ENABLE(WEB_AUTHN)