java 使用 URL.openConnection() 建立 HTTPS 连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14114480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Making an HTTPS connection using URL.openConnection()
提问by Deanna
I'm trying to make an HTTPS connection to a serverthat has a certificate set to expire in April 2013 and uses GlobalSign as the root certificate.
我正在尝试与服务器建立 HTTPS 连接,该服务器的证书设置为 2013 年 4 月到期,并使用 GlobalSign 作为根证书。
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
// urlConnection.setSSLSocketFactory(sslSocketFactory);
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
// Send the POST data
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(postParamString.toString().getBytes("UTF8"));
// Read the reply
InputStream in = urlConnection.getInputStream();
As it stands, this throws javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
when getOutputStream()
is called.
就目前而言,这会javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
在getOutputStream()
调用时抛出。
This same site and certificate are valid in the stock HTC web browser and desktop browsers. When I use the same code to access Googleit works (but then complains about a 404 error). Various posts on StackOverflow imply that it should "just work" and others say to set up your own key store (or disable all HTTPS validation!) I assume the difference in behaviour is down to different root key stores in use (Can anyone clarify this?).
这个相同的站点和证书在股票的 HTC 网络浏览器和桌面浏览器中有效。当我使用相同的代码访问Google 时,它可以工作(但随后会抱怨 404 错误)。StackOverflow 上的各种帖子暗示它应该“正常工作”,而其他人则说要设置自己的密钥库(或禁用所有 HTTPS 验证!) ?)。
I've now tried creating a key store using bouncy castle but I can't get this to load on my device.
我现在尝试使用充气城堡创建一个密钥存储,但我无法将其加载到我的设备上。
After exporting the certificate from Firefox, I create a key store using:
从 Firefox 导出证书后,我使用以下命令创建了一个密钥库:
keytool.exe -import -alias onlinescoutmanager -file www.onlinescoutmanager.co.uk.crt -storetype BKS -keystore res\raw\keystore
This is then loaded and used in the application using:
然后使用以下方法加载并在应用程序中使用:
InputStream stream = context.getResources().openRawResource(R.raw.keystore);
// BKS seems to be the default but we want to be explicit
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(stream, "www.onlinescoutmanager.co.uk".toCharArray());
stream.close();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
SSLContext context2 = SSLContext.getInstance("TLS");
context2.init(null, new TrustManager[] { defaultTrustManager }, null);
sslSocketFactory = context2.getSocketFactory();
This is failing with java.io.IOException: Wrong version of key store.
when keystore.Load()
is called.
这java.io.IOException: Wrong version of key store.
在keystore.Load()
调用when 时失败。
I have ensured I'm passing -storetype BKS
, used a <=7 character keystore password, added the CA certs to the key store, and using both Bouncy Castle version 1.45 and 1.47 to create the key store with no change in the reported error message.
我已确保通过-storetype BKS
,使用 <=7 个字符的密钥库密码,将 CA 证书添加到密钥库,并使用 Bouncy Castle 1.45 和 1.47 版创建密钥库,报告的错误消息没有任何变化。
My environment is Eclipse Juno 4.2.1 with JRE 1.7u9b5 running on Windows 8. The device I'm testing on is an HTC sensation running stock Android 2.3. The application has a minimum SDK version of 7 and a target of 15.
我的环境是 Eclipse Juno 4.2.1,JRE 1.7u9b5 在 Windows 8 上运行。我正在测试的设备是运行 Android 2.3 的 HTC 感觉。该应用程序的最低 SDK 版本为 7,目标为 15。
If anyone can explain how to create a valid BKS key store on Windows 8 or how I can get Java to use the same key store as the browser(or system?) that would be appreciated.
如果有人能解释如何在 Windows 8 上创建有效的 BKS 密钥库,或者我如何让 Java 使用与浏览器(或系统?)相同的密钥库,那将不胜感激。
You can download the entire projectas it was at the time of writing, and the generated keystoreif required.
采纳答案by Akdeniz
Bouncy Castle 1.47 is using different version header. Can you try 1.46 version, it should work.
Bouncy Castle 1.47 使用不同的版本标头。你可以试试1.46 版本,它应该可以工作。
keytool -import -alias onlinescoutmanager -file www.onlinescoutmanager.co.uk.crt -storetype BKS -storepass osmosm -keystore C:/keystore -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-1.46.jar
回答by Deanna
Thanks to various people for their hints on this, there are multiple things that all needed to be correct for it to work.
多亏了很多人对此的提示,有很多事情都需要正确才能使其正常工作。
If the HTTPS site's certificate is signed by a trusted root certificate then it will work out of the box without a custom
SSLSocketFactory
. The trusted root certificates CAN be different to that used by a browser so don't assume that if it works in the Android web browser then it will work in your app.
If it's not a trusted root certificate and you get exceptions likejavax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
, then you need to create and load a key store as below.The key store needs to be generated using the Bouncy Castle provider (1) by specifying
-storetype bks
on thekeytool
command line.
If Bouncy Castle is not installed correctly then this will fail with various exceptions includingjava.security.KeyStoreException: BKS not found
. If the key store is not created with the Bouncy Castle provider then you may get thejava.io.IOException: Wrong version of key store.
exception, causing confusion with the next case.You need to use an appropriate version (1, 2, 3) of the Bouncy Castle provider. In most cases, this seems to be version 1.46.
This can be put into your JRE'slib/ext/
folder and the class name added tolib/security/java.security
, or specified directly on the command line tokeytool
. If it's an incompatible version (or store type) you will get exceptions along the lines ofjava.io.IOException: Wrong version of key store.
again.You must include all intermediary and the root certificate. If any are missing, you will get a
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
exception.The certificate chain MUST be in order for them to be validated correctly. If they aren't you will either get
javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: IssuerName(CN=XYZ) does not match SubjectName(CN=ABC) of signing certificate.
or again, a genericjavax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I have not found a way to order them in the key store so resorted to doing it in code at runtime.
如果 HTTPS 站点的证书是由受信任的根证书签名的,那么它将开箱即用,无需自定义
SSLSocketFactory
. 受信任的根证书可能与浏览器使用的证书不同,所以不要假设如果它在 Android 网络浏览器中工作,那么它就可以在您的应用程序中工作。
如果它不是受信任的根证书并且您得到类似 的异常javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
,那么您需要创建并加载如下所示的密钥库。需要使用 Bouncy Castle 提供程序 ( 1) 通过
-storetype bks
在keytool
命令行上指定来生成密钥库。
如果 Bouncy Castle 安装不正确,那么这将失败,并出现各种异常,包括java.security.KeyStoreException: BKS not found
. 如果密钥库不是使用 Bouncy Castle 提供程序创建的,那么您可能会遇到java.io.IOException: Wrong version of key store.
异常,从而导致与下一种情况混淆。您需要使用Bouncy Castle 提供程序的适当版本(1、2、3)。在大多数情况下,这似乎是1.46 版。
这可以放入您的 JRElib/ext/
文件夹并将类名添加到lib/security/java.security
,或者直接在命令行中指定到keytool
。如果它是不兼容的版本(或商店类型),您将java.io.IOException: Wrong version of key store.
再次遇到异常。您必须包括所有中介和根证书。如果有任何缺失,您将得到一个
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
例外。证书链必须是为了正确验证它们。如果它们不是,你要么得到,
javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: IssuerName(CN=XYZ) does not match SubjectName(CN=ABC) of signing certificate.
要么再次得到一个通用的,javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
我还没有找到在密钥库中对它们进行排序的方法,所以在运行时在代码中执行它。
Some people have suggested that using a keystore password longer than 7 characterswill also cause it to fail, but that's not what I've found.
有些人建议使用超过 7 个字符的密钥库密码也会导致它失败,但这不是我发现的。
I think this covers every pitfall I found, but feel free to expand and add linsk to related questions.
我认为这涵盖了我发现的每个陷阱,但可以随意扩展并添加相关问题的 linsk。