Can't establish mTLS on iOS with WKWebView and ProxyConfiguration

I have a sample iOS app in Xcode that I run in the iOS 17.5 Simulator. It creates a WKWebView and configures a proxy via the ProxyConfiguration API, it works as expected unless the proxy tries to establish mTLS. It seems there is no way to handle the client certificate request when using a proxy. If I navigate to a page that requests mTLS without a proxy configured, it works as expected. Here is a minimal repro:

#import "ViewController.h"
#import <WebKit/WebKit.h>

@import Foundation;
@import WebKit;

@interface ViewController () <WKNavigationDelegate>
@property (nonatomic,strong) WKWebView* webView;
@property (nonatomic, strong) WKWebViewConfiguration * webConfig;
@end

@implementation ViewController

- (void)loadView {
    [super loadView];
    
    nw_protocol_options_t tls_options = nw_tls_create_options();
    sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options);

    sec_protocol_options_set_challenge_block(
        sec_options,
        ^(sec_protocol_metadata_t metadata, sec_protocol_challenge_complete_t challenge_complete) {
            NSLog(@"Inside of challenge block");
            challenge_complete(nil);
        },
        dispatch_get_main_queue());
    
    nw_endpoint_t proxy_endpoint =
    nw_endpoint_create_host(GetHost(), GetPort());
    
    nw_relay_hop_t relay =
    nw_relay_hop_create(nil, proxy_endpoint, tls_options);
    nw_proxy_config_t proxy_config =
    nw_proxy_config_create_relay(relay, nil);
    
    nw_proxy_config_add_match_domain(proxy_config, "api.ipify.org");
    
    self.webConfig = [[WKWebViewConfiguration alloc] init];
    self.webConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
    self.webConfig.websiteDataStore.proxyConfigurations = @[ proxy_config ];
    
    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:self.webConfig];
    
    self.webView.navigationDelegate = self;
    
    [self.view addSubview:self.webView];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%s",__func__);
    NSURL* url = [[NSURL alloc] initWithString:@"https://api.ipify.org"];
    NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url];
    [self.webView loadRequest:request];
}

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"%s",__func__);
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"%s. Error %@",__func__,error);
}

- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
    NSLog(@"%s",__func__);
    NSLog(@"protection space: %@", challenge.protectionSpace.authenticationMethod);
    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}

@end

The logs for this code show:

-[ViewController viewDidLoad]
-[ViewController webView:didStartProvisionalNavigation:]
-[ViewController webView:didFailProvisionalNavigation:withError:]. Error Error Domain=NSURLErrorDomain Code=-1206 "The server “api.ipify.org” requires a client certificate."

If we don't set up the ProxyConfiguration and navigate to a site that requires mTLS, the logs look like this:

-[ViewController viewDidLoad]
-[ViewController webView:didReceiveAuthenticationChallenge:completionHandler:]
protection space: NSURLAuthenticationMethodServerTrust
-[ViewController webView:didReceiveAuthenticationChallenge:completionHandler:]
protection space: NSURLAuthenticationMethodClientCertificate
-[ViewController webView:didStartProvisionalNavigation:]
//...

Eventually the request fails but the key difference is that didReceiveAuthenticationChallenge was invoked. When using the ProxyConfiguration neither that function nor the block we set via sec_protocol_options_set_challenge_block were run.

I also tried to provide the client identity via sec_protocol_options_set_local_identity to no avail, and I've tried configuring these options too but they had no effect

    sec_protocol_options_add_tls_application_protocol(sec_options, "h2");
    sec_protocol_options_set_max_tls_protocol_version(sec_options, tls_protocol_version_TLSv13);
    sec_protocol_options_set_peer_authentication_required(sec_options, true);

Am I missing something? Or is this a bug in the ProxyConfiguration API?

Can't establish mTLS on iOS with WKWebView and ProxyConfiguration
 
 
Q