【问题标题】:How to use a self signed SSL certificate in Android如何在 Android 中使用自签名 SSL 证书
【发布时间】:2012-06-01 13:45:45
【问题描述】:

这几天一直困扰着我。我已经阅读了很多关于整个问题的其他问题,但仍然无法继续。

我创建了一个简单的测试应用程序,只是为了在 Android 上测试 SSL。该应用程序只有一个按钮,当单击该按钮时,应用程序会尝试通过 SSL 加密连接向我的测试服务器发送“Hello World”,然后它会以完全相同的短语进行响应。

首先,我使用 openssl 为我的服务器创建了一个测试密钥和测试证书。然后我一直按照Crazy Bob's blog 中的说明进行操作。我直接从 Bouncy Castle 的网站获得了 Bouncy Castle 提供程序,创建了一个受信任的密钥库,如 Crazy Bob 的博客上所示,我相信那时一切都正确。

当我尝试运行我的代码时,我收到了异常“IOException:密钥库版本错误”。然后我在 StackOverflow 上找到了this question。有人建议我应该尝试使用较旧的 Bouncy Castle Providers 而不是最新的 bcprov-jdk15on-147.jar。我继续考虑这一点,实际上最终尝试了从 jdk13-146 到 jdk16-146 的每个 bcpprovider。仍然每次我得到相同的“IOExcpetion:错误版本的密钥库”。例外。

然后我在 StackOverflow 上找到了 yet another question 关于类似问题的信息。有人设法通过使用 512 位大小的密钥而不是 1024 位大小的密钥来摆脱该异常。好吧,我试了一下,什么也没做,但同样的例外。

所以我现在在这里,想知道下一步该做什么。我的想法和谷歌搜索结果几乎用完了。

我的网络代码是疯狂鲍勃代码的一对一副本,除此之外,应用程序只有处理按钮的活动类。我正在尝试在 API 级别 7 上实现这一点。

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 如果您将目标 API 移动到 10 或 14 之类的东西,它会开始工作吗?在使用较旧的 API 级别时,为了确保它不是兼容性问题,在较新的 API 级别上进行测试并不是一个坏主意。
  • 我需要为大脑树的 Android 项目创建“.pem”文件。我安装了 openssl 并运行以下 cmd: openssl> s_client -connect $xxx.xxx.xx:443 2>&1 | \ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem 但在 s_client 中出现错误。请帮我。我从 Crazy Bob 的博客中得到命令。

标签: java android ssl https android-networking


【解决方案1】:

2 个选择:

  1. 你可以做你想做的事并创建你自己的密钥库,我已经做到了,这是我存储的代码中的说明(因为让它工作非常耗时):

    要生成 PKS:

    1. 在 IIS7 中创建了证书,然后导出为 pfx。遵循 SelfSSL 上的说明:http://www.robbagby.com/iis/self-signed-certificates-on-iis-7-the-easy-way-and-the-most-effective-way/ 1a。下载工具:http://cid-3c8d41bb553e84f5.skydrive.live.com/browse.aspx/SelfSSL 1b。运行:SelfSSL /N:CN=mydomainname /V:1000 /S:1 /P:8081 我在我的服务器上使用端口 8181 1c。从 IIS 管理器导出到 cert.pfx
    2. 在 SSL 中运行命令行将文件转换为 X.509: openssl pkcs12 -in C:\cert.pfx -out C:\cert.cer -nodes
    3. 编辑文件并删除所有文件,除了 -----BEGIN.... END CERTIFICATE----- 重要!当我得到适当的(5)个破折号并将标签和数据放在单独的行上时,它就可以工作了
    4. 使用密钥工具。 C:\Java\JDK\bcprov.jar 是单独下载的 C:\Users>keytool -import -v -trustcacerts -alias key_alias -file C:\cert.cer -keystore C:\mystore.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\ Java\JDK\bcprov.jar -storepass 123456
  2. 创建 TRUST ALL KeyStore 并忘记这一切。基本上,您可以使用任何 SSL 而不会出错。如果您真的关心,只需在生产中禁用它。这是我用来准备 SSL 客户端的代码(假设您使用 Apache Http 客户端)

    private HttpClient getHttpClient()
    {
        HttpParams params = new BasicHttpParams();
    
        //Set main protocol parameters
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);
    
        // Turn off stale checking.  Our connections break all the time anyway, and it's not worth it to pay the penalty of checking every time.
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        // FIX v2.2.1+ - Set timeout to 30 seconds, seems like 5 seconds was not enough for good communication
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
        HttpConnectionParams.setSoTimeout(params, 30 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
    
        // Don't handle redirects -- return them to the caller.  Our code often wants to re-POST after a redirect, which we must do ourselves.
        HttpClientParams.setRedirecting(params, false);
    
        // Register our own "trust-all" SSL scheme
        SchemeRegistry schReg = new SchemeRegistry();
        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
    
            TrustAllSSLSocketFactory sslSocketFactory = new TrustAllSSLSocketFactory(trustStore);
            sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            Scheme sslTrustAllScheme = new Scheme("https", sslSocketFactory, 443);
            schReg.register(sslTrustAllScheme);
        }
        catch (Exception ex)
        {
            LogData.e(LOG_TAG, ex, LogData.Priority.None);
        }
    
        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
        return new DefaultHttpClient(conMgr, params);
    }
    

【讨论】:

  • 如果我使用 TRUST ALL 选项,是否意味着我的应用程序是唯一信任所有网站的应用程序?换句话说,我只是想确保它不会以任何方式影响手机上的其他应用程序。我的应用程序使用的 URL 是硬编码的,因为它永远不会更改,因此允许应用程序信任所有站点可能是安全的,因为它永远不会尝试连接到某些“不受信任”的站点。
  • 是的,您只需将其设置为信任此特定连接的所有证书。其他应用不受影响
  • 这种信任所有解决方案都有效,但它使可能的应用程序仍然容易受到中间人攻击。出于测试目的,它没问题,但我认为我需要继续努力让 SSL 仅在一个受信任的站点上工作:)
  • 我在 #1 中给了你指示。它对我有用。后来我转向信任,因为中间的男人对我来说不是问题
  • 是的,我检查了您在 #1 处的说明,但即使我按照您提供的说明进行操作,我仍然收到“错误版本的密钥库”异常。我将更改为 Java 1.6 或 Java 1.5 并重试,因为到目前为止我一直在使用 Java 1.7。希望这会有所帮助。
【解决方案2】:

当我尝试向 EWS 请求时,它类似于 my question。您可以参考this link 并下载example source code 然后像我的回答一样修改它。希望这会有所帮助!

更新
以下命令对我有用(我大约 2 个月前尝试过):

  C:\OpenSSL-Win32\bin>keytool -importcert -v -trustcacerts -file "d:/cer.cer" 
  -alias parkgroup_restful -keystore "D:/parkgroup-ws-client.bks" 
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath 
 "D:/bcprov-jdk16-145.jar" -storetype BKS -storepass 1234567

  .... /**It should show the result here**/

   Trust this certificate? [no]:  yes
   Certificate was added to keystore
   [Storing D:/parkgroup-ws-client.bks]

   C:\OpenSSL-Win32\bin>keytool -list -keystore "D:/parkgroup-ws-client.bks" -provi
   der org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "D:/bcprov-
   jdk16-145.jar" -storetype BKS -storepass 1234567

   Keystore type: BKS
   Keystore provider: BC

   Your keystore contains 1 entry

   parkgroup_restful, Apr 10, 2012, trustedCertEntry,
   Certificate fingerprint (MD5): 36:47:88:62:23:1C:F3:52:17:BE:7A:A9:94:56:19:18

你可以看到,我使用 bcprov-jdk16-145.jar 和 openssl lib。你可以试试。
另一个创建密钥库的工具:http://portecle.sourceforge.net/

【讨论】:

  • 感谢您的链接,但仍然无法克服“密钥库版本错误”异常。
  • 我不确定我是否真的明白你在第一行所做的事情,因为在我看来你从来没有使用过你在那里创建的 PEM。你能解释一下吗?否则,您的解决方案看起来很像我尝试过的。我也尝试过 bcprov-jdk16-145.jar(以及其他版本)和 openssl。
  • 我建议您检查您的证书文件,因为我遇到了与您相同的问题。然后我尝试使用另一个文件,它起作用了。
【解决方案3】:

我也遇到过同样的情况,为了解决这个问题,我从 R4j 引用的同一篇博文 (http://nelenkov.blogspot.in/2011/12/using-custom-certificate-trust-store-on.html) 中获得了帮助。以下是所涉及的步骤:

  1. 创建自定义信任库:我使用 Portecle 创建了一个密钥库并将公钥证书从我的服务器导入到其中。
  2. 使用密钥对创建自定义密钥库:keytool -genkeypair -alias sample -keyalg RSA -sigalg SHA1withRSA -dname "CN=Nazgul, OU=Assault, O=Sauron Enterprises, L=Mordor, ST=Middle Earth, C=ME" -keypass welcome123 -validity 365 -storetype pkcs12 -keystore g:\mordor_key_store.pfx -storepass welcome123 -keysize 2048
  3. 然后您可以按照 nelkov 的 博客中的说明使用它们。您可能还需要创建自己的自定义 AbstractVerifier,以防遇到为 abc.com 颁发证书而验证器拒绝 www.abc.com
  4. 的情况
  5. 最后,要创建安全的 HTTPClient,您可以执行以下操作:

            public static DefaultHttpClient getSecureHttpClient(){
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        SSLContext sslContext = null;
        try {
            sslContext = createSslContext(true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        final X509HostnameVerifier delegate = new BrowserCompatHostnameVerifier();
        MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, delegate);
        schemeRegistry.register(new Scheme("https", socketFactory, 443));
    
        DefaultHttpClient client = new DefaultHttpClient();
        HttpParams params = client.getParams();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params){
            protected HttpParams determineParams(HttpRequest req) {
                HttpParams params = req.getParams(); // req is an HttpRequest object
                HttpConnectionParams.setSoTimeout(params, 60000);
                HttpConnectionParams.setConnectionTimeout(params, 60000);
                return params;
            }
        };
    
        return client;
    }
    

我选择的详细原因可以参考这个帖子http://fuking-android.quora.com/Implement-HTTPS-for-android-apps-a-novices-tale

【讨论】:

    猜你喜欢
    • 2020-10-25
    • 2021-09-29
    • 2011-03-15
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    • 2016-12-04
    相关资源
    最近更新 更多