Java 에서 ValidatorException 등 인증서 관련 에러 해결 - keystore에 SSL/TLS 인증서를 import 하기
프로그램 자료/Java & Spring 2019. 7. 4. 17:26출처 : https://www.lesstif.com/pages/viewpage.action?pageId=12451848
2019/07/04 - [프로그램 자료/Java & Spring] - okhttp3 사용해서 RESTful API 호출하기
증상
java 에서 HTTPS 로 remote 사이트에 연결시 다음과 같은 Exception 이 발생
원인
다음과 같이 여러 가지 원인이 있을 수 있다.
- 연결하려는 remote site의 인증서가 신뢰하는 인증기관 인증서 목록(keystore)에 없음
- 서버/클라이언트간 사용하려는 SSL/TLS 버전이 맞지 않음(Ex:TLS 1.0 만 지원하는 서버에 1.2로 hand shaking 요청등)
- SSL/TLS 통신에 사용하려는 cipher suite 가 오래되거나 지원하지 않음. (Ex: JDK 1.8 부터는 RC4 를 사용하려고 하면 에러 발생)
- 웹 브라우저의 경우 인증서 경로 설정을 참고하여 웹 서버에 Intermediate CA certificate 를 설치한다.
무료 SSL 인증서를 발급해 주는 Let's encrypt 의 CA 인증서는 Java VM 에 포함되어 있지 않으므로 Let's encrypt 에서 발급 받은 SSL 인증서를 Java 에서 사용할 경우에도 위와 같은 에러가 발생한다.
해결
1번 원인일 경우 현재 구동되는 JDK 의 keystore에 상대방 인증서를 넣어줘야 함
CMD 에서 처리
gist 에서 InstallCert.Java 를 다운로드
curl -O https://gist.githubusercontent.com/lesstif/cd26f57b7cfd2cd55241b20e05b5cd93/raw/InstallCert.java
컴파일
javac InstallCert.java
InstallCert 구동
# localhost 에 SSL 인증서를 받아올 호스트명을 입력
java -cp ./ InstallCert lesstif.com
다음과 같은 화면이 나오면 1을 눌러서 인증서 저장
서버가 2 개의 인증서를 전송했는데 2번째가 Let's Encrypt 의 CA 인증서이므로 2번을 선택해서 저장해야 한다.
다음과 같은 메시지가 나오고 저장됨. keystore 명과 alias 명을 기억
keytool 로 keystore에서 인증서 추출 (KeyStore의 암호는 changeit 이라 가정!)
## alias 옵션뒤에 위의 alias명 입력
keytool -exportcert -keystore jssecacerts -storepass changeit -file output.cert -alias letsencrypt
-alias 옵션 뒤에 파라미터는 5번에서 저장된 alias(letsencrypt) 를 입력
현재 JDK 의 keystore에 cert import
## JAVA_HOME=/usr/java/jdk1.7.0_25
keytool -importcert -keystore ${JAVA_HOME}/jre/lib/security/cacerts -storepass changeit -file output.cert -alias letsencrypt
이미 존재할 경우 다음 명령어로 삭제
keytool -delete -alias letsencrypt -keystore ${JAVA_HOME}/jre/lib/security/cacerts -storepass changeit
Portecle GUI 사용
Java 로 개발된 GUI 기반의 Keystore 관리 유틸리티인 portecle 사용해서 keystore 관리하는 방법(https://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services#ConnectingtoSSLservices-Resolution)
- http://sourceforge.net/projects/portecle/files/latest/download 를 다운로드후 압축 해제
실행
- Examine SSL/TLS Connection: 실행
- 저장할 인증서를 선택후 PEM Encoding 클릭
- SSL 인증서를 $JRE\lib\security 에 저장
- Open keystore File 선택후 ${JAVA_HOME}\jre\lib\security\cacerts 파일 선택
- keystore 암호 입력(기본값 changeit)
- Import Trusted Ceritificate 선택
- 저장한 인증서 선택
- Keystore 저장
CA 별 Intermediate 인증서 등록
Comodo
comodo 의 root ca 인증서는 JVM에 포함되어 있지만 CA의 DN이 (CN = COMODO RSA Domain Validation Secure Server CA) 인경우 미포함이므로 keystore 에 넣어 주거나 웹 서버에 SSL 경로 구성을 해야 함(https://lesstif.gitbook.io/web-service-hardening/ssl-tls-https#undefined-5 참고)
CA 인증서 다운로드
curl -o comodo-domainca.crt https://gist.githubusercontent.com/lesstif/3fdfc2086b9834dbfbcd4461bfb68cd1/raw/76d3614bf86838a24343d0fddbb8ea39a9f1524c/comodo-domainca.crt
ROOT CA 인증서 다운로드
curl -o comodo-rootca.crt https://gist.githubusercontent.com/lesstif/3fdfc2086b9834dbfbcd4461bfb68cd1/raw/76d3614bf86838a24343d0fddbb8ea39a9f1524c/comodo-rootca.crt
- keystore 에 import 하거나 웹 서버에 인증서 경로 구성
코모도의 전체 CA 인증서 목록은 https://ssl.comodo.com/support/which-is-root-which-is-intermediate.php 를 참고
AlphaSSL
저렴한 https://www.alphassl.com 의 경우 Java 의 Keystore 에 포함되지 않았으므로 수작업으로 인증서를 넣어줘야 한다.
Alpha SSL root 인증서 다운로드
curl -o root.cer https://www.alphassl.com/support/roots/root.pem
https://www.alphassl.com/support/install-root-certificate.html 에 연결하여 발급한 인증서의 ca 인증서를 ca.cer 로 저장 (Ex: SHA-256 - Orders March 31, 2014 and After)
Key store 에 import
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -alias alpharoot -file root.cer -storepass changeit -noprompt
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -alias alphaca -file ca.cer -storepass changeit -noprompt
let's encrypt 인증서
무료 인증서 발급해 주는 https://letsencrypt.org 일 경우
전체 인증서 체인은 https://letsencrypt.org/certificates/ 참고
root cert 다운로드
curl -o root.cer https://letsencrypt.org/certs/isrgrootx1.pem
발급받은 인증서에 맞는 ca cert download(Ex: Let’s Encrypt Authority X3 (IdenTrust cross-signed):)
curl -o ca.cer https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem
Key store 에 import
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -alias letsroot -file root.cer -storepass changeit -noprompt
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -alias letsca -file ca.cer -storepass changeit -noprompt
확인
- 해당 사이트에 웹 브라우저로 연결하여 문제가 해결되었는지 확인
openssl 명령창으로 SSL 인증서 정보 확인
curl 로 연결해서 정보 확인
주의 사항
WAS 기반의 서비스일 경우 JDK 설정이 변경되었으므로 재구동이 필요함
JDK나 JRE 가 upgrade 될 경우 위의 작업을 다시 시행해야 함
같이 보기
- java keytool 사용법 - Keystore 생성, 키쌍 생성, 인증서 등록 및 관리
- OpenSSL 자주 쓰는 명령어(command) 및 사용법, tip 정리
- curl 에 신뢰하는 인증기관 인증서 추가하기
Ref
- http://stackoverflow.com/questions/6353849/received-fatal-alert-handshake-failure-through-sslhandshakeexception
- http://stackoverflow.com/questions/3685548/java-keytool-easy-way-to-add-server-cert-from-url-port
- https://confluence.atlassian.com/display/CONFKB/Unable+to+Connect+to+SSL+Services+due+to+PKIX+Path+Building+Failed+sun.security.provider.certpath.SunCertPathBuilderException
- http://nodsw.com/blog/leeland/2006/12/06-no-more-unable-find-valid-certification-path-requested-target
- https://stackoverflow.com/questions/5871279/java-ssl-and-cert-keystore