解决 Java 调用 Azure SDK 证书错误 javax.net.ssl.SSLHandshakeException

本文主要是介绍解决 Java 调用 Azure SDK 证书错误 javax.net.ssl.SSLHandshakeException,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Azure 作为微软的公有云平台,提供了非常丰富的 SDK 和 API 让开发人员可以非常方便的调用的各项服务,目前除了自家的 .NET、Java、Python、 nodeJS、Ruby,PHP 等语言都提供支持,详细的文档说明请参考:

https://azure.microsoft.com/en-us/documentation/

然而在使用过程中,以 Java 语言为例,在初始调用 Azure SDK/API 的时候大家会碰到类似下面的错误:

[WARN] ServiceBusContract - com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target <com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requestedtarget>com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:151)
at com.microsoft.windowsazure.services.servicebus.implementation.AuthorizationFilter.handle(AuthorizationFilter.java:39)
at com.microsoft.windowsazure.core.pipeline.jersey.ClientFilterRequestAdapter.handle(ClientFilterRequestAdapter.java:36)
at com.sun.jersey.api.client.Client.handle(Client.java:648)

 

其实这个错误并不是 Azure 的问题,如果大家搜一搜就知道,只要是你用 Java 去访问 https 的网站或者服务,都会碰到类似的错误,最根本的原因是 CNNIC 所颁发的证书并不被 JDK 所认可,其中原因大家应该懂得:)

 

 

言归正传,如何解决这个问题?

1. 等待 Oracle/Google/Mozilla 等等组织信任 CNNIC,算了,洗洗睡吧

2. 使用 Java 的 TrustManager 忽略所有的 SSL 请求的证书,仅仅用于开发测试,限于篇幅不做介绍了

3. 导入目标网站的证书,然后在开始调用之前,指定 keystore 就 ok 了,本文介绍下该方法

在你的 IDE 环境中导入如下文件获取目标网站的证书,该程序是 Sun(已经被 Oracle 收了)的一位大牛写的,名字没有查到,我只是引用一下,不是我写的,对其贡献表示尊重:

package com.azurelabs.china.tools;/*
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class InstallCert {
public static void main(String[] args) throws Exception {
String host;
int port;
char[] passphrase;
if ((args.length == 1) || (args.length == 2)) {
String[] c = args[0].split(":");
host = c[0];
port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
String p = (args.length == 1) ? "changeit" : args[1];
passphrase = p.toCharArray();
} else {
System.out
.println("Usage: java InstallCert <host>[:port] [passphrase]");
return;
}
File file = new File("jssecacerts");
if (file.isFile() == false) {
char SEP = File.separatorChar;
File dir = new File(System.getProperty("java.home") + SEP + "lib"
+ SEP + "security");
file = new File(dir, "jssecacerts");
if (file.isFile() == false) {
file = new File(dir, "cacerts");
}
}
System.out.println("Loading KeyStore " + file + "...");
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, passphrase);
in.close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf
.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory factory = context.getSocketFactory();
System.out
.println("Opening connection to " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
try {
System.out.println("Starting SSL handshake...");
socket.startHandshake();
socket.close();
System.out.println();
System.out.println("No errors, certificate is already trusted");
} catch (SSLException e) {
System.out.println();
e.printStackTrace(System.out);
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("Could not obtain server certificate chain");
return;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
System.out.println();
System.out.println("Server sent " + chain.length + " certificate(s):");
System.out.println();
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
System.out.println(" " + (i + 1) + " Subject "
+ cert.getSubjectDN());
System.out.println(" Issuer " + cert.getIssuerDN());
sha1.update(cert.getEncoded());
System.out.println(" sha1 " + toHexString(sha1.digest()));
md5.update(cert.getEncoded());
System.out.println(" md5 " + toHexString(md5.digest()));
System.out.println();
}
System.out
.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
String line = reader.readLine().trim();
int k;
try {
k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
} catch (NumberFormatException e) {
System.out.println("KeyStore not changed");
return;
}
X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();
System.out.println();
System.out.println(cert);
System.out.println();
System.out
.println("Added certificate to keystore 'jssecacerts' using alias '"
+ alias + "'");
}
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b : bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers() {
throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
}

 

复制到你的IDE中,加上你的网站名字作为参数运行,如果是Azure,就使用www.windowsazure.cn作为参数,选择1,回车,就可以得到一个keystore文件:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.azurelabs.china.tools.InstallCert.main(InstallCert.java:104)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at com.azurelabs.china.tools.InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:200)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown Source)
... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 17 more

Server sent 2 certificate(s):

1 Subject CN=support.windowsazure.cn, OU=Azure, O=Shanghai Blue Cloud Technology Co. Ltd, L=Shanghai, ST=Shanghai, C=CN
Issuer CN=WoSign Class 3 OV Server CA G2, O=WoSign CA Limited, C=CN
sha1 39 02 08 52 59 bf 47 97 2f eb f7 8f fc c9 03 ef 26 cb 21 dd
md5 83 28 58 28 51 b8 62 ed 36 e6 d0 70 15 99 a8 38

2 Subject CN=WoSign Class 3 OV Server CA G2, O=WoSign CA Limited, C=CN
Issuer CN=Certification Authority of WoSign, O=WoSign CA Limited, C=CN
sha1 2b 43 72 46 cc ba 25 15 9e b5 be a1 62 ac 60 18 dc bf f4 72
md5 5f a4 91 6a ab d3 c9 80 09 6c eb 00 31 34 fc 3d

Enter certificate to add to trusted keystore or 'q' to quit: [1]
1

[
[
Version: V3
Subject: CN=support.windowsazure.cn, OU=Azure, O=Shanghai Blue Cloud Technology Co. Ltd, L=Shanghai, ST=Shanghai, C=CN
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

Key: Sun RSA public key, 2048 bits
modulus: 24104532407647535108241621827688332263926906187163691939931462013874932504662453335625927986716086247633840840524051115
364996238391743503802118690155144909240897365990040793471910633352618274034556617076873608976668528804939183424686164227185431879
267461919749098227696743182875748132677719418665216178511515782485580061460364614666955611361304411692446552333333850501994838165
659760614012629638654246105220036245117410486536684224500173338204500619911544787890879820586922542656204188700978168997284623863
785685892268535250107770005916206905453265121667987788474107941942533485774966535690717314093662982801373356241
public exponent: 65537
Validity: [From: Tue Nov 24 19:32:28 CST 2015,
To: Fri Nov 24 19:32:28 CST 2017]
Issuer: CN=WoSign Class 3 OV Server CA G2, O=WoSign CA Limited, C=CN
SerialNumber: [ 6d899f54 35b4c5af f9f08f76 a88e0d33]

Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: ocsp
accessLocation: URIName: http://ocsp1.wosign.com/ca6/server3
,
accessMethod: caIssuers
accessLocation: URIName: http://aia1.wosign.com/ca6.server3.cer
]
]
[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: F9 8B EC 04 38 6A 3F AA 06 C6 94 AD 73 95 2A B0 ....8j?.....s.*.
0010: C8 E6 B8 FB ....
]
]

[3]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]

[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crls1.wosign.com/ca6-server3.crl]
]]

[5]: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
[CertificatePolicyId: [2.23.140.1.2.2]
[] ]
[CertificatePolicyId: [1.3.6.1.4.1.36305.6.3.2.1]
[PolicyQualifierInfo: [
qualifierID: 1.3.6.1.5.5.7.2.1
qualifier: 0000: 16 1D 68 74 74 70 3A 2F 2F 77 77 77 2E 77 6F 73 ..http://www.wos
0010: 69 67 6E 2E 63 6F 6D 2F 70 6F 6C 69 63 79 2F ign.com/policy/

]] ]
]

[6]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
clientAuth
serverAuth
]

[7]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
DigitalSignature
Key_Encipherment
]

[8]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: support.windowsazure.cn
DNSName: www.windowsazure.cn
]

[9]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 17 38 7A B7 4C 12 D9 0A 36 B5 C6 70 C3 DD DE B8 .8z.L...6..p....
0010: 46 AE 86 70 F..p
]
]

]
Algorithm: [SHA256withRSA]
Signature:
0000: 9B 9D DB 30 3E 69 B9 29 3C ED 98 98 AA 21 B0 DD ...0>i.)<....!..
0010: 0F AD 16 79 21 7D 7F 54 66 90 87 73 BF 1C 1A 8A ...y!..Tf..s....
0020: 4A 08 86 1A 31 AF 27 74 11 22 B5 4A 8B A0 23 4B J...1.'t.".J..#K
0030: BE 80 7D 51 35 96 D1 E9 2B 6F F6 3C AB E5 DF C8 ...Q5...+o.<....
0040: D7 B7 C4 63 D5 0E EC D8 AE 67 33 A6 C7 03 C1 51 ...c.....g3....Q
0050: F1 A5 4B 06 DC 37 B5 DB D2 B8 64 E9 E1 A3 8E C7 ..K..7....d.....
0060: B4 4A 96 D3 08 A7 E3 3D 64 61 13 24 6D 35 01 29 .J.....=da.$m5.)
0070: 64 F3 7D CE E2 56 8E 6A A2 E2 60 0D D8 D2 AD CF d....V.j..`.....
0080: FC 0E 5C 14 4B 6F F7 BE 71 1D 78 7A C7 09 5C 87 ..\.Ko..q.xz..\.
0090: 0F 38 AD 0D 94 19 E1 45 32 72 EA AB 78 4D 4C 67 .8.....E2r..xMLg
00A0: E8 4E 94 4B A7 28 35 3A 94 A6 97 CC 06 F0 68 74 .N.K.(5:......ht
00B0: 02 C0 D9 B3 4B 64 CD 7A 43 F0 8B B9 E8 CC 75 9A ....Kd.zC.....u.
00C0: 08 50 4F A1 CF 63 1D 80 7C 5A 8D 32 D1 09 B9 C3 .PO..c...Z.2....
00D0: B8 C0 B7 BE 6B 92 2B 80 B0 A4 8A 0E 19 16 41 42 ....k.+.......AB
00E0: 90 88 B4 CA E7 3B B5 F7 70 80 D7 10 37 41 DB 4D .....;..p...7A.M
00F0: 9E 2B 65 45 F1 CB 08 EA 83 1F 29 A1 E3 68 EA 9B .+eE......)..h..

]

Added certificate to keystore 'jssecacerts' using alias 'www.windowsazure.cn-1'

 

 你在程序运行的当前目录会生成一个jssecacerts文件,你可以将它放到你的jre的lib\security目录,也可以放在任意位置,然后再你的程序调用API之前指定TrustStore的位置:

System.setProperty("javax.net.ssl.trustStore","E:\\DevSpace\\jssecacerts");

 

我的例子如下:

 

各位如果对此感兴趣的话,可以来这里与我交流。

转载于:https://www.cnblogs.com/cbits/p/7494195.html

这篇关于解决 Java 调用 Azure SDK 证书错误 javax.net.ssl.SSLHandshakeException的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/380244

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。