PKIX path building failed

Allow·2023년 3월 17일
0

SpringBoot에서 feignClient를 사용해 외부 API를 호출하니 아래와 같은 오류가 발생했다.

https Error - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException

원인

대부분의 원인은 연결하려는 site의 인증서가 JVM의 신뢰하는 인증서 목록에 없는 경우이다.


해결방법

문제되는 사이트의 SSL인증서를 추출해서 등록하면 해결된다.

1. InstallCert.java 다운로드

lesstif님의 gist에서 다운로드 받았고 다른 경로에서 다운로드 받아도 된다.

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

2. 다운로드 받은 코드를 컴파일

javac InstallCert.java

3. 연결하려는 사이트 도메인을 포함하여 실행

java -cp ./ InstallCert test.com
Loading KeyStore jssecacerts...
Opening connection to test.com:443...
Starting SSL handshake...

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:353)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:296)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:291)
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357)
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232)
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175)
	at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
	at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:183)
	at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172)
	at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1506)
	at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1416)
	at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:456)
	at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:427)
	at InstallCert.main(InstallCert.java:116)
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 java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
	at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
	at java.base/sun.security.validator.Validator.validate(Validator.java:264)
	at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:233)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:110)
	at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:199)
	at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1510)
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1341)
	... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
	at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
	... 20 more

Server sent 2 certificate(s):

 1 Subject CN=*.test.com
   Issuer  CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   sha1    50 40 9c e4 8d ae 8e 51 a2 16 96 f8 cb bd 61 55 04 4a 13 2a
   md5     52 99 43 a8 1b a8 5e 6c 3e ae ba 4f 57 bc ed 43

 2 Subject CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   Issuer  CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   sha1    97 fe 03 0c 78 ce 02 c9 a8 e3 c8 4b e8 76 f6 fd 85 b1 a9 63
   md5     bc 40 06 6d ff 9c c4 3f 24 8c bf ca cc f6 f7 e6

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

4. 2개의 인증서 중 두번째 인증서를 선택하여 저장한다.

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

5. 아래와 같은 메세지가 출력되는데 keystore(jssecacerts)값과 alias(test.com-2)를 기억하거나 저장한다.

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

6. keystore파일 jssecacerts에 있는 인증서를 output.cert라는 파일로 저장

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

7. jvm의 keystore에 인증서를 추가

sudo  keytool -importcert -keystore ${JAVA_HOME}/lib/security/cacerts -storepass changeit -file output.cert -alias letsencrypt
소유자: CN=*.test.com
발행자: CN=Symantec CA, O=*****, L=Seoul, ST=Seoul, C=KR
일련 번호: 9d0ff9bc92058720082601b3fc857587
적합한 시작 날짜: Mon Oct 24 01:42:17 KST 2022 종료 날짜: Sat Nov 25 01:42:16 KST 2023
인증서 지문:
	 SHA1: 50:40:9C:E4:8D:AE:8E:51:A2:16:96:F8:CB:BD:61:55:04:4A:13:2A
	 SHA256: 60:FE:80:32:76:A0:22:D9:A3:80:80:78:8C:E4:48:3E:C3:AE:D9:8B:67:84:9A:58:07:C6:1C:13:C8:B0:D4:38
서명 알고리즘 이름: SHA256withRSA
주체 공용 키 알고리즘: 2048비트 RSA 키
버전: 3

확장:

#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: *.test.com
]

이 인증서를 신뢰합니까? [아니오]:  y
인증서가 키 저장소에 추가되었습니다.

인증서 키가 저장되고 서버 restart를 하면 정상적으로 실행된다.

Ref

https://github.com/lesstif

profile
반갑습니다!

0개의 댓글