Android和客户端证书 [英] Android and Client Certificates

查看:122
本文介绍了Android和客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经搜索了几周,似乎无法在任何地方找到答案。我正在尝试为Android执行以下操作。该代码来自我编写的C#应用​​程序,但正在将其移植到Android。 Web端点要求将证书附加到相互身份验证的请求上,以进行Web服务调用。

I have been searching for this for a few weeks and can't seem to find an answer anywhere. I am trying to do the following for Android. This code is from a C# app I wrote but am porting it to Android. The web endpoint requires a cert to be attached to the request for mutual authentication to make the web service call.

        string certThumbprint = "E1313F6A2D770783868755D016CE748F6A9B0028";
        X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        try
        {
            certStore.Open(OpenFlags.ReadOnly);
        }
        catch (Exception e)
        {
            if (e is CryptographicException)
            {
                Console.WriteLine("Error: The store is unreadable.");
            }
            else if (e is SecurityException)
            {
                Console.WriteLine("Error: You don't have the required permission.");
            }
            else if (e is ArgumentException)
            {
                Console.WriteLine("Error: Invalid values in the store.");
            }
            else
            {
                throw;
            }
        }
        X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false);
        certStore.Close();
        if (0 == certCollection.Count)
        {
            throw new Exception("Error: No certificate found containing thumbprint " + certThumbprint);
        }
        X509Certificate2 certificate = certCollection[0];
        return certificate;

我正在这样做(请求是HttpWebRequest):

I am then doing this (request is an HttpWebRequest):

request.ClientCertificates.Add(cert);

这在C#中效果很好,但是当我转到Android时,却收到找不到文件 getInputStream()调用时出错。这是我的Android代码:

This works fine in C# however when I move to Android I'm getting a "file not found" error on the getInputStream() call. Here is my Android code:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

        StrictMode.setThreadPolicy(policy);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        InputStream caInput = new BufferedInputStream(new FileInputStream("/sdcard/Certificate.pfx"));
        KeyHelper kh = new KeyHelper();
        Certificate ca = kh.GetKey("Password");
        String keyStoreType = KeyStore.getDefaultType();
        keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, "Password".toCharArray());
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(kmf.getKeyManagers(),null,new SecureRandom());
        HttpsURLConnection urlConnection =
                (HttpsURLConnection)url.openConnection();
        urlConnection.setRequestProperty("x-ms-version",AZURE_REST_VERSION);
        urlConnection.setDoInput(true);
        urlConnection.setDoOutput(true);
        urlConnection.setRequestMethod("GET");
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        urlConnection.connect();

        InputStream in = new BufferedInputStream(urlConnection.getInputStream()); //<-----Blows up here

    } catch (KeyStoreException e) {
        throw new KeyStoreException("Keystore Exception",e);
    } catch (NoSuchAlgorithmException e) {
        throw new NoSuchAlgorithmException("Algorithm exception",e);
    } catch (KeyManagementException e) {
        throw new KeyManagementException("Key Exception", e);
    }

我试图将提琴手放在仿真器和端点之间,然后返回一个200。我认为这是因为我的证书在我的开发机器上的本地私有商店中。有什么想法吗?

I tried to put fiddler between the emulator and the endpoint and it comes back with a 200. I think this is because my cert is in my local private store on my dev machine. Any thoughts?

推荐答案

好。我找到了答案。问题在于,自签名证书必须存在于android TrustStore中才能使用。但是,默认的TrustStore在应用启动后为只读,因此很难对其进行修改。我正在建立自己的自定义信任库,但是根证书不是其中的一部分,因此调用任何https都将失败。解决方案来自此博客文章:

OK. I found the answer to this one. The issue lies in that the self signed cert can't be used until it exists in the android TrustStore. However the default TrustStore is read-only after an app starts so it's hard to modify it. I was setting up my own custom trust store, however the root certs were not part of it, so calls out to any https would fail. The solution came from this blog post:

http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html

长话短说,设置一个包含自签名证书的自定义TrustStore,然后从默认信任库中导出所有证书并将其导入到自定义信任库中。然后,使用该信任库来设置您的SSL上下文(还需要使用自定义密钥库,因为客户端证书也需要附加到请求中)。我相信,如果我不允许自签名证书,那也没什么大不了的,因为客户端证书的根证书将存在于默认的TrustStore中(或者至少希望如此)。

Long story short, setup a custom TrustStore that contains the self signed cert, then export all the certificates from the default trust store and import them into the custom trust store. Then use that trust store to setup your SSL Context (also need to use a custom keystore since the client certificate needs to be attached to the request as well). I believe if I would not allow self signed certs this wouldn't be a big deal as the root cert for the client certificate would exist in the default TrustStore (or at least I hope it would).

这篇关于Android和客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆