alexrainman / ModernHttpClient

ModernHttpClient
MIT License
126 stars 27 forks source link

How to use a certificate with Public Key along with ModernHttpClient. #59

Closed rkshnair closed 4 years ago

rkshnair commented 4 years ago

I have a certificate with Public Key is installed in my Android App. I need to read the certificate and pass that with all the http requests.

I was able to read my certificate and key information using the below code. But how I can pass that information through ModernHttpClient for getting an HTTP request.

Please help.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Security;
using Java.Security;
using Java.Security.Cert;

namespace CertificateValidation.Droid
{
    public static class CertificateService
    {
        public async static Task ValidateDeviceCertificateAsync(Context context, string alias)
        {
            await Task.Run(() =>
           {
               ChoosePrivateKeyAlias((Activity)context, alias, (x, y) =>
               {
                   if (x is X509Certificate[] certificates && y is IPrivateKey privateKey)
                   {

                   }
               });
           });
        }

        #region Private Methods 
        /// <summary>
        /// Method to choose the private key alias from android Keychain
        /// </summary>
        /// <param name="context"></param>
        /// <param name="alias"></param>
        /// <param name="certificateCallback"></param>
        private static void ChoosePrivateKeyAlias(Activity context, string alias, Action<object, object> certificateCallback)
        {
            try
            {
                KeyChain.ChoosePrivateKeyAlias(context, new KeyChainAliasCallback(context, certificateCallback), null, null, null, -1, alias);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
        #endregion
    }

    public class KeyChainAliasCallback : Java.Lang.Object, IKeyChainAliasCallback
    {
        #region Private Declarations 
        /// <summary>
        /// Delegate for result callback
        /// </summary>
        Action<object, object> CallBack { get; set; }
        /// <summary>
        /// Calling activity 
        /// </summary>
        Activity RootActivity { get; set; }
        #endregion

        #region .ctor

        public KeyChainAliasCallback(Activity activity, Action<object, object> certificateCallback)
        {
            CallBack = certificateCallback;
            RootActivity = activity;
        }
        #endregion

        #region IKeyChainAliasCallback

        public void Alias(string alias)
        {
            if (!string.IsNullOrEmpty(alias))
            {
                X509Certificate[] certificate = GetCertificates(alias);
                IPrivateKey privateKey = GetPrivateKey(alias);
                CallBack.Invoke(certificate, privateKey);
            }
            else
            {
                CallBack.Invoke(null, null);
            }
        }
        #endregion

        #region Private Methods 
        /// <summary>
        /// Method to get the private key of the certificate
        /// </summary>
        /// <param name="alias"></param>
        /// <returns></returns>
        private IPrivateKey GetPrivateKey(string alias)
        {
            try
            {
                return KeyChain.GetPrivateKey(RootActivity, alias);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;

        }

        /// <summary>
        /// Method to fetch the certificate
        /// </summary>
        /// <param name="alias"></param>
        /// <returns></returns>
        private X509Certificate[] GetCertificates(string alias)
        {
            try
            {
                return KeyChain.GetCertificateChain(RootActivity, alias);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }
        #endregion
    }

}

image

stezma commented 4 years ago

I think only certificate pinning is supported. I am not sure.. @phdonnelly @alexrainman Can help.

alexrainman commented 4 years ago

First, you don't pass certificate with all the http requests.

Certificate validation happens during SSL handshake and, if everything goes as expected, private keys are interchanged between client and server so the data in the wire can be encrypted.

Including a certificate in the app is an outdated and not flexible practice. If the certificate expires, you will need to update your app.

Use the certificate public keys instead, which is the support provided in the plugin.

rafcabezas commented 4 years ago

@alexrainman I'm trying to understand, can you please explain why won't the public keys also be invalid when the certificate expires and a new one is generated?