I am creating an enterprise application, in which the Organization's MDM solution will install a client certificate on the device. I tied to read the same using the below code but my connection is not get established with the server.
if (x is X509Certificate[] certificates && y is IPrivateKey privateKey)
{
var keyStore = KeyStore.GetInstance("PKCS12");
keyStore.Load(null, null);
var keyFactory = KeyFactory.GetInstance(privateKey?.Algorithm);
keyStore.SetKeyEntry(alias, privateKey, null, certificates);
var kmf = KeyManagerFactory.GetInstance(KeyManagerFactory.DefaultAlgorithm);
kmf.Init(keyStore, null);
var sslContext = SSLContext.GetInstance("TLS");
sslContext.Init(kmf.GetKeyManagers(), null, null);
var sslSocketFactory = sslContext.SocketFactory;
var sslSocket = (SSLSocket)sslSocketFactory.CreateSocket(new Socket(hostName, port), hostName, port, false);
sslSocket.AddHandshakeCompletedListener(new HandshakeCompletedListener());
sslSocket.NeedClientAuth = true;
sslSocket.KeepAlive = true;
sslSocket.StartHandshake();
var uri = new URL("https://apiapp-iserver.ase-meap-dev.p.azurewebsites.net/api/CertificateLogin");
var urlConnection = (HttpsURLConnection)uri.OpenConnection();
var status = urlConnection.ResponseCode;
if (status == HttpStatus.Forbidden)
{
var errorStream = urlConnection.ErrorStream;
var errorResult = ReadStream(errorStream);
}
urlConnection.SSLSocketFactory = sslContext.SocketFactory;
var inputStream = urlConnection.InputStream;
var loResponseStream = new StreamReader(inputStream);
var response = loResponseStream.ReadToEnd();
}
I am using the below code to read the private key and certificate.
private X509Certificate[] GetCertificates(string alias)
{
try
{
return KeyChain.GetCertificateChain(RootActivity, alias);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return null;
}
private IPrivateKey GetPrivateKey(string alias)
{
try
{
return KeyChain.GetPrivateKey(RootActivity, alias);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return null;
}
I also tried the same with WebView by passing the certificate and key with OnReceivedClientCertRequest and which is working fine.
public override void OnReceivedClientCertRequest(WebView view, ClientCertRequest request)
{
request.Proceed(PPritvateKey, CCertificate);
}
Could you please help to figure out what is wrong in my code.
You haven't configured the trust manager factory and which intern affecting the request call. Try this
if (x is X509Certificate[] certificates && y is IPrivateKey privateKey)
{
var keyStore = KeyStore.GetInstance("PKCS12");
keyStore.Load(null, null);
var keyFactory = KeyFactory.GetInstance(privateKey?.Algorithm);
keyStore.SetKeyEntry(alias, privateKey, null, certificates);
var kmf = KeyManagerFactory.GetInstance(KeyManagerFactory.DefaultAlgorithm);
kmf.Init(keyStore, null);
KeyStore serverKeysStore = KeyStore.GetInstance("AndroidCAStore");
serverKeysStore.Load(null, null);
var serverTrustManagerFactory = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
serverTrustManagerFactory.Init(serverKeysStore);
var tms = serverTrustManagerFactory.GetTrustManagers();
var sslContext = SSLContext.GetInstance("TLS");
sslContext.Init(kmf.GetKeyManagers(), serverTrustManagerFactory.GetTrustManagers(), new SecureRandom());
HttpsURLConnection.DefaultSSLSocketFactory = sslContext.SocketFactory;
var sslSocketFactory = sslContext.SocketFactory;
var sslSocket = (SSLSocket)sslSocketFactory.CreateSocket(new Socket(hostName, port), hostName, port, false);
sslSocket.AddHandshakeCompletedListener(new HandshakeCompletedListener());
sslSocket.NeedClientAuth = true;
sslSocket.KeepAlive = true;
sslSocket.StartHandshake();
var uri = new URL("https://apiapp-iserver.ase-meap-dev.p.azurewebsites.net/api/CertificateLogin");
var urlConnection = (HttpsURLConnection)uri.OpenConnection();
var status = urlConnection.ResponseCode;
if (status == HttpStatus.Forbidden)
{
var errorStream = urlConnection.ErrorStream;
var errorResult = ReadStream(errorStream);
}
urlConnection.SSLSocketFactory = sslContext.SocketFactory;
var inputStream = urlConnection.InputStream;
var loResponseStream = new StreamReader(inputStream);
var response = loResponseStream.ReadToEnd();
}