Remove unused WebProcessPool::setCanHandleHTTPSServerTrustEvaluation
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / Challenge.mm
1 /*
2  * Copyright (C) 2019 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
28 #import "PlatformUtilities.h"
29 #import "TCPServer.h"
30 #import "Test.h"
31 #import "TestWKWebView.h"
32 #import "WKWebViewConfigurationExtras.h"
33 #import <WebKit/WKNavigationDelegate.h>
34 #import <WebKit/WKProcessPoolPrivate.h>
35 #import <WebKit/WKWebsiteDataRecordPrivate.h>
36 #import <WebKit/WKWebsiteDataStorePrivate.h>
37 #import <WebKit/WebKit.h>
38 #import <WebKit/_WKErrorRecoveryAttempting.h>
39 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
40 #import <wtf/Platform.h>
41 #import <wtf/RetainPtr.h>
42 #import <wtf/spi/cocoa/SecuritySPI.h>
43
44 static bool navigationFinished;
45
46 static RetainPtr<NSURLCredential> credentialWithIdentity()
47 {
48     auto certificateBytes = TestWebKitAPI::TCPServer::testCertificate();
49     auto certificate = adoptCF(SecCertificateCreateWithData(nullptr, (__bridge CFDataRef)[NSData dataWithBytes:certificateBytes.data() length:certificateBytes.size()]));
50     
51     auto privateKeyBytes = TestWebKitAPI::TCPServer::testPrivateKey();
52     NSData *derEncodedPrivateKey = [NSData dataWithBytes:privateKeyBytes.data() length:privateKeyBytes.size()];
53     NSDictionary* options = @{
54         (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
55         (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
56         (id)kSecAttrKeySizeInBits: @4096,
57     };
58     const NSUInteger pemEncodedPrivateKeyHeaderLength = 26;
59     CFErrorRef error = nullptr;
60     auto privateKey = adoptCF(SecKeyCreateWithData((__bridge CFDataRef)[derEncodedPrivateKey subdataWithRange:NSMakeRange(pemEncodedPrivateKeyHeaderLength, derEncodedPrivateKey.length - pemEncodedPrivateKeyHeaderLength)], (__bridge CFDictionaryRef)options, &error));
61     EXPECT_NULL(error);
62     EXPECT_NOT_NULL(privateKey.get());
63
64     auto identity = adoptCF(SecIdentityCreate(kCFAllocatorDefault, certificate.get(), privateKey.get()));
65     EXPECT_NOT_NULL(identity);
66     
67     return [NSURLCredential credentialWithIdentity:identity.get() certificates:@[(id)certificate.get()] persistence:NSURLCredentialPersistenceNone];
68 }
69
70 @interface ChallengeDelegate : NSObject <WKNavigationDelegate>
71 @end
72
73 @implementation ChallengeDelegate
74
75 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
76 {
77     navigationFinished = true;
78 }
79
80 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
81 {
82     NSURLProtectionSpace *protectionSpace = challenge.protectionSpace;
83     EXPECT_NULL(challenge.proposedCredential);
84     EXPECT_EQ(challenge.previousFailureCount, 0);
85     EXPECT_TRUE([protectionSpace.realm isEqualToString:@"testrealm"]);
86     EXPECT_FALSE(protectionSpace.receivesCredentialSecurely);
87     EXPECT_FALSE(protectionSpace.isProxy);
88     EXPECT_TRUE([protectionSpace.host isEqualToString:@"127.0.0.1"]);
89     EXPECT_NULL(protectionSpace.proxyType);
90     EXPECT_TRUE([protectionSpace.protocol isEqualToString:NSURLProtectionSpaceHTTP]);
91     EXPECT_TRUE([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]);
92     EXPECT_EQ([(NSHTTPURLResponse *)challenge.failureResponse statusCode], 401);
93
94     completionHandler(NSURLSessionAuthChallengeUseCredential, credentialWithIdentity().get());
95 }
96
97 @end
98
99 TEST(Challenge, SecIdentity)
100 {
101     using namespace TestWebKitAPI;
102     TCPServer server(TCPServer::respondWithChallengeThenOK);
103
104     auto webView = adoptNS([WKWebView new]);
105     auto delegate = adoptNS([ChallengeDelegate new]);
106     [webView setNavigationDelegate:delegate.get()];
107
108     // Make sure no credential left by previous tests.
109     NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithHost:@"127.0.0.1" port:server.port() protocol:NSURLProtectionSpaceHTTP realm:@"testrealm" authenticationMethod:NSURLAuthenticationMethodHTTPBasic] autorelease];
110     [[webView configuration].processPool _clearPermanentCredentialsForProtectionSpace:protectionSpace];
111
112     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", server.port()]]]];
113
114     Util::run(&navigationFinished);
115 }
116
117 @interface ClientCertificateDelegate : NSObject <WKNavigationDelegate> {
118     Vector<RetainPtr<NSString>> _authenticationMethods;
119 }
120 - (const Vector<RetainPtr<NSString>>&)authenticationMethods;
121 @end
122
123 @implementation ClientCertificateDelegate
124
125 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
126 {
127     navigationFinished = true;
128 }
129
130 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
131 {
132     _authenticationMethods.append(challenge.protectionSpace.authenticationMethod);
133
134     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
135         return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
136     
137     EXPECT_TRUE([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]);
138     completionHandler(NSURLSessionAuthChallengeUseCredential, credentialWithIdentity().get());
139 }
140
141 - (const Vector<RetainPtr<NSString>>&)authenticationMethods
142 {
143     return _authenticationMethods;
144 }
145
146 @end
147
148 #if HAVE(SEC_KEY_PROXY)
149 TEST(Challenge, ClientCertificate)
150 {
151     using namespace TestWebKitAPI;
152     TCPServer server(TCPServer::Protocol::HTTPSWithClientCertificateRequest, TCPServer::respondWithOK);
153
154     auto webView = adoptNS([WKWebView new]);
155     auto delegate = adoptNS([ClientCertificateDelegate new]);
156     [webView setNavigationDelegate:delegate.get()];
157     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://127.0.0.1:%d/", server.port()]]]];
158     
159     Util::run(&navigationFinished);
160     auto& methods = [delegate authenticationMethods];
161     EXPECT_EQ(methods.size(), 2ull);
162     EXPECT_TRUE([methods[0] isEqualToString:NSURLAuthenticationMethodServerTrust]);
163     EXPECT_TRUE([methods[1] isEqualToString:NSURLAuthenticationMethodClientCertificate]);
164 }
165 #endif
166
167 static bool receivedSecondChallenge;
168 static RetainPtr<NSURLCredential> persistentCredential;
169
170 @interface ProposedCredentialDelegate : NSObject <WKNavigationDelegate>
171 @end
172
173 @implementation ProposedCredentialDelegate
174
175 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
176 {
177     navigationFinished = true;
178 }
179
180 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
181 {
182     static bool firstChallenge = true;
183     if (firstChallenge) {
184         firstChallenge = false;
185         persistentCredential = adoptNS([[NSURLCredential alloc] initWithUser:@"testuser" password:@"testpassword" persistence:NSURLCredentialPersistencePermanent]);
186         return completionHandler(NSURLSessionAuthChallengeUseCredential, persistentCredential.get());
187         
188     }
189     receivedSecondChallenge = true;
190     return completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
191 }
192
193 @end
194
195 TEST(Challenge, BasicProposedCredential)
196 {
197     using namespace TestWebKitAPI;
198     TCPServer server(TCPServer::respondWithChallengeThenOK, 2);
199     auto configuration = retainPtr([WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BasicProposedCredentialPlugIn"]);
200     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
201     auto delegate = adoptNS([ProposedCredentialDelegate new]);
202     [webView setNavigationDelegate:delegate.get()];
203
204     // Make sure no credential left by previous tests.
205     NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithHost:@"127.0.0.1" port:server.port() protocol:NSURLProtectionSpaceHTTP realm:@"testrealm" authenticationMethod:NSURLAuthenticationMethodHTTPBasic] autorelease];
206     [[webView configuration].processPool _clearPermanentCredentialsForProtectionSpace:protectionSpace];
207
208     RetainPtr<NSURLRequest> request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", server.port()]]];
209     [webView loadRequest:request.get()];
210     Util::run(&navigationFinished);
211     navigationFinished = false;
212     [webView loadRequest:request.get()];
213     Util::run(&navigationFinished);
214     EXPECT_TRUE(receivedSecondChallenge);
215
216     // Clear persistent credentials created by this test.
217     [[webView configuration].processPool _clearPermanentCredentialsForProtectionSpace:protectionSpace];
218 }
219
220 #if HAVE(SSL)
221 static void verifyCertificateAndPublicKey(SecTrustRef trust)
222 {
223     EXPECT_NOT_NULL(trust);
224
225     auto compareData = [] (const RetainPtr<CFDataRef>& data, const Vector<uint8_t>& expected) {
226         size_t length = CFDataGetLength(data.get());
227         EXPECT_EQ(length, expected.size());
228         const UInt8* bytes = CFDataGetBytePtr(data.get());
229         for (size_t i = 0; i < length; ++i)
230             EXPECT_EQ(expected[i], bytes[i]);
231     };
232
233     auto publicKey = adoptCF(SecKeyCopyExternalRepresentation(adoptCF(SecTrustCopyPublicKey(trust)).get(), nullptr));
234     compareData(publicKey, {
235         0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd8, 0x2b, 0xc8, 0xa6, 0x32, 0xe4, 0x62, 0xff, 0x4d,
236         0xf3, 0xd0, 0xad, 0x59, 0x8b, 0x45, 0xa7, 0xbd, 0xf1, 0x47, 0xbf, 0x09, 0x58, 0x7b, 0x22, 0xbd,
237         0x35, 0xae, 0x97, 0x25, 0x86, 0x94, 0xa0, 0x80, 0xc0, 0xb4, 0x1f, 0x76, 0x91, 0x67, 0x46, 0x31,
238         0xd0, 0x10, 0x84, 0xb7, 0x22, 0x1e, 0x70, 0x23, 0x91, 0x72, 0xc8, 0xe9, 0x6d, 0x79, 0x3a, 0x85,
239         0x77, 0x80, 0x0f, 0xc4, 0x95, 0x16, 0x75, 0xc5, 0x4a, 0x71, 0x4c, 0xc8, 0x63, 0x3f, 0xa3, 0xf2,
240         0x63, 0x9c, 0x2a, 0x4f, 0x9a, 0xfa, 0xcb, 0xc1, 0x71, 0x6e, 0x28, 0x85, 0x28, 0xa0, 0x27, 0x1e,
241         0x65, 0x1c, 0xae, 0x07, 0xd5, 0x5b, 0x6f, 0x2d, 0x43, 0xed, 0x2b, 0x90, 0xb1, 0x8c, 0xaf, 0x24,
242         0x6d, 0xae, 0xe9, 0x17, 0x3a, 0x05, 0xc1, 0xbf, 0xb8, 0x1c, 0xae, 0x65, 0x3b, 0x1b, 0x58, 0xc2,
243         0xd9, 0xae, 0xd6, 0xaa, 0x67, 0x88, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01
244     });
245     
246     EXPECT_EQ(1, SecTrustGetCertificateCount(trust));
247     auto certificate = adoptCF(SecCertificateCopyData(SecTrustGetCertificateAtIndex(trust, 0)));
248     compareData(certificate, {
249         0x30, 0x82, 0x02, 0x58, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
250         0xfb, 0xb0, 0x4c, 0x2e, 0xab, 0x10, 0x9b, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
251         0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
252         0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
253         0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
254         0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
255         0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
256         0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x32, 0x33, 0x32, 0x30, 0x35, 0x30, 0x34, 0x30, 0x5a, 0x17,
257         0x0d, 0x31, 0x37, 0x30, 0x34, 0x32, 0x32, 0x32, 0x30, 0x35, 0x30, 0x34, 0x30, 0x5a, 0x30, 0x45,
258         0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
259         0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
260         0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74,
261         0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
262         0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
263         0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
264         0x81, 0x00, 0xd8, 0x2b, 0xc8, 0xa6, 0x32, 0xe4, 0x62, 0xff, 0x4d, 0xf3, 0xd0, 0xad, 0x59, 0x8b,
265         0x45, 0xa7, 0xbd, 0xf1, 0x47, 0xbf, 0x09, 0x58, 0x7b, 0x22, 0xbd, 0x35, 0xae, 0x97, 0x25, 0x86,
266         0x94, 0xa0, 0x80, 0xc0, 0xb4, 0x1f, 0x76, 0x91, 0x67, 0x46, 0x31, 0xd0, 0x10, 0x84, 0xb7, 0x22,
267         0x1e, 0x70, 0x23, 0x91, 0x72, 0xc8, 0xe9, 0x6d, 0x79, 0x3a, 0x85, 0x77, 0x80, 0x0f, 0xc4, 0x95,
268         0x16, 0x75, 0xc5, 0x4a, 0x71, 0x4c, 0xc8, 0x63, 0x3f, 0xa3, 0xf2, 0x63, 0x9c, 0x2a, 0x4f, 0x9a,
269         0xfa, 0xcb, 0xc1, 0x71, 0x6e, 0x28, 0x85, 0x28, 0xa0, 0x27, 0x1e, 0x65, 0x1c, 0xae, 0x07, 0xd5,
270         0x5b, 0x6f, 0x2d, 0x43, 0xed, 0x2b, 0x90, 0xb1, 0x8c, 0xaf, 0x24, 0x6d, 0xae, 0xe9, 0x17, 0x3a,
271         0x05, 0xc1, 0xbf, 0xb8, 0x1c, 0xae, 0x65, 0x3b, 0x1b, 0x58, 0xc2, 0xd9, 0xae, 0xd6, 0xaa, 0x67,
272         0x88, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55,
273         0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x8b, 0x75, 0xd5, 0xac, 0xcb, 0x08, 0xbe, 0x0e, 0x1f, 0x65,
274         0xb7, 0xfa, 0x56, 0xbe, 0x6c, 0xa7, 0x75, 0xda, 0x85, 0xaf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
275         0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x8b, 0x75, 0xd5, 0xac, 0xcb, 0x08, 0xbe, 0x0e, 0x1f,
276         0x65, 0xb7, 0xfa, 0x56, 0xbe, 0x6c, 0xa7, 0x75, 0xda, 0x85, 0xaf, 0x30, 0x0c, 0x06, 0x03, 0x55,
277         0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
278         0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x3b, 0xe8, 0x78, 0x6d,
279         0x95, 0xd6, 0x3d, 0x6a, 0xf7, 0x13, 0x19, 0x2c, 0x1b, 0xc2, 0x88, 0xae, 0x22, 0xab, 0xf4, 0x8d,
280         0x32, 0xf5, 0x7c, 0x71, 0x67, 0xcf, 0x2d, 0xd1, 0x1c, 0xc2, 0xc3, 0x87, 0xe2, 0xe9, 0xbe, 0x89,
281         0x5c, 0xe4, 0x34, 0xab, 0x48, 0x91, 0xc2, 0x3f, 0x95, 0xae, 0x2b, 0x47, 0x9e, 0x25, 0x78, 0x6b,
282         0x4f, 0x9a, 0x10, 0xa4, 0x72, 0xfd, 0xcf, 0xf7, 0x02, 0x0c, 0xb0, 0x0a, 0x08, 0xa4, 0x5a, 0xe2,
283         0xe5, 0x74, 0x7e, 0x11, 0x1d, 0x39, 0x60, 0x6a, 0xc9, 0x1f, 0x69, 0xf3, 0x2e, 0x63, 0x26, 0xdc,
284         0x9e, 0xef, 0x6b, 0x7a, 0x0a, 0xe1, 0x54, 0x57, 0x98, 0xaa, 0x72, 0x91, 0x78, 0x04, 0x7e, 0x1f,
285         0x8f, 0x65, 0x4d, 0x1f, 0x0b, 0x12, 0xac, 0x9c, 0x24, 0x0f, 0x84, 0x14, 0x1a, 0x55, 0x2d, 0x1f,
286         0xbb, 0xf0, 0x9d, 0x09, 0xb2, 0x08, 0x5c, 0x59, 0x32, 0x65, 0x80, 0x26
287     });
288 }
289
290 @interface ServerTrustDelegate : NSObject <WKNavigationDelegate>
291 - (void)waitForDidFinishNavigation;
292 - (NSError *)waitForDidFailProvisionalNavigationError;
293 - (size_t)authenticationChallengeCount;
294 @end
295
296 @implementation ServerTrustDelegate {
297     size_t _authenticationChallengeCount;
298     bool _navigationFinished;
299     RetainPtr<NSError> _provisionalNavigationFailedError;
300 }
301
302 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
303 {
304     _navigationFinished = true;
305 }
306
307 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
308 {
309     _provisionalNavigationFailedError = error;
310 }
311
312 - (void)waitForDidFinishNavigation
313 {
314     TestWebKitAPI::Util::run(&_navigationFinished);
315 }
316
317 - (NSError *)waitForDidFailProvisionalNavigationError
318 {
319     while (!_provisionalNavigationFailedError)
320         TestWebKitAPI::Util::spinRunLoop();
321     return _provisionalNavigationFailedError.autorelease();
322 }
323
324 - (size_t)authenticationChallengeCount
325 {
326     return _authenticationChallengeCount;
327 }
328
329 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
330 {
331     _authenticationChallengeCount++;
332     SecTrustRef trust = challenge.protectionSpace.serverTrust;
333     verifyCertificateAndPublicKey(trust);
334     completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:trust]);
335 }
336
337 @end
338
339 namespace TestWebKitAPI {
340
341 TEST(WebKit, ServerTrust)
342 {
343     TCPServer server(TCPServer::Protocol::HTTPS, [] (SSL* ssl) {
344         TCPServer::read(ssl);
345
346         const char* reply = ""
347         "HTTP/1.1 200 OK\r\n"
348         "Content-Length: 13\r\n\r\n"
349         "Hello, World!";
350         TCPServer::write(ssl, reply, strlen(reply));
351     });
352
353     auto webView = adoptNS([WKWebView new]);
354     auto delegate = adoptNS([ServerTrustDelegate new]);
355     [webView setNavigationDelegate:delegate.get()];
356
357     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://localhost:%d/", server.port()]]]];
358     [delegate waitForDidFinishNavigation];
359
360     verifyCertificateAndPublicKey([webView serverTrust]);
361     EXPECT_EQ([delegate authenticationChallengeCount], 1u);
362 }
363
364 TEST(WebKit, FastServerTrust)
365 {
366 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
367     TCPServer server(TCPServer::Protocol::HTTPS, TCPServer::respondWithOK);
368 #else
369     TCPServer server(TCPServer::Protocol::HTTPS, [](SSL* ssl) {
370         EXPECT_FALSE(ssl);
371     });
372 #endif
373     WKWebViewConfiguration *configuration = [[[WKWebViewConfiguration alloc] init] autorelease];
374     _WKWebsiteDataStoreConfiguration *dataStoreConfiguration = [[[_WKWebsiteDataStoreConfiguration alloc] init] autorelease];
375     dataStoreConfiguration.fastServerTrustEvaluationEnabled = YES;
376     configuration.websiteDataStore = [[[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration] autorelease];
377     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
378     auto delegate = adoptNS([ServerTrustDelegate new]);
379     [webView setNavigationDelegate:delegate.get()];
380     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://localhost:%d/", server.port()]]]];
381 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
382     [delegate waitForDidFinishNavigation];
383     EXPECT_EQ([delegate authenticationChallengeCount], 1ull);
384 #else
385     NSError *error = [delegate waitForDidFailProvisionalNavigationError];
386     EXPECT_WK_STREQ([error.userInfo[_WKRecoveryAttempterErrorKey] className], @"WKReloadFrameErrorRecoveryAttempter");
387     EXPECT_WK_STREQ(error.domain, NSURLErrorDomain);
388     EXPECT_EQ(error.code, NSURLErrorServerCertificateUntrusted);
389     EXPECT_EQ([delegate authenticationChallengeCount], 0ull);
390 #endif
391 }
392
393 } // namespace TestWebKitAPI
394
395 #endif // HAVE(SSL)