• PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


    注:网上搜来的快照,暂未验证

    在java代码中请求https链接的时候,可能会报下面这个错误

    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

    原因是没有证书。在浏览器中直接使用url访问是可以的,应该是浏览器之前就保存过对应的.cer证书。

    解决方法有两种,从目标机器获得有效证书或者忽略证书信任问题。

    一、获得目标机器有效证书

    1、编译安装证书程序 javac InstallCert.java(代码如下)


      1 /*
      2 
      3  * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
      4 
      5  *
      6 
      7  * Redistribution and use in source and binary forms, with or without
      8 
      9  * modification, are permitted provided that the following conditions
     10 
     11  * are met:
     12 
     13  *
     14 
     15  *  - Redistributions of source code must retain the above copyright
     16 
     17  *   notice, this list of conditions and the following disclaimer.
     18 
     19  *
     20 
     21  *  - Redistributions in binary form must reproduce the above copyright
     22 
     23  *   notice, this list of conditions and the following disclaimer in the
     24 
     25  *   documentation and/or other materials provided with the distribution.
     26 
     27  *
     28 
     29  *  - Neither the name of Sun Microsystems nor the names of its
     30 
     31  *   contributors may be used to endorse or promote products derived
     32 
     33  *   from this software without specific prior written permission.
     34 
     35  *
     36 
     37  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     38 
     39  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     40 
     41  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     42 
     43  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     44 
     45  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     46 
     47  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     48 
     49  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     50 
     51  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     52 
     53  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     54 
     55  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     56 
     57  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     58 
     59  */
     60 
     61 /**
     62 
     63  * http://blogs.sun.com/andreas/resource/InstallCert.java
     64 
     65  * Use:
     66 
     67  * java InstallCert hostname
     68 
     69  * Example:
     70 
     71  *% java InstallCert ecc.fedora.redhat.com
     72 
     73  */
     74 
     75 import javax.net.ssl.*;
     76 
     77 import java.io.*;
     78 
     79 import java.security.KeyStore;
     80 
     81 import java.security.MessageDigest;
     82 
     83 import java.security.cert.CertificateException;
     84 
     85 import java.security.cert.X509Certificate;
     86 
     87 /**
     88 
     89  * Class used to add the server's certificate to the KeyStore
     90 
     91  * with your trusted certificates.
     92 
     93  */
     94 
     95 public class InstallCert {
     96 
     97     public static void main(String[] args) throws Exception {
     98 
     99         String host;
    100 
    101         int port;
    102 
    103         char[] passphrase;
    104 
    105         if ((args.length == 1) || (args.length == 2)) {
    106 
    107             String[] c = args[0].split(":");
    108 
    109             host = c[0];
    110 
    111             port = (c.length == 1) ? 443 : Integer.parseint(c[1]);
    112 
    113             String p = (args.length == 1) ? "changeit" : args[1];
    114 
    115             passphrase = p.toCharArray();
    116 
    117         } else {
    118 
    119             System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
    120 
    121             return;
    122 
    123         }
    124 
    125         File file = new File("jssecacerts");
    126 
    127         if (file.isFile() == false) {
    128 
    129             char SEP = File.separatorchar;
    130 
    131             File dir = new File(System.getProperty("java.home") + SEP
    132 
    133                       + "lib" + SEP + "security");
    134 
    135             file = new File(dir, "jssecacerts");
    136 
    137             if (file.isFile() == false) {
    138 
    139                 file = new File(dir, "cacerts");
    140 
    141             }
    142 
    143         }
    144 
    145         System.out.println("Loading KeyStore " + file + "...");
    146 
    147         InputStream in = new FileInputStream(file);
    148 
    149         KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    150 
    151         ks.load(in, passphrase);
    152 
    153         in.close();
    154 
    155         SSLContext context = SSLContext.getInstance("TLS");
    156 
    157         TrustManagerFactory tmf =
    158 
    159                 TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    160 
    161         tmf.init(ks);
    162 
    163         X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
    164 
    165         SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
    166 
    167         context.init(null, new TrustManager[]{
    168 
    169             tm
    170 
    171         }
    172 
    173         , null);
    174 
    175         SSLSocketFactory factory = context.getSocketFactory();
    176 
    177         System.out.println("Opening connection to " + host + ":" + port + "...");
    178 
    179         SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
    180 
    181         socket.setSoTimeout(10000);
    182 
    183         try {
    184 
    185             System.out.println("Starting SSL handshake...");
    186 
    187             socket.startHandshake();
    188 
    189             socket.close();
    190 
    191             System.out.println();
    192 
    193             System.out.println("No errors, certificate is already trusted");
    194 
    195         }
    196 
    197         catch (SSLException e) {
    198 
    199             System.out.println();
    200 
    201             e.printStackTrace(System.out);
    202 
    203         }
    204 
    205         X509Certificate[] chain = tm.chain;
    206 
    207         if (chain == null) {
    208 
    209             System.out.println("Could not obtain server certificate chain");
    210 
    211             return;
    212 
    213         }
    214 
    215         BufferedReader reader =
    216 
    217                 new BufferedReader(new InputStreamReader(System.in));
    218 
    219         System.out.println();
    220 
    221         System.out.println("Server sent " + chain.length + " certificate(s):");
    222 
    223         System.out.println();
    224 
    225         MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    226 
    227         MessageDigest md5 = MessageDigest.getInstance("MD5");
    228 
    229         for (int i = 0; i < chain.length; i++) {
    230 
    231             X509Certificate cert = chain[i];
    232 
    233             System.out.println
    234 
    235                       (" " + (i + 1) + " Subject " + cert.getSubjectDN());
    236 
    237             System.out.println("  Issuer " + cert.getIssuerDN());
    238 
    239             sha1.update(cert.getEncoded());
    240 
    241             System.out.println("  sha1  " + toHexString(sha1.digest()));
    242 
    243             md5.update(cert.getEncoded());
    244 
    245             System.out.println("  md5   " + toHexString(md5.digest()));
    246 
    247             System.out.println();
    248 
    249         }
    250 
    251         System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
    252 
    253         String line = reader.readLine().trim();
    254 
    255         int k;
    256 
    257         try {
    258 
    259             k = (line.length() == 0) ? 0 : Integer.parseint(line) - 1;
    260 
    261         }
    262 
    263         catch (NumberFormatException e) {
    264 
    265             System.out.println("KeyStore not changed");
    266 
    267             return;
    268 
    269         }
    270 
    271         X509Certificate cert = chain[k];
    272 
    273         String alias = host + "-" + (k + 1);
    274 
    275         ks.setCertificateEntry(alias, cert);
    276 
    277         OutputStream out = new FileOutputStream("jssecacerts");
    278 
    279         ks.store(out, passphrase);
    280 
    281         out.close();
    282 
    283         System.out.println();
    284 
    285         System.out.println(cert);
    286 
    287         System.out.println();
    288 
    289         System.out.println
    290 
    291                 ("Added certificate to keystore 'jssecacerts' using alias '"
    292 
    293                     + alias + "'");
    294 
    295     }
    296 
    297     private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
    298 
    299     private static String toHexString(byte[] bytes) {
    300 
    301         StringBuilder sb = new StringBuilder(bytes.length * 3);
    302 
    303         for (int b : bytes) {
    304 
    305             b &= 0xff;
    306 
    307             sb.append(HEXDIGITS[b >> 4]);
    308 
    309             sb.append(HEXDIGITS[b & 15]);
    310 
    311             sb.append(' ');
    312 
    313         }
    314 
    315         return sb.toString();
    316 
    317     }
    318 
    319     private static class SavingTrustManager implements X509TrustManager {
    320 
    321         private final X509TrustManager tm;
    322 
    323         private X509Certificate[] chain;
    324 
    325         SavingTrustManager(X509TrustManager tm) {
    326 
    327             this.tm = tm;
    328 
    329         }
    330 
    331         public X509Certificate[] getAcceptedIssuers() {
    332 
    333             throw new UnsupportedOperationException();
    334 
    335         }
    336 
    337         public void checkClientTrusted(X509Certificate[] chain, String authType)
    338 
    339                 throws CertificateException {
    340 
    341             throw new UnsupportedOperationException();
    342 
    343         }
    344 
    345         public void checkServerTrusted(X509Certificate[] chain, String authType)
    346 
    347                 throws CertificateException {
    348 
    349             this.chain = chain;
    350 
    351             tm.checkServerTrusted(chain, authType);
    352 
    353         }
    354 
    355     }
    356 
    357 }



    2、运行安装证书程序生成证书

    java InstallCert www.xxx.com

    例如:java InstalCert smtp.zhangsan.com:465 admin
    如果不加参数password和host的端口号,上面的获取证书程序中默认给的端口号是:443,密码是:changeit

    3、根据运行提示信息,输入1,回车,在当前目录下生成名为: jssecacerts 的证书

    将证书放置到$JAVA_HOME/jre/lib/security目录下, 切记该JDK的jre是工程所用的环境!!!

    或者:

    System.setProperty("javax.net.ssl.trustStore", "你的jssecacerts证书路径");

    可以更改密码,在security目录下运行命令

    keytool -storepasswd -new xxxcom -keystore cacerts

    就可以修改密码,修改后使用命令

    keytool -list -v -keystore cacerts

    查看文件的信息,会提示需要密码才能查看,如果输入密码与修改后的密码匹配,说明修改成功了。

    PS:至此这种方式可以成功使用ssl了,另外再补充一下,根据刚才生成的文件jssecacerts,可以生成cer文件,

    命令如下

    keytool -export -alias xxx.com-1 -keystore jssecacerts -rfc -file xxx.cer

    如上,之前的工具类中默认命名别名是加上"-1"。使用InstallCert设置的密码需要跟cacerts文件中的密码一致,

    如果修改过密码,就需要修改InstallCert类中对应的密码字符串,否则会有下面这个异常:

    java.security.UnrecoverableKeyException: Password verification failed

    二、忽略证书信任问题

    源码:http://mengyang.iteye.com/blog/575671

    一定要注意需要在connection创建之前调用文章里所述的方法,像这个样子:

    trustAllHttpsCertificates();

    HostnameVerifier hv = new HostnameVerifier() {

        public boolean verify(String urlHostName, SSLSession session) {

          return true;

        }

      };
        

    trustAllHttpsCertificates();

    HostnameVerifier hv = new HostnameVerifier() {

        public boolean verify(String urlHostName, SSLSession session) {

          return true;

        }

      };

    HttpsURLConnection.setDefaultHostnameVerifier(hv);

    connection = (HttpURLConnection) url.openConnection();

  • 相关阅读:
    java多线程
    java垃圾回收
    java研发常见问题总结 1
    js获取时间加多山天和时间戳转换成日期
    php时间选择器亲测可以自己修改
    html5时间选择器
    php生成员工编号,产品编号
    桌面远程链接
    SQL 左外连接查询 将右表中的多行变为左表的一列或多列
    PHPMailer发匿名邮件及Extension missing: openssl的解决
  • 原文地址:https://www.cnblogs.com/woooodlin/p/13023444.html
Copyright © 2020-2023  润新知