java开发https请求ssl不受信任问题解决方法

在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

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

/*

 * 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.

 */

/**

 * http://blogs.sun.com/andreas/resource/InstallCert.java

 * Use:

 * java InstallCert hostname

 * Example:

 *% java InstallCert ecc.fedora.redhat.com

 */

import javax.net.ssl.*;

import java.io.*;

import java.security.KeyStore;

import java.security.MessageDigest;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

/**

 * Class used to add the server's certificate to the KeyStore

 * with your trusted certificates.

 */

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

        }

    }

}

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

java InstallCert my.hoolai.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创建之前调用文章里所述的方法,像这个样子:

?

1

2

3

4

5

6

7

8

trustAllHttpsCertificates();

HostnameVerifier hv = new HostnameVerifier() {

    public boolean verify(String urlHostName, SSLSession session) {

      return true;

    }

  };

HttpsURLConnection.setDefaultHostnameVerifier(hv);

connection = (HttpURLConnection) url.openConnection();

好吧,两种方法都试过有效。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值