Java 기반 시스템을 운영하다 보면 보안 설정을 위해서 인증서나 비밀 키를 저장하는 키스토어를 자주 다루게 된다.
특히 java.io.IOException: Invalid Keystore Format 예외는 어쩌면 가장 자주 마주치는 예외일 것이다.
이번 포스팅에서는 Baeldung의 최신 가이드를 바탕으로 이 에러의 원인을 파악하고 해결하는 실무 노하우에 대해서 정리하고자 한다.
이 에러는 keystore 파일 형식과 Java 코드에서 기대하는 형식(JKS, PKCS12등)이 일치하지 않거나 빌드 과정 또는 전송 중에 파일이 손상된 경우 발생하며 정확한 진단 도구와 설정을 통해 해결할 수 있다.
Invalid Keystore Format Error에 대한 3가지 주요 포인트
개발자 여러분들이 주목해야 할 핵심적인 에러 원인 및 진단 방법을 세가지로 정리해 보았다.
코드와 파일 형식의 불일치 선언
가장 흔한 원인 중 하나다. 파일 자체는 유효한 PKCS#12(.p12 또는 확장자가 혼동된 .jks) 형식인데 코드에서 KeyStore.getInstance(“JKS”)로 로드하려고 하는 경우다.
이 경우 파일의 형식에 맞춰 KeyStore.getInstance()의 타입을 정확히 지정해야 한다. (PKCS12 또는 JKS)
단순히 파일 확장자만으로 확인할 것이 아니라 실제 KeyStore 파일 형식의 형식을 확인해야 한다.
keytool 명령 확인
자바가 설치되어 있다면 keytool 명령을 통해 확인해 볼 수 있다.
keytool -list -v -keystore 파일명Bash파일 시그니처로 확인
파일의 첫 4byte 정보(파일 시그니처)를 통해서 확인할 수 있다.
리눅스나 맥 터미널에서 xxd 명령을 통해서 파일의 헤더를 확인해 볼 수 있다.
# 파일의 첫 1줄(16바이트)만 16진수로 출력
xxd -l 16 keystore.p12Bash출력
# JKS 파일
00000000: feed feed 0000 0002 ...
# PKCS12 파일
00000000: 3082 09c0 0201 0330 ...Plaintext바이너리 파일에 대한 빌드 도구의 텍스트 필터링 활성화
의외로 많은 개발자들이 놓치는 부분이다. Maven이나 Gradle 같은 빌드 도구가 리소스를 처리할 때 기본적으로 텍스트 파일에 변수 치환(Filtering)을 적용하는 경우가 많은데 이 때 바이너리 파일인 keystore 파일이 텍스트 필터링이 되어 내용이 변조되는 경우다.
pom.xml 혹은 build.gradle 설정에서 keystore 파일이 포함된 디렉토리 혹은 해당 keystore 파일에 대해서는 명시적으로 리소스 필터링을 비활성화 해야 한다.
maven
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
<nonFilteredFileExtension>pfx</nonFilteredFileExtension>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>XMLgradle
processResources {
// 텍스트 파일은 치환하되, 인증서 파일(.p12, .pfx)은 건드리지 않도록 설정
filesNotMatching(['**/*.p12', '**/*.pfx', '**/*.jks']) {
expand(project.properties)
}
}Groovykeytool 및 OpenSSL을 이용한 사전 진단
코드 작업 이전에 우선 keystore 파일 자체의 유효성과 내용을 확인하여 이상이 없음을 우선 체크한다. 앞서 소개한 keytool 명령을 통해 파일 유형과 함께 유효성을 체크할 수 있다.
keytool -list -v -keystore 파일명Bash파일이 유효하면 비밀번호 입력 요청이 생기고 keystore에 대한 상세 정보를 출력한다. 파일이 잘못된 형식인 경우에는 Exception 메시지가 출력된다.
openssl pkcs12 -info -in xxxx.jksBash파일 확장자가 jks라도 실제로는 PKCS#12 형식일 수 있으므로 OpenSSL 명령을 사용해 실제 형식을 진단할 수 있다. 위 명령에서 파일을 성공적으로 읽는 다면 xxxx.jks 파일은 실제로 PKCS#12 형식임을 확인할 수 있다.
코드 작업
위 내용을 통해 keystore 파일 유형과 유효성을 파악했다면 코드 작업에 착수한다.
파일이 PKCS#12 형식이라면 다음과 같이 로딩한다.
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("keystore.p12"), "password".toCharArray());Java기존의 JKS 형식이라면 다음과 같이 로딩한다.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("keystore.jks"), "password".toCharArray());Java앞서 알아본 바와 같이 코드 내 keystore 형식이 실제 파일 형식과 일치하도록 하면 java가 데이터를 잘못 해석하는 것을 방지하고 형식 오류를 제거할 수 있다.
형식 변경
그래도 keystore 형식이 예상된 것과 일치하지 않는다면 keytool을 통해 변환할 수 있다.
$ keytool -importkeystore \
-srckeystore keystore.p12 -srcstoretype pkcs12 \
-destkeystore keystore.jks -deststoretype jksBash변환 후 keytool -list 명령을 통해서 변환된 파일이 이상없이 로드되는지 확인할 수 있다.
keystore 형식 에러는 자주 발생하지만 해결책은 의외로 간단하다. keystore 파일의 실제 형식과 코드의 기대 형식을 일치시키는 것이 중요하고 파일이 변조되지 않도록 관리하는 것이다.
참고링크 (밸덩)
https://www.baeldung.com/java-resolve-ioexception-invalid-keystore-format-error