I'm building cross-platform auth components, which include client-certificate (PKI) authentication. Currently only SocketsHttpHandler is fully functional, but I would like to support NSUrlSessionHandler as well.
The work on https://github.com/xamarin/xamarin-macios/issues/13856 got me most of the way there, but one problem remains: detecting when a server challenges my client for a client certificate. In the past the norm used to be to look for HTTP/401 or 403 replies, but now many TLS/SSLv3-secured services use error alerts instead. This happens when the connection is still negotiated so I have no HttpResponseMessage to work with — all I have is an HttpRequestException.
With SocketsHttpHandler on iOS, I have options. I can subscribe to LocalCertificateSelectionCallback and listen for events, or I can check HttpRequestException's InnerException (of type Interop+AppleCrypto+SslException) gives me a specific libsecurity error code via HResult. I can check if it matches e.g. errSSLPeerBadCert (-9825) and prompt user for a client certificate.
But with NSUrlSessionHandler, this challenge is doomed to fail unless I pre-load a correct certificate ahead of time, and I end up with a fairly generic "connection lost" HttpRequestException:
System.Net.Http.HttpRequestException: The network connection was lost.
---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x600000c4cd20 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" ...}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/Foundation/NSUrlSessionHandler.cs:line 551
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
I might be able to workaround this by e.g. falling back to SocketHttpHandler when I see that "network connection lost" error to double-check if this is a certificate challenge. But my life would be a lot easier if NSUrlSessionHandler itself could help detect a challenge, either by providing a client-certificate-selection callback, or by providing a more detailed error message.
I'm building cross-platform auth components, which include client-certificate (PKI) authentication. Currently only SocketsHttpHandler is fully functional, but I would like to support NSUrlSessionHandler as well.
The work on https://github.com/xamarin/xamarin-macios/issues/13856 got me most of the way there, but one problem remains: detecting when a server challenges my client for a client certificate. In the past the norm used to be to look for HTTP/401 or 403 replies, but now many TLS/SSLv3-secured services use error alerts instead. This happens when the connection is still negotiated so I have no HttpResponseMessage to work with — all I have is an HttpRequestException.
With SocketsHttpHandler on iOS, I have options. I can subscribe to LocalCertificateSelectionCallback and listen for events, or I can check HttpRequestException's InnerException (of type Interop+AppleCrypto+SslException) gives me a specific libsecurity error code via HResult. I can check if it matches e.g. errSSLPeerBadCert (-9825) and prompt user for a client certificate.
With vanilla NSUrlSession I can look for challenges with AuthenticationMethodClientCertificate protection space.
But with NSUrlSessionHandler, this challenge is doomed to fail unless I pre-load a correct certificate ahead of time, and I end up with a fairly generic "connection lost" HttpRequestException:
I might be able to workaround this by e.g. falling back to SocketHttpHandler when I see that "network connection lost" error to double-check if this is a certificate challenge. But my life would be a lot easier if NSUrlSessionHandler itself could help detect a challenge, either by providing a client-certificate-selection callback, or by providing a more detailed error message.
P.S. I also made a similar request for SocketHttpHandler-on-Android in https://github.com/dotnet/runtime/issues/109532