Android和客户端证书

时间:2013-12-23 17:00:33

标签: android ssl-certificate httpclient x509certificate client-certificates

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

        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):

request.ClientCertificates.Add(cert);

这在C#中运行良好但是当我转移到Android时,我找不到"文件未找到" getInputStream()调用时出错。这是我的Android代码:

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

我试图将fiddler放在模拟器和端点之间,它返回200.我认为这是因为我的证书在我的dev机器上的本地私人商店中。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

行。我找到了这个答案。问题在于自签名证书在android TrustStore中存在之前无法使用。但是,默认的TrustStore在应用程序启动后是只读的,因此很难对其进行修改。我正在设置自己的自定义信任存储,但根证书不属于它,因此调用任何https都会失败。解决方案来自这篇博文:

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

简而言之,设置包含自签名证书的自定义TrustStore,然后从默认信任库导出所有证书并将其导入自定义信任库。然后使用该信任库来设置SSL上下文(还需要使用自定义密钥库,因为客户端证书也需要附加到请求)。我相信如果我不允许自签名证书这将不会是一个大问题,因为客户端证书的根证书将存在于默认的TrustStore中(或者至少我希望它会存在)。

答案 1 :(得分:0)

此外,您永远不应该对路径进行硬编码:

 InputStream caInput = new BufferedInputStream(new FileInputStream("/sdcard/Certificate.pfx"));

改为使用:

 Environment.getExternalStorageDirectory()

看看这个:http://developer.android.com/training/basics/data-storage/files.html

也用于证书 看看这个:Using a self-signed certificate to create a secure client-server connection in android