2012-06-01 30 views
4

这件事一直在困扰我几天。我读过关于整个问题的很多其他问题,但仍然无法继续。如何在Android中使用自签名SSL证书

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

首先,我使用openssl为我的服务器创建了一个测试密钥和测试证书。然后我一直遵循Crazy Bob's blog中显示的说明。我从Bouncy Castle的网站直接获得了Bouncy Castle提供商,创建了一个可信的密钥库,如Crazy Bob的博客所示,并且我相信这一切都正确。

当我试图运行我的代码时,出现异常“IOException:密钥存储区的版本错误”。然后我在StackOverflow上找到了this question。在那里有人建议我应该尝试使用旧的充气城堡供应商,而不是最新的bcprov-jdk15on-147.jar。我继续记住这一点,并最终尝试了从jdk13-146到jdk16-146的每个bcprovider。每次我仍然得到相同的“IOExcpetion:密钥存储的错误版本”。例外。

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

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

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

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

+0

如果您将目标API移动到类似10或14的东西,它是否会开始工作?在处理较旧的API级别时,测试较新的API并不是一个坏主意,只是为了确保它不是兼容性问题。 – matt5784

+0

我需要为大脑树的Android项目创建“.pem”文件。我安装了openssl并运行以下命令:openssl> s_client -connect $ https://xxx.xxx.xx:443 2>&1 | \ sed -ne'/ -BEGIN CERTIFICATE - /,/ - END CERTIFICATE-/p'> mycert.pem 但我在s_client中出错。请帮帮我。我从Crazy Bob的博客得到命令。 –

回答

0

当我试图向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库。你可以尝试一下。
另一种工具来创建密钥库:http://portecle.sourceforge.net/

+0

感谢您的链接,但仍无法克服“密钥存储区的错误版本”异常。 – zaplec

+0

@zaplec:我已经更新了我的答案 – R4j

+0

我不确定我是否真的明白了你在第一行所做的事情,因为在我看来,你从未使用过在此创建的PEM。你能解释一下吗?否则,你的解决方案看起来很像我试过的。我试过bcprov-jdk16-145.jar(加上其他版本)和openssl。 – zaplec

2

2个选择:

  1. 你可以做你做什么,并创建自己的密钥存储和我已经做了,这里是从我的代码指令我存储(因为它是如此耗费时间得到它的工作):

    要生成PKS:

    1. 在IIS7然后EXP创建证书orted作为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 我在我的服务器 1c上使用端口8181。从IIS管理器导出到cert.pfx
    2. 运行命令行中的SSL,以文件转换成X.509: OpenSSL的PKCS12 -in C:\ cert.pfx退房手续C:\ cert.cer -nodes
    3. 编辑文件并删除所有除了----- BEGIN .... END CERTIFICATE -----重要!它正在工作,当我得到适当的(5)破折号并将标签和数据放在不同的行上时
    4. 使用keytool。 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. 建立信任所有密钥库和忘掉这一切。基本上,您可以使用任何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); 
    } 
    
+0

如果我使用TRUST ALL选项,是否意味着我的应用程序是唯一一个信任所有网站的应用程序?换句话说,我只是想确保它不会以任何方式影响手机上的其他应用程序。我的应用程序使用的URL是硬编码的,因为它永远不会更改,因此允许应用程序信任所有站点可能是安全的,因为它永远不会尝试连接到某个“不受信任”的站点。 – zaplec

+0

是的,您只会将其设置为信任此特定连接的所有证书。其他应用程序不会受到影响 – katit

+0

此信任所有解决方案的工作原理,但它可能使应用程序仍然容易受到中间人攻击。出于测试目的,这是可以的,但我认为我需要继续争取让SSL工作只有一个受信任的站点:) – zaplec

0

嗯,我也面临这个同样的情况,并解决它,我花了帮助,从相同的博客文章(http://nelenkov.blogspot.in/2011/12/using-custom-certificate-trust-store-on.html)简称通过R4j。以下是相关的步骤:

  1. 创建自定义trustore:我用Portecle创建从我的服务器密钥库和进口的公钥证书进去。
  2. 创建密钥对定制密钥库:密钥工具-genkeypair -alias样品-keyalg RSA -sigalg SHA1withRSA -dname“CN =戒灵,OU =攻击,O =索伦企业,L =魔多,ST =中间地球,C = ME“-keypass welcome123 -validity 365 -storetype pkcs12 -keystore g:\ mordor_key_store.pfx -storepass welcome123 -keyize 2048
  3. 然后,您使用它们,如nelkov的博客中所述。您可能还需要创建自己的自定义AbstractVerifier的情况下,你的土地到那里证书为abc.com颁发的形势和验证拒绝www.abc.com
  4. 最后创建安全了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我选择的详细原因。