https不瞭解,對https雙向認證更是一臉懵java
客戶方要求系統提供https的服務,一年前申請某網站的免費證書,下載後包含了各類web容器的證書,應用程序的web容器爲tomcat8,最後選用了tomcat下的證書,爲jks格式。
web
一年後免費服務到期,須要更換證書,客戶申請了阿里雲的證書,下載下來的格式爲pfx,客戶說只有這種格式的。坑已挖好。apache
百度搜索結果說能夠將pfx轉換成jks
命令以下:瀏覽器
keytool -importkeystore -srckeystore xxx.pfx -destkeystore xxx.jks -srcstoretype PKCS12 -deststoretype JKS -srcstorepass xxx -deststorepass xxx -srcalias alias -destalias destalias
由於原來tomcat中配置了jks相關的信息,想着直接將新的jks的文件名和密碼保持一致,直接替換原文件就能夠了。結果被坑。tomcat
按原來的文件名、密碼生成新證書後,啓動tomcat,事實證實想的仍是太簡單。
報錯信息以下:服務器
15-Nov-2019 12:20:20.221 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"] java.security.UnrecoverableKeyException: Cannot recover key at sun.security.provider.KeyProtector.recover(Unknown Source) at sun.security.provider.JavaKeyStore.engineGetKey(Unknown Source) at sun.security.provider.JavaKeyStore$JKS.engineGetKey(Unknown Source) at java.security.KeyStore.getKey(Unknown Source) at sun.security.ssl.SunX509KeyManagerImpl.<init>(Unknown Source) at sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(Unknown Source) at javax.net.ssl.KeyManagerFactory.init(Unknown Source) at org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:617) at org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:546) . . . Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failed at org.apache.catalina.connector.Connector.initInternal(Connector.java:962) at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102) ... 12 more Caused by: java.security.UnrecoverableKeyException: Cannot recover key at sun.security.provider.KeyProtector.recover(Unknown Source) at sun.security.provider.JavaKeyStore.engineGetKey(Unknown Source)
處理辦法:
將新的jks的密碼和pfx的密碼保持一致,修改tomcat配置文件中的密碼。app
其實tomcat能夠直接配置pfx格式證書,須要指定 keystoreType="PKCS12"
keystoreFile="/證書路徑/名稱.pfx" keystoreType="PKCS12" keystorePass="證書密碼"
但此次的客戶有作https雙向認證,以前的代碼已經寫死支持jks證書庫,因此須要生成jkside
15-Nov-2019 11:59:55.017 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"] java.io.IOException: Keystore was tampered with, or password was incorrect at sun.security.provider.JavaKeyStore.engineLoad(Unknown Source) at sun.security.provider.JavaKeyStore$JKS.engineLoad(Unknown Source) . . . Caused by: java.security.UnrecoverableKeyException: Password verification failed ... 25 more
異常信息以下:post
15-Nov-2019 12:20:20.221 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"] java.security.UnrecoverableKeyException: Cannot recover key
import javax.net.ssl.*; import java.io.*; import java.net.URL; import java.nio.charset.Charset; import java.security.KeyStore; /** * #2 * HTTPS 雙向認證 - use truststore * 原生方式 * * @Author soft_xiang * @Date 7/11/2017 */ public class HttpsTruststoreNativeDemo { // 客戶端證書路徑,用了本地絕對路徑,須要修改 調用方證書 private final static String CLIENT_CERT_FILE = "D:\\xxx\\https\\xxx-ip.p12"; // 客戶端證書密碼 private final static String CLIENT_PWD = "pwd"; // 信任庫路徑 (被調用方證書合集) private final static String TRUST_STRORE_FILE = "D:\\xxx\\https\\xxx.jks"; // 信任庫密碼 private final static String TRUST_STORE_PWD = "xxx"; private static String readResponseBody(InputStream inputStream) throws IOException { try { BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); StringBuffer sb = new StringBuffer(); String buff = null; while ((buff = br.readLine()) != null) { sb.append(buff + "\n"); } return sb.toString(); } finally { inputStream.close(); } } public static void httpsCall() throws Exception { // 初始化密鑰庫 KeyManagerFactory keyManagerFactory = KeyManagerFactory .getInstance("SunX509"); KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12"); keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray()); // 初始化信任庫 TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance("SunX509"); KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS"); trustManagerFactory.init(trustkeyStore); // 初始化SSL上下文 SSLContext ctx = SSLContext.getInstance("SSL"); ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory .getTrustManagers(), null); SSLSocketFactory sf = ctx.getSocketFactory(); HttpsURLConnection.setDefaultSSLSocketFactory(sf); String url = "post url"; URL urlObj = new URL(url); HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection(); con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"); con.setRequestProperty("Accept-Language", "zh-CN;en-US,en;q=0.5"); con.setRequestProperty("Content-Type", "text/xml"); con.setRequestMethod("POST"); con.setRequestProperty("Content-Length", "0"); con.setDoInput(true); con.setDoOutput(true); DataOutputStream os = new DataOutputStream(con.getOutputStream()); os.write("".getBytes("UTF-8"), 0, 0); os.flush(); os.close(); con.connect(); InputStream is = con.getInputStream(); Integer code = con.getResponseCode(); final String contentType = con.getContentType(); System.out.println(code + ":" + contentType); String response = readResponseBody(is); System.out.println(response); } /** * 得到KeyStore * * @param keyStorePath * @param password * @return * @throws Exception */ private static KeyStore getKeyStore(String keyStorePath, String password, String type) throws Exception { FileInputStream is = new FileInputStream(keyStorePath); KeyStore ks = KeyStore.getInstance(type); ks.load(is, password.toCharArray()); is.close(); return ks; } public static void main(String[] args) throws Exception { httpsCall(); } }
在容許調用的服務器,直接瀏覽器打開須要訪問的地址,調用出現401,sap問題,協調sap解決網站
證書庫密碼錯誤
證書錯誤,確認sap加入信任庫的證書和代碼中調用的證書庫中的證書是同一個
keytool -import -alias xxx -file "xxx.der" -keystore xxx.jks -storepass pass
將證書導入信任庫
keytool -export -alias xxx -keystore abc.jks -storepass pass -file xxx.cer
將證書庫abc.jks中別名爲xxx的證書導出爲xxx.cer,cer客戶端證書
keytool -import -alias xxx -file xxx.cer -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -storepass changeit -trustcacerts
將客戶端證書導入jdk的默認信任庫(cacerts爲jdk默認信任庫,導入以前記得備份)