client certificate with NSUrlSessionDelegate in xamarin

Multi tool use
Multi tool use


client certificate with NSUrlSessionDelegate in xamarin



I want to implement client certificate authentication in my xamarin app.
On top of that I am using a custom Certificate Authority (CA) and TLS 1.2.



Until now I managed to get it running using android, UWP and WPF. The only platform missing is ios.



Here is my NSUrlSessionDelegate:


public class SSLSessionDelegate : NSUrlSessionDelegate, INSUrlSessionDelegate
{
private NSUrlCredential Credential { get; set; }
private SecIdentity identity = null;
private X509Certificate2 ClientCertificate = null;

private readonly SecCertificate CACertificate = null;

public SSLSessionDelegate(byte caCert) : base()
{
if (caCert != null)
{
CACertificate = new SecCertificate(new X509Certificate2(caCert));
}
}

public void SetClientCertificate(byte pkcs12, char password)
{
if (pkcs12 != null)
{
ClientCertificate = new X509Certificate2(pkcs12, new string(password));
identity = SecIdentity.Import(ClientCertificate);

SecCertificate certificate = new SecCertificate(ClientCertificate);
SecCertificate certificates = { certificate };

Credential = NSUrlCredential.FromIdentityCertificatesPersistance(identity, certificates, NSUrlCredentialPersistence.ForSession);
}
else
{
ClientCertificate = null;
identity = null;
Credential = null;
}
}

public override void DidReceiveChallenge(NSUrlSession session, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodClientCertificate)
{
NSUrlCredential c = Credential;
if (c != null)
{
completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.UseCredential, c);
return;
}
}

if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust)
{
SecTrust secTrust = challenge.ProtectionSpace.ServerSecTrust;
secTrust.SetAnchorCertificates(new SecCertificate {
CACertificate
});
secTrust.SetAnchorCertificatesOnly(true);

}
completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null);
}
}



This works if no client certificate is configured DidReceiveChallenge is called once with AuthenticationMethodServerTrust and the custom CA is accepted.


DidReceiveChallenge


AuthenticationMethodServerTrust



But as soon as a client certificate is configured DidReceiveChallenge gets called 4 times (twice for each AuthenticationMethod) and I am getting NSURLErrorDomain (-1200) error.


DidReceiveChallenge


AuthenticationMethod


NSURLErrorDomain (-1200)



Anyone any idea what I am doing wrong?



The SSLSessionDelegate is used like this:


SSLSessionDelegate


public class HttpsServer : AbstractRemoteServer, IRemoteServer
{
private static readonly Logger LOG = LogManager.GetLogger();

private SSLSessionDelegate sSLSessionDelegate;

private NSUrlSession session;

private NSUrl baseAddress;

public HttpsServer()
{
sSLSessionDelegate = new SSLSessionDelegate(SSLSupport.GetTruststoreRaw());
NSUrlSessionConfiguration configuration = NSUrlSessionConfiguration.DefaultSessionConfiguration;
configuration.HttpShouldSetCookies = true;
configuration.TimeoutIntervalForRequest = 30;
configuration.TLSMinimumSupportedProtocol = SslProtocol.Tls_1_2;
configuration.TimeoutIntervalForResource = 30;
NSMutableDictionary requestHeaders;
if (configuration.HttpAdditionalHeaders != null)
{
requestHeaders = (NSMutableDictionary)configuration.HttpAdditionalHeaders.MutableCopy();
}
else
{
requestHeaders = new NSMutableDictionary();
}
AppendHeaders(requestHeaders, SSLSupport.GetDefaultHeaders());
configuration.HttpAdditionalHeaders = requestHeaders;

session = NSUrlSession.FromConfiguration(configuration, (INSUrlSessionDelegate)sSLSessionDelegate, NSOperationQueue.MainQueue);
baseAddress = NSUrl.FromString(SSLSupport.GetBaseAddress());
}

public void SetClientCertificate(byte pkcs12, char password)
{
sSLSessionDelegate.SetClientCertificate(pkcs12, password);
}

public override async Task<string> GetString(string url, Dictionary<string, string> headers, CancellationToken cancellationToken)
{
NSData responseContent = await GetRaw(url, headers, cancellationToken);
return NSString.FromData(responseContent, NSStringEncoding.UTF8).ToString();
}

private async Task<NSData> GetRaw(string url, Dictionary<string, string> headers, CancellationToken cancellationToken)
{
NSMutableUrlRequest request = GetRequest(url);
request.HttpMethod = "GET";
request.Headers = AppendHeaders(request.Headers, headers);

Task<NSUrlSessionDataTaskRequest> taskRequest = session.CreateDataTaskAsync(request, out NSUrlSessionDataTask task);
cancellationToken.Register(() =>
{
if (task != null)
{
task.Cancel();
}
});
try
{
task.Resume();
NSUrlSessionDataTaskRequest taskResponse = await taskRequest;
if (taskResponse == null || taskResponse.Response == null)
{
throw new Exception(task.Error.Description);
}
else
{
NSHttpUrlResponse httpResponse = (NSHttpUrlResponse)taskResponse.Response;
if (httpResponse.StatusCode == 303)
{
if (!httpResponse.AllHeaderFields.TryGetValue(new NSString("Location"), out NSObject locationValue))
{
throw new Exception("redirect received without Location-header!");
}
return await GetRaw(locationValue.ToString(), headers, cancellationToken);
}
if (httpResponse.StatusCode != 200)
{
throw new Exception("unsupported statuscode: " + httpResponse.Description);
}
return taskResponse.Data;
}
}
catch (Exception ex)
{
throw new Exception("communication exception: " + ex.Message);
}
}
}



And here my Info.plist


Info.plist


<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>XXXXXXXXXX</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>



Looking for an answer drawing from credible and/or official sources.



Other ways of implementing client certificates in Xamarin.IOS are also welcome.









By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

LW naNq siQT70H4L,VUGtFlxbPUB5r5lDHE854yYwm0rqg5dMlf,3jQrmQQdh,o41ePhMs8Q5 ii3FRN 3nXTaa
N8Xhm8jf

Popular posts from this blog

Rothschild family

Boo (programming language)