내 프로그램에서 두 개의 다른 서버에 보안 (양방향 SSL) 요청을 실행해야합니다. 지금은 에 연결하려고하면 예외가 발생합니다. javax.net.ssl.SSLHandshakeException
. 가장 이상한 점은 에 대한 요청이 실패한 후 server2
에서 응답을받을 수 없다는 것입니다. java.net.SocketTimeoutException
예외가 발생합니다. 에 대한 요청이 실행되지 않으면 server2
이 데이터를 성공적으로 반환합니다.java.net.SocketTimeoutException : 실패한 요청 후 시간 초과 읽기.
스택 추적 : server1
에 대한 요청의
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(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
...
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(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 14 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 20 more
Exception in thread "main": java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.security.ssl.InputRecord.readFully(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read1(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
...
코드 : server2
에 대한 요청의
URL url = ...
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "application/soap+xml; charset=UTF-8");
connection.setConnectTimeout(300000);
connection.setReadTimeout(300000);
connection.setDoInput(true);
connection.setDoOutput(true);
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream is = new FileInputStream(new File(...));
try {
keyStore.load(is, "password".toCharArray());
keyManagerFactory.init(keyStore, "password".toCharArray());
} finally {
is.close();
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
is = new FileInputStream(new File(...));
try {
keyStore.load(is, "password".toCharArray());
trustManagerFactory.init(keyStore);
} finally {
is.close();
}
sslContext.init(keyManagerFactory.getKeyManagers(),
trustManagerFactory.getTrustManagers(),new SecureRandom());
httpsConnection.setSSLSocketFactory(sslContext.getSocketFactory());
httpsConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
try {
OutputStream os = connection.getOutputStream();
try {
String s = ...;
os.write(s.getBytes());
} finally {
os.close();
}
System.out.println("Response code: " + connection.getResponseCode());
} finally {
connection.disconnect();
}
코드 :
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream is = new FileInputStream(new File(...));
try {
keyStore.load(is, "password".toCharArray());
keyManagerFactory.init(localKeyStore, "password".toCharArray());
} finally {
is.close();
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyStore = KeyStore.getInstance("JKS");
is = new FileInputStream(new File(...));
try {
keyStore.load(is, "password".toCharArray());
trustManagerFactory.init(keyStore);
} finally {
is.close();
}
sslContext.init(keyManagerFactory.getKeyManagers(),
trustManagerFactory.getTrustManagers(), new SecureRandom());
URL url = ...
URLConnection connection = url.openConnection();
((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
connection.setReadTimeout(40000);
connection.setConnectTimeout(40000);
connection.setDoInput(true);
connection.setDoOutput(false);
int respCode = ((HttpURLConnection) connection).getResponseCode();
if (respCode != 200)
throw new RuntimeException(...);
BufferedInputStream bufferedIs = new BufferedInputStream(connection.getInputStream());
try {
byte[] buf = new byte[512];
int j;
while ((j = bufferedIs.read(buf)) != -1) {
...
} finally {
bufferedIs.close();
}
내가 어떤 도움을 부탁드립니다.
두 개의 다른 키 저장소와 신뢰 저장소를 사용하고 있습니까? 만약 그렇다면, 그렇게해서는 안되며 그렇지 않다면 두 번 힘들게 두 번 구성하지 말고 동일한 SSLContext를 두 번 사용해야합니다. – EJP
@EJP 물론 모든 경우마다 다른 키/트러스트 스토어를 사용하고 있습니다. 'SSLContext'는 코드 샘플 에서처럼 두 번 만들어집니다. – briarheart