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