본문 바로가기
IT/Java

Java 인증서 추가 방법 ( SunCertPathBuilderException 해결 )

by 어느 개발자의 블로그 2021. 10. 27.
728x170

- 에러 로그

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

 

- 원인

Java에서는 따로 관리하는 신뢰하는 인증서 목록이 존재하는데 이 파일에  호출하는 도메인 인증서의 루트 인증서가 등록되어 있지 않을때 발생함.

 

- 해결 방법

1. 인증서 목록에서 존재 여부 찾기
1.1. 조회 명령어 ( 인증서 목록이 2개니 cacerts, jssecacerts 중에서 사용하는 파일에서 조회 - 확인은 아래 "테스트 방법" 에 존재 )
  * keytool -list -v -keystore ${JAVA_HOME}/jre/lib/security/cacerts -storepass changeit | grep -A 10 -B 10 "Thawte"
  * keytool -list -v -keystore ${JAVA_HOME}/jre/lib/security/jssecacerts -storepass changeit | grep -A 10 -B 10 "Thawte"
    ** -v : 자세한 keystore 항목 리스트 
    ** -keystore <keystore> : keystore 이름
    ** -storepass changeit : 비밀번호 
    ** -A 10 : 특정 문자열 이후 10줄
    ** -B 10 : 특정 문자열 이전 10줄

2. 인증서 추출
  * 인증서 제공 기관에서 다운로드 또는 해당 도메인에서 추출

3. 인증서 keystore에 추가 
 3.1. 다운로드 받은 인증서를 서버에 업로드
 3.2. 해당 인증서 경로로 이동
 3.3. su root 로 권한 변경
 3.4. keytool을 이용하여 keystore에 추가 ( 사용하는 인증서 목록 cacerts, jssecacerts 중에서 사용하는 곳에 추가 )
  * keytool -import -keystore ${JAVA_HOME}/jre/lib/security/jssecacerts -file "DigiCertGlobalRootG2.crt" -storepass changeit -alias "digicertglobalrootg2"
    ** -file <filename> : 추가할 인증서 파일명
    ** -alias <alias> : 추가할 인증서 파일의 별칭
  * 중복시 삭제 명령어 : keytool -delete -alias digicertglobalrootg2 -keystore ${JAVA_HOME}/jre/lib/security/jssecacerts -storepass changeit
 3.5. 인증서 추가 여부 확인에 "y" 입력
 3.6. 추가 완료되었다면 테스트
 3.7. 테스트 완료되었다면 서비스 재기동

 

- 테스트 방법

1. su root 로 권한 변경
2. vi SSLChecker.java 
3. 테스트 소스 복사 후 저장
4. javac SSLChecker.java 로 테스트 소스 컴파일
5. java SSLChecker <도메인> <포트> 로 도메인 연결 테스트
  * java SSLChecker tistory.com 443
    ** Error: Could not find or load main class SSLChecker 에러 발생시 : java -cp . SSLChecker tistory.com 443
  * 사용하는 인증서 파일을 보고 싶은 경우 
    ** -Djavax.net.debug=ssl 옵션 추가 : java -cp . -Djavax.net.debug=ssl SSLChecker tistory.com 443
    ** 출력의 최상단에 아래 예시와 같이 확인 가능.

※ -Djavax.net.debug=ssl 옵션 출력 예시
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: [JAVA HOME경로]/jre/lib/security/jssecacerts
trustStore type is : jks
trustStore provider is :
init truststore

- 테스트 SSLChecker.java 파일 소스

import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;

public class SSLChecker {
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Usage: "+SSLChecker.class.getName()+" <host> <port>");
            System.exit(1);
        }
        try {
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));
            //sslsocket.setEnabledProtocols(new String[] {"TLSv1.2"}); // TLS설정 : TLSv1, TLSv1.1, TLSv1.2

            SSLParameters sslparams = new SSLParameters();
            //sslparams.setProtocols(new String[] {"TLSv1.2"}); // TLS설정 : TLSv1, TLSv1.1, TLSv1.2
            sslparams.setEndpointIdentificationAlgorithm("HTTPS");
            sslsocket.setSSLParameters(sslparams);

            InputStream in = sslsocket.getInputStream();
            OutputStream out = sslsocket.getOutputStream();

            // Write a test byte to get a reaction :)
            out.write(1);

            while (in.available() > 0) {
                System.out.print(in.read());
            }
            System.out.println("Successfully connected");

        } catch (Exception exception) {
            exception.printStackTrace();
            System.exit(1);
        }
    }
}
반응형
그리드형

'IT > Java' 카테고리의 다른 글

Quartz 스케줄러 사용하기  (0) 2020.06.15

댓글