Java手动添加SSL证书
出现错误为 SSLHandshakeException - unable to find valid certification path to requested target
在服务器上找到对应的jssecacerts文件或cacerts, 一般在 <jre home>/lib/security 目录下, 在本地执行以下代码, 将cert添加到文件里,
再用新产生的jssecacerts放回覆盖旧文件(建议先备份)
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 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | package com.rockbb.test; /* * 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.*; import java.net.URL; import java.security.*; import java.security.cert.*; import javax.net.ssl.*; public class InstallCert { public static void main(String[] args) throws Exception { args = new String[]{ "api.weixin.qq.com" }; 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( "E:\\temp\\" ); 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); } } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程