0

I am trying to add client certificate whitch I am getting from this method:

    private X509Certificate[] GetCertificateChain(string alias)
    {
        try
        {
            return KeyChain.GetCertificateChain(this, alias);
        }
        catch (KeyChainException e)
        {

        }            

        return null;
    }

System.Net.Http.HttpClientHandler doesn't allow me to addclient certificate. NotImplemented exception is thrown. Any solution? Maybe other Http client?

Kacper
  • 620
  • 1
  • 7
  • 16
  • The piece of your code doesn't correspond to your description. Add more. Your HttpClient, how do you add your certificate, where the error is thrown, what exact error message looks like ... – OlegI Mar 07 '19 at 12:04
  • https://github.com/mono/mono/blob/5e08742b5c299c0503d11ea44d115c32a6b7c68f/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs#L414-L418 ClientCertificates method have only get method – Kacper Mar 07 '19 at 12:06
  • Can you try `handler.ClientCertificates.Add(cer);` ? Let me know if it works. – nevermore Mar 08 '19 at 06:41
  • Jack Hua, NotImplemented Exception is thrown – Kacper Mar 08 '19 at 07:29
  • See also [my answer here](https://stackoverflow.com/a/51051092/731183) – AlexS Mar 08 '19 at 10:18
  • byte[] pkcs12 is cert PrivateKey? – Kacper Mar 08 '19 at 10:32

1 Answers1

1

You need to extend AndroidClientHandler and override ConfigureCustomSSLSocketFactory

public class HttpsClientHandler : AndroidClientHandler
{
    private static readonly Logger LOG = LogManager.GetLogger();

    private SSLContext sslContext;
    private readonly ITrustManager[] trustManagers;
    private IKeyManager[] keyManagers = null;

    public HttpsClientHandler() : base()
    {
        trustManagers = GetTrustManagers();
        sslContext = GetSSLContext();
    }

    private SSLContext GetSSLContext()
    {
        string protocol;
        if (SslProtocols == SslProtocols.Tls11)
        {
            protocol = "TLSv1.1";
        } else if (SslProtocols == SslProtocols.Tls || SslProtocols == SslProtocols.Tls12)
        {
            protocol = "TLSv1.2";
        } else
        {
            throw new IOException("unsupported ssl protocol: " + SslProtocols.ToString());
        }
        SSLContext ctx = SSLContext.GetInstance(protocol);
        ctx.Init(keyManagers, trustManagers, null);
        return ctx;
    }

    public new SslProtocols SslProtocols { get; set; } = SslProtocols.Tls12;

    public void SetClientCertificate(byte[] pkcs12, char[] password)
    {
        keyManagers = GetKeyManagersFromClientCert(pkcs12, password);
        SSLContext newContext = GetSSLContext();
        sslContext = newContext;
    }

    private ITrustManager[] GetTrustManagers()
    {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
        trustManagerFactory.Init((KeyStore)null);
        return trustManagerFactory.GetTrustManagers();
    }

    private IKeyManager[] GetKeyManagersFromClientCert(byte[] pkcs12, char[] password)
    {
        if (pkcs12 != null)
        {
            using (MemoryStream memoryStream = new MemoryStream(pkcs12))
            {
                KeyStore keyStore = KeyStore.GetInstance("pkcs12");
                keyStore.Load(memoryStream, password);
                KeyManagerFactory kmf = KeyManagerFactory.GetInstance("x509");
                kmf.Init(keyStore, password);
                return kmf.GetKeyManagers();
            }
        }
        return null;
    }

    protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
    {
        SSLSocketFactory socketFactory = sslContext.SocketFactory;
        if (connection != null)
        {
            connection.SSLSocketFactory = socketFactory;
        }
        return socketFactory;
    }
}
AlexS
  • 5,295
  • 3
  • 38
  • 54
  • byte[] pkcs12 is value of PrivateKey? – Kacper Mar 08 '19 at 10:25
  • I test set certificate with client.badssl.com page and this doesn't work – Kacper Mar 08 '19 at 14:38
  • @K. Kempski The code is a snippet of one of my programms. The original code also supports custom CAs and worked fine when I last tested it. So if you have problems using it, you should add updates to your question describing what you did and what the result was. – AlexS Mar 09 '19 at 23:04
  • Just tell me whai is byte[] pkcs12? Raw cert data what is encrypted or what? – Kacper Mar 10 '19 at 11:39
  • It is the raw bytes of a pkcs1.2 keystore containing THW certificate and private key. The underlying implementation of the http protocol will choose the right certificate according to SSL handshake. – AlexS Mar 11 '19 at 19:20
  • this is useful once you have the certificate. But how to read the certifictae from thr user certificates in the first place.? A separate question i know. – phil soady Mar 05 '20 at 23:52