天天看點

jodd忽略ssl證書_JDK版本低導緻對Let’s Encrypt證書不信任的問題異常資訊:原因:解決辦法:辦法1(推薦):辦法2:辦法3:

jodd忽略ssl證書_JDK版本低導緻對Let’s Encrypt證書不信任的問題異常資訊:原因:解決辦法:辦法1(推薦):辦法2:辦法3:

異常資訊:

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 [: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.comLoading 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 moreCaused 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 moreServer 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=falseExtension 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]Added certificate to keystore 'jssecacerts' using alias 'www.domain.com-1'
           

成功執行後在運作的目錄下會生成一個叫 jssecacerts 的檔案,将這個檔案拷貝到jdk的安裝目錄:

mv jssecacerts $JAVA_HOME/jre/lib/security/
           

最後重新開機tomcat。