Java PKIX path building failed: 에러 해결

TL;DR

SSL 인증서를 추출해서 Java VM 에 등록해 주면 해결됩니다.

curl -O https://gist.githubusercontent.com/lesstif/cd26f57b7cfd2cd55241b20e05b5cd93/raw/InstallCert.java
javac InstallCert.java


에러나는 사이트 주소(Ex: lesstif.com) 를 넣고 실행후 SSL 인증서 추출

java -cp ./ InstallCert lesstif.com


개요

Java 에서 HTTPS 로 다른 사이트에 연결할 경우 다음과 같이 "ValidatorException: PKIX path building failed" 에러를 만나는 경우가 있습니다.

Caused by: javax.naming.CommunicationException: simple bind failed: <server-name>

[Root exception is 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\


대부분의 원인은 원격 사이트에서 사용하는 SSL 인증서 정보가 현재 JVM 의 신뢰하는 인증기관 인증서 목록에 등록되어 있지 않기때문이며 JVM 의 keystore 에 인증서를 넣어주고 재구동하면 해결됩니다.

처리

Java 인증서 관련 에러 해결 문서에 여러 가지 방법을 정리해 놨는데 그 중에서 SSL 인증서를 추출하는 InstallCert 를 사용하는 방법을 설명합니다.


먼저 github 에 올려 놓은 소스를 다운로드 받습니다.

curl -O https://gist.githubusercontent.com/lesstif/cd26f57b7cfd2cd55241b20e05b5cd93/raw/InstallCert.java


다운받은 소스를 컴파일합니다.

javac InstallCert.java


installCert 를 연결하려는 사이트 이름(예: lesstif.com)과 함께 실행합니다.

java -cp ./ InstallCert  lesstif.com


서버가 2 개의 인증서를 전송했는데 보통 아래에 있는게 CA 의 인증서이며 이 경우 2번째가 Let's Encrypt 의 CA 인증서이므로 2번을 선택해서 저장해야 합니다.

No errors, certificate is already trusted

Server sent 2 certificate(s):

 1 Subject CN=lesstif.com
   Issuer  CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
   sha1    c6 9e d1 7a ed 37 45 04 98 36 43 07 dd e1 77 cd 8f a3 51 0e 
   md5     bc f8 da 1f f9 38 a0 c4 45 49 0e 33 32 ca 61 53 

 2 Subject CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
   Issuer  CN=DST Root CA X3, O=Digital Signature Trust Co.
   sha1    e6 a3 b4 5b 06 2d 50 9b 33 82 28 2d 19 6e fe 97 d5 95 6c cb 
   md5     b1 54 09 27 4f 54 ad 8f 02 3d 3b 85 a5 ec ec 5d 

Enter certificate to add to trusted keystore or 'q' to quit: [1]
2


다음과 같은 메시지가 나오고 저장되는데 keystore(jssecacerts) 명과 alias(lesstif.com-2) 명을 기억합니다.

Added certificate to keystore 'jssecacerts' using alias 'lesstif.com-2'



이제 생성된 keystore 파일 jssecacerts 에 있는 인증서를 output.cert 라는 파일로 저장합니다. -alias 옵션 뒤에는 위에서 표시한 alias 이름을 주어야 합니다.

keytool -exportcert -keystore jssecacerts -storepass changeit -file output.cert -alias lesstif.com-2

JAVA_HOME 변수가 설정되어 있어야 하며 root 로 실행해야 합니다.


아래 명령어로 JVM 의 keystore 에 CA 인증서를 추가합니다.

sudo  keytool -importcert -keystore ${JAVA_HOME}/lib/security/cacerts -storepass changeit -file output.cert -alias letsencrypt


만약 해당 label 이 있다면 다음 에러가 발생합니다.

keytool error: java.lang.Exception: Certificate not imported, alias <letsencrypt> already exists


이 경우 아래 명령어로 기존 label 을 삭제합니다.

sudo keytool -delete  -keystore ${JAVA_HOME}/lib/security/cacerts -storepass changeit  -alias letsencrypt


위 과정은 첨부 이미지를 보면 확인할 수 있습니다.

같이 보기