Связь SSL с клиентским сертификатом с использованием Xamarin Android - PullRequest
1 голос
/ 17 октября 2019

Я создаю корпоративное приложение, в котором решение MDM Организации установит клиентский сертификат на устройстве. Я пытался прочитать то же самое, используя приведенный ниже код, но мое соединение с сервером не устанавливается.

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();
}   

Я использую приведенный ниже код для чтения секретного ключа и сертификата.

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;

}

Я также попытался сделать то же самое с WebView, передав сертификат и ключ с помощью OnReceivedClientCertRequest и который работает нормально.

 public override void OnReceivedClientCertRequest(WebView view, ClientCertRequest request)
 {
     request.Proceed(PPritvateKey, CCertificate);
 }

Не могли бы вы помочь выяснить, что не так в моем коде.

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Вы не настроили фабрику диспетчера доверия и какой стажер влияет на запрос вызова. Попробуйте это

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();
}
1 голос
/ 18 октября 2019

Вы можете использовать URLConnection.Connect Method(), чтобы открыть соединение с ресурсом.

urlConnection.Connect();

Для получения дополнительной информации, пожалуйста, обратитесь по ссылке ниже.

URLConnection.Connect Method: https://docs.microsoft.com/en-us/dotnet/api/java.net.urlconnection.connect?view=xamarin-android-sdk-9#Java_Net_URLConnection_Connect

URL.openConnection Примеры: https://csharp.hotexamples.com/examples/-/URL/openConnection/php-url-openconnection-method-examples.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...