首页 » Web服务器 » Tomcat » 正文

由于本地JDK版本低导致对Let’s Encrypt证书不信任的问题

异常信息:

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

原因:

此问题通常出现在:在Java中你所调用的第三方服务使用的是 Let’s Encrypt 签发的证书,而你的jvm对Let’s Encrypt证书不信任造成的,其原因是因为你本地的JDK版本太低,Let’s Encrypt 证书没有在jvm的信任列表里造成的,具体可以查看这个帖子 https://stackoverflow.com/questions/34110426/does-java-support-lets-encrypt-certificates

 

解决办法:

办法1(推荐):

升级你本地的JDK(Java 7 >= 7u111 and Java 8 >= 8u101)

办法2:

通过代码层面忽略证书(不建议,可临时使用,避免安全风险)

办法3:

使用工具类将证书安装到本地jvm,具体如下:

创建 InstallCert.java 文件,内容如下:

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;  
        }  

        @Override
        public X509Certificate[] getAcceptedIssuers() {  
            return new X509Certificate[0];
            //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);  
        }  
    } 
}

 

编译此文件:

javac InstallCert.java

执行安装证书:

java InstallCert www.domain.com

记录如下:

# java InstallCert www.domain.com
Loading KeyStore /data/app/jdk1.8.0_77/jre/lib/security/cacerts...
Opening connection to www.domain.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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
        at InstallCert.main(InstallCert.java:71)
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:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:105)
        at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:169)
        at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:922)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
        ... 8 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ... 16 more

Server sent 2 certificate(s):

 1 Subject CN=www.domain.com
   Issuer  CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
   sha1    0a be b4 66 34 61 0c 12 a6 ce 41 23 fa a6 ac 07 4e 0d 01 c5 
   md5     03 62 53 b6 64 eb e2 c1 94 b1 78 ca 7f ca ba 09 

 2 Subject CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
   Issuer  CN=DST Root CA X3, O=Digital Signature Trust Co.
   sha1    e6 a3 b4 5b 06 2d 50 9b 33 82 28 2d 19 6e fe 97 d5 95 6c cb 
   md5     b1 54 09 27 4f 54 ad 8f 02 3d 3b 85 a5 ec ec 5d 

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


[
[
  Version: V3
  Subject: CN=www.domain.com
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: 20073005243728703890588625943439848561211336917674835504230346105918901249807853936939686786974700735334977268942537167497323546692843523563644823213534348008465907027247526510520051634473185420180113385807184770917288823070595268127830274256454298387634509973843867157786335822014566834526468758634700848208964478670608646135355728636198569419055785142073582810635466008668388439780072550163434088218033275089781036684049357703781872890278369916588130963751270663307524095122347914948370134783779849338647818610006412969932795337706390420574531209519088162964883858704023384983157705668767899247906940630765663557239
  public exponent: 65537
  Validity: [From: Thu May 03 09:57:46 CST 2018,
               To: Wed Aug 01 09:57:46 CST 2018]
  Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
  SerialNumber: [    0490ded4 91a4b26f d82aaa5a bd06ffa4 4804]

Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.4.1.11129.2.4.2 Criticality=false
Extension unknown: DER encoded OCTET string =
0000: 04 81 F5 04 81 F2 00 F0   00 76 00 55 81 D4 C2 16  .........v.U....
0010: 90 36 01 4A EA 0B 9B 57   3C 53 F0 C0 E4 38 78 70  .6.J...W<S...8xp
0020: 25 08 17 2F A3 AA 1D 07   13 D3 0C 00 00 01 63 23  %../..........c#
0030: EF 2B C9 00 00 04 03 00   47 30 45 02 21 00 E3 52  .+......G0E.!..R
0040: 37 05 FF 9F F1 16 CE 6F   A4 86 77 DF 3D 4D 82 CF  7......o..w.=M..
0050: 92 2D BC 04 2F 1C B0 DC   4E FF 90 C1 D1 7E 02 20  .-../...N...... 
0060: 27 E7 AF 9E 09 14 32 D0   52 BD B9 1F FD B4 8B 1C  '.....2.R.......
0070: DF A2 FD 6C FE B2 E6 9B   3A 45 47 78 6B 37 AE A3  ...l....:EGxk7..
0080: 00 76 00 29 3C 51 96 54   C8 39 65 BA AA 50 FC 58  .v.)<Q.T.9e..P.X
0090: 07 D4 B7 6F BF 58 7A 29   72 DC A4 C3 0C F4 E5 45  ...o.Xz)r......E
00A0: 47 F4 78 00 00 01 63 23   EF 2B A4 00 00 04 03 00  G.x...c#.+......
00B0: 47 30 45 02 20 0A 09 D1   3F 17 B2 D5 21 F9 D8 9D  G0E. ...?...!...
00C0: D1 15 73 4F 81 DC 4C 0A   CB 1F F6 34 47 B8 F3 8F  ..sO..L....4G...
00D0: 21 2D 8B 25 01 02 21 00   FD 99 44 63 9C 65 54 A4  !-.%..!...Dc.eT.
00E0: 74 FC FB F6 D1 60 66 25   60 DF C0 97 59 9B 08 6C  t....`f%`...Y..l
00F0: DE 13 58 7F 6B 5A 23 E8                            ..X.kZ#.


[2]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: ocsp
   accessLocation: URIName: http://ocsp.int-x3.letsencrypt.org
, 
   accessMethod: caIssuers
   accessLocation: URIName: http://cert.int-x3.letsencrypt.org/
]
]

[3]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A8 4A 6A 63 04 7D DD BA   E6 D1 39 B7 A6 45 65 EF  .Jjc......9..Ee.
0010: F3 A8 EC A1                                        ....
]
]

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

[5]: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
  [CertificatePolicyId: [2.23.140.1.2.1]
[]  ]
  [CertificatePolicyId: [1.3.6.1.4.1.44947.1.1.1]
[PolicyQualifierInfo: [
  qualifierID: 1.3.6.1.5.5.7.2.1
  qualifier: 0000: 16 1A 68 74 74 70 3A 2F   2F 63 70 73 2E 6C 65 74  ..http://cps.let
0010: 73 65 6E 63 72 79 70 74   2E 6F 72 67              sencrypt.org

], PolicyQualifierInfo: [
  qualifierID: 1.3.6.1.5.5.7.2.2
  qualifier: 0000: 30 81 9E 0C 81 9B 54 68   69 73 20 43 65 72 74 69  0.....This Certi
0010: 66 69 63 61 74 65 20 6D   61 79 20 6F 6E 6C 79 20  ficate may only 
0020: 62 65 20 72 65 6C 69 65   64 20 75 70 6F 6E 20 62  be relied upon b
0030: 79 20 52 65 6C 79 69 6E   67 20 50 61 72 74 69 65  y Relying Partie
0040: 73 20 61 6E 64 20 6F 6E   6C 79 20 69 6E 20 61 63  s and only in ac
0050: 63 6F 72 64 61 6E 63 65   20 77 69 74 68 20 74 68  cordance with th
0060: 65 20 43 65 72 74 69 66   69 63 61 74 65 20 50 6F  e Certificate Po
0070: 6C 69 63 79 20 66 6F 75   6E 64 20 61 74 20 68 74  licy found at ht
0080: 74 70 73 3A 2F 2F 6C 65   74 73 65 6E 63 72 79 70  tps://letsencryp
0090: 74 2E 6F 72 67 2F 72 65   70 6F 73 69 74 6F 72 79  t.org/repository
00A0: 2F                                                 /

]]  ]
]

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

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

[8]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: www.domain.com
]

[9]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 4D 27 88 53 F8 2B E5 57   E3 93 A2 39 0C D0 8A D8  M'.S.+.W...9....
0010: E5 BC 84 A4                                        ....
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 5D 16 29 6D C4 E8 76 AC   32 CF 44 AE E4 27 3B 44  ].)m..v.2.D..';D
0010: CC A7 9A DF 95 1A AC 73   AF 2B 89 51 14 32 2C 5D  .......s.+.Q.2,]
0020: 7C 04 9E 29 47 AA AD C4   CF 9E EF DB B3 7B A9 09  ...)G...........
0030: 28 8B 85 60 C1 4B 67 31   D5 4C 7A C6 54 64 C9 90  (..`.Kg1.Lz.Td..
0040: 7C 31 7A A4 CA 59 CD 9B   0B 78 0C C0 00 A4 F6 EF  .1z..Y...x......
0050: 99 AF 60 F7 98 3C DB F0   8E 08 38 7F 8B 7F C0 9A  ..`..<....8.....
0060: 18 0B 2C D5 CD 01 08 EB   2C EA AA 69 21 C7 99 6E  ..,.....,..i!..n
0070: 24 4E 13 41 94 28 7A C2   D2 43 E9 20 22 C2 35 C9  $N.A.(z..C. ".5.
0080: 9D 05 51 25 DB 4D D5 19   58 3B D7 1D 8E DB F2 2E  ..Q%.M..X;......
0090: 78 73 63 35 9C B2 51 88   00 00 61 1F DB 79 87 EA  xsc5..Q...a..y..
00A0: AF 60 9F F7 03 CA B7 63   F4 95 C2 D1 8F D0 1E 2F  .`.....c......./
00B0: 21 65 D0 CF EF 7A B9 F7   B7 2A BF F2 04 BE 78 F4  !e...z...*....x.
00C0: 6F EA 29 89 00 15 E0 8F   72 77 79 8A 9C 6E 2E 98  o.).....rwy..n..
00D0: C9 EE BF 71 18 AB 90 7A   65 C8 FD 03 1C 7C 0B 32  ...q...ze......2
00E0: DD 00 06 D4 67 61 AF BF   83 3F F3 D8 9D EE 3B 2E  ....ga...?....;.
00F0: E4 94 BB AD 9B 48 47 F3   C2 CE C2 36 8C ED 74 3E  .....HG....6..t>

]

Added certificate to keystore 'jssecacerts' using alias 'www.domain.com-1'

成功执行后在运行的目录下会生成一个叫 jssecacerts 的文件,将这个文件拷贝到jdk的安装目录:

mv jssecacerts $JAVA_HOME/jre/lib/security/

最后重启tomcat。

 

发表评论

验证码加载中....