完整版见https://jadyer.github.io/2012/07/29/ssl-pkix/
话说前几天在测试服务器上遇到了这么个异常
- 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
接着就拜Google大神,发现一篇文章能被N个人转来转去的,关键文章还不怎么靠谱
后来找到了一个办法,幸运的是在测试环境一弄,这个问题看上去就被解决了
我们要做的就是将所要访问的URL的安全认证证书导入到客户端
下面是获取安全证书的一种方法
- /*
- * 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);
- }
- }
- }
执行方式:Java InstallCert hostname eg:Java InstallCert www.cebbank.com
接下来会看到下面的打印信息
- java InstallCert www.cebbank.com
- Loading KeyStore /usr/java/jdk1.6.0_31/jre/lib/security/cacerts...
- Opening connection to www.cebbank.com:443...
- Starting SSL handshake...
- 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.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
- at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
- at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
- at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
- at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
- at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
- at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
- at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
- at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
- at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
- at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
- at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
- at InstallCert.main(InstallCert.java:102)
- 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(PKIXValidator.java:323)
- at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
- at sun.security.validator.Validator.validate(Validator.java:218)
- at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
- at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
- at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:198)
- at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1198)
- ... 8 more
- Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
- at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
- at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
- at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
- ... 14 more
- Server sent 1 certificate(s):
- 1 Subject CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing
- Issuer CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network
- sha1 5b d2 85 6e b3 a4 2b 07 a2 13 47 b3 be 3e 1f c9 d3 ce 46 57
- md5 05 d8 ae ee f1 d9 51 63 6d 2f 11 e0 ac d0 e7 d7
- Enter certificate to add to trusted keystore or 'q' to quit: [1]
- [
- [
- Version: V3
- Subject: CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing
- Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
- Key: Sun RSA public key, 2048 bits
- modulus: 30831246384548809540705228292841393062583732250993909916355780413722161557074568469738254573472093341710481517139910877
- public exponent: 65537
- Validity: [From: Mon Jul 02 08:00:00 CST 2012,
- To: Thu Jul 03 07:59:59 CST 2014]
- Issuer: CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network
- SerialNumber: [ 5715ab25 6be8fa42 2fa28dd4 601bc732]
- Certificate Extensions: 9
- [1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
- AuthorityInfoAccess [
- [
- accessMethod: 1.3.6.1.5.5.7.48.1
- accessLocation: URIName: http://ocsp.verisign.com,
- accessMethod: 1.3.6.1.5.5.7.48.2
- accessLocation: URIName: http://EVSecure-aia.verisign.com/EVSecure2006.cer]
- ]
- [2]: ObjectId: 2.5.29.17 Criticality=false
- SubjectAlternativeName [
- DNSName: www.cebbank.com
- ]
- [3]: ObjectId: 2.5.29.35 Criticality=false
- AuthorityKeyIdentifier [
- KeyIdentifier [
- 0000: FC 8A 50 BA 9E B9 25 5A 7B 55 85 4F 95 00 63 8F ..P...%Z.U.O..c.
- 0010: E9 58 6B 43 .XkC
- ]
- ]
- [4]: ObjectId: 2.5.29.32 Criticality=false
- CertificatePolicies [
- [CertificatePolicyId: [2.16.840.1.113733.1.7.23.6]
- [PolicyQualifierInfo: [
- qualifierID: 1.3.6.1.5.5.7.2.1
- qualifier: 0000: 16 1C 68 74 74 70 73 3A 2F 2F 77 77 77 2E 76 65 ..https://www.ve
- 0010: 72 69 73 69 67 6E 2E 63 6F 6D 2F 63 70 73 risign.com/cps
- ]] ]
- ]
- [5]: ObjectId: 2.5.29.19 Criticality=false
- BasicConstraints:[
- CA:false
- PathLen: undefined
- ]
- [6]: ObjectId: 1.3.6.1.5.5.7.1.12 Criticality=false
- Extension unknown: DER encoded OCTET string =
- 0000: 04 62 30 60 A1 5E A0 5C 30 5A 30 58 30 56 16 09 .b0`.^.\0Z0X0V..
- 0010: 69 6D 61 67 65 2F 67 69 66 30 21 30 1F 30 07 06 image/gif0!0.0..
- 0020: 05 2B 0E 03 02 1A 04 14 4B 6B B9 28 96 06 0C BB .+......Kk.(....
- 0030: D0 52 38 9B 29 AC 4B 07 8B 21 05 18 30 26 16 24 .R8.).K..!..0&.$
- 0040: 68 74 74 70 3A 2F 2F 6C 6F 67 6F 2E 76 65 72 69 http://logo.veri
- 0050: 73 69 67 6E 2E 63 6F 6D 2F 76 73 6C 6F 67 6F 31 sign.com/vslogo1
- 0060: 2E 67 69 66 .gif
- [7]: ObjectId: 2.5.29.37 Criticality=false
- ExtendedKeyUsages [
- serverAuth
- clientAuth
- ]
- [8]: ObjectId: 2.5.29.31 Criticality=false
- CRLDistributionPoints [
- [DistributionPoint:
- [URIName: http://EVSecure-crl.verisign.com/EVSecure2006.crl]
- ]]
- [9]: ObjectId: 2.5.29.15 Criticality=false
- KeyUsage [
- DigitalSignature
- Key_Encipherment
- ]
- ]
- Algorithm: [SHA1withRSA]
- Signature:
- 0000: 42 0A 89 BF 48 08 1E F4 98 F2 E5 DB 0D 83 EF 37 B...H..........7
- 0010: EC 27 6F 4D 81 69 C6 4A 4C 17 EC 57 F5 48 2A 14 .'oM.i.JL..W.H*.
- 0020: 3C 54 B2 C5 49 39 42 BA EC 83 78 02 F9 96 6C 63 <T..I9B...x...lc
- 0030: 80 BC 60 61 BB 20 D1 AD C3 D3 76 47 6F 0C 7B AC ..`a. ....vGo...
- 0040: 76 B2 C7 2D B1 0A 7A 00 CA 40 38 86 FF 9F 12 F5 v..-..z..@8.....
- 0050: BE 5A E7 42 97 2F DF DE 0C 19 C5 F6 92 58 17 7A .Z.B./.......X.z
- 0060: 9A 1D 2C 2C DA 8B 83 83 2D BE 07 58 56 36 92 E7 ..,,....-..XV6..
- 0070: B1 F8 A0 B5 00 F4 C3 30 D1 34 37 3D 94 75 28 04 .......0.47=.u(.
- 0080: A2 D8 C3 FE B1 E1 C2 2E 51 A8 6F D5 09 6D 49 DB ........Q.o..mI.
- 0090: 2E 1D 4B F7 A8 06 30 B4 97 E7 C2 33 26 FD 6A DF ..K...0....3&.j.
- 00A0: D6 B0 10 A1 F2 73 DD 5A 60 DE 51 5E EA 80 46 86 .....s.Z`.Q^..F.
- 00B0: 25 0B 53 FC C2 57 80 35 09 2D 31 55 28 35 EE 0F %.S..W.5.-1U(5..
- 00C0: 62 50 4B 12 75 0B 02 9F 2F 0B D2 8A 0D 23 E3 C1 bPK.u.../....#..
- 00D0: 48 28 56 33 E1 DE 31 DD 72 78 15 96 EE 2B A5 1D H(V3..1.rx...+..
- 00E0: 37 85 1B E5 88 53 80 88 02 6D 90 F3 E6 4A 74 AC 7....S...m...Jt.
- 00F0: D2 CA 0E 04 BC 46 A0 57 34 FA CF 9D E5 D7 0E 4B .....F.W4......K
- ]
- Added certificate to keystore 'jssecacerts' using alias 'www.cebbank.com-1'
再将名为jssecacerts的证书拷贝\\%JAVA_HONME%\\jre\\lib\\security\\目录中
最后重启下应用的服务,证书就会生效了。。
补充:有人说生成证书后不用拷贝,直接代码里加句话就行,结果试了一下发现不管用
- System.setProperty("javax.net.ssl.trustStore", "jssecacerts证书路径");