httpclient를 이용해서 SSL 접속 하기

httpclient로 웹 접속을 할 경우 ssl 오류가 나는 경우가 있다.

error message:
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)

 

같은 소스를 이용해서 다른 사이트를 접속할 경우에도 에러 안나는데 특정 사이트만 위 에러가 나온다.

(https://www.~~~ ) https 라고 무조건 위  처럼 SSL 오류 메세지는 나오지 않는다.

 

원인은 아래와 같다 한다.

  1. 연결하려는 remote site의 인증서가 신뢰하는 인증기관 인증서 목록(keystore)에 없음
  2. 서버/클라이언트간 사용하려는 SSL/TLS 버전이 맞지 않음(Ex:TLS 1.0 만 지원하는 서버에 1.2로 hand shaking 요청등)
  3. SSL/TLS 통신에 사용하려는 cipher suite 가 오래되거나 지원하지 않음. (Ex: JDK 1.8 부터는 RC4 를 사용하려고 하면 에러 발생)

 

작업할것은 2가지이다

 

  1. SSL 인증서를 만드는 것이다. ( 인증서라는 용어가 맞는지는 모르겄다.)
  2. http source 작성

1번작업

아래 사이트 보면 7번 사진에서 작업할 내용이 하나 더 있다.
8번. 저장한 인승서 선택 – 오른쪽 클릭 – export 하면 된다. 옵션은 기본 선택된것으로 한다.
https://www.lesstif.com/pages/viewpage.action?pageId=12451848

2번작업

  1.  만든 인증서를 java에서 사용하기 위해서는  .keystore 형식으로 저장해야 한다.
    위 1번작업에서 생성한   site.cer 를 site.keystore로 변경.
    keytool -import -v -trustcacerts -alias keyAlias -file d:\site.cer -keystore d:\site.keystore -keypass changeit -storepass changeit
  2. 소스 작성

 

		File keyFile = new File ("site.keystore1");
		if ( keyFile.exists() == false ){
			InputStream is = getClass().getResourceAsStream("site.keystore");
 
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
 
			OutputStream outStream = new FileOutputStream(keyFile);
			outStream.write(buffer);
			outStream.close();
		}
 
		<strong>SSLContext sslcontext = SSLContexts.custom()
				.loadTrustMaterial(keyFile, "changeit".toCharArray(),
						new TrustSelfSignedStrategy())
				.build();</strong>
 
 
		// Allow TLSv1 protocol only
		<strong>SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
				sslcontext,
				new String[] { "TLSv1" },
				null,
				SSLConnectionSocketFactory.getDefaultHostnameVerifier());
		CloseableHttpClient httpclient = HttpClients.custom()
				.setSSLSocketFactory(sslsf)
				.build();</strong>
//                 httpclient를 생성했으니 사용하면 된다.

굴게 표시한게 핵심이다.