안드로이드 어플리케이션은 .keystore 파일을 이용해 내 앱을 사인(signing)할 수 있다. 앱이나 키스토어(keystore)가 한두개라면 모르겠지만, 각 앱마다 다른 키스토어를 만들었다거나 테스트용, 릴리즈용 등으로 여러개의 앱을 가지고 있다보면 사인이 되긴 된건지, 어떤 키로 사인이 된건지 헷갈린다. (CI 환경을 만들어서 차곡차곡 정리해두면 헷갈리 없겠지만) 사인이 된 앱을 가지고 있고, 이 앱이 어떤 키스토어로 사인이 되었는지 확인하고 싶다면 어떻게 해야할까? 결론부터 이야기하면, 앱과 키스토어의 Certificate fingerprint를 비교하면 된다. 먼저 키스토어에서
fingerprint를 확인해보자. 키스토어의 비밀번호를 입력하면 다음과 같이 키스토어에 포함된 alias 들의 정보가 출력된다. 출력된 데이터에서 Certificate fingerprint 부분을 확인한다. 이번에는 사인된 앱에서 Certificate fingerprint를 확인해보자. 키스토어를 확인할 때와 마찬가지로 keytool을 이용한다. 위와 같이 커맨드라인에서 입력하면, 앱 안의 META-INF 폴더 안의 .RSA 파일에서 인증서 정보를 추출하여 인증서의 정보를 보여준다. 그 중에서 같은 방법으로 만들어진 Certificate fingerprint를 비교해서 같다면, 이 앱은 이 키스토어로 사인된 것으로 보면 된다. 그리고 위에서 언급했듯이 인증서의 위치가 META-INF/*.RSA로 고정되어 있다. 그러므로, .apk 파일을 압축해제 한 후에
META-INF/*.RSA 파일에 아래 명령어를 실행해도 Certificate fingerprint를 꺼낼 수 있다. 참조
Java 는 KeyStore 라는 인터페이스를 통해 Encryption/Decryption 및 Digital Signature 에 사용되는 Private Key, Public Key 와 Certificate 를 추상화하여 제공하고 있다.
KeyStore 를 구현한 Provider 에 따라 실제 개인키가 저장되는 곳이 로컬 디스크이든 HSM 같은 별도의 하드웨어이든 아니면 Windows 의 CertStore나 OSX 의 KeyChain 이든 상관없이 사용자는 소스 코드 수정없이 키와 인증서를 가져올 수 있고 이를 이용하여 데이타 암복호화, 전자서명을 수행할 수 있다.
keytool 은 Keystore 기반으로 인증서와 키를 관리할 수 있는 커맨드 방식의 유틸리티로 JDK 에 포함되어 있다. 커맨드 방식의 openssl 과 비슷한 용도로 사용할 수 있는 프로그램이라 보면 될 것 같다.
옵션없이 keytool 을 실행하면 다음과 같이 메인 command 를 표시한다.
keytool Key and Certificate Management Tool Commands: -certreq Generates a certificate request -changealias Changes an entry's alias -delete Deletes an entry -exportcert Exports certificate -genkeypair Generates a key pair -genseckey Generates a secret key -gencert Generates certificate from a certificate request -importcert Imports a certificate or a certificate chain -importkeystore Imports one or all entries from another keystore -keypasswd Changes the key password of an entry -list Lists entries in a keystore -printcert Prints the content of a certificate -printcertreq Prints the content of a certificate request -printcrl Prints the content of a CRL file -storepasswd Changes the store password of a keystore Use "keytool -command_name -help" for usage of command_name
CODE
커맨드마다 하위 옵션이 있으며 커맨드의 상세 설명을 보려면 -help 옵션을 커맨드 뒤에 추가하면 된다.
다음은 공개키와 개인키 두 개의 키쌍을 생성하는 -genkeypair 명령의 옵션을 표시하는 예제이다.
keytool -genkeypair -help keytool -genkeypair [OPTION]... Generates a key pair Options: -alias <alias> alias name of the entry to process -keyalg <keyalg> key algorithm name -keysize <keysize> key bit size -sigalg <sigalg> signature algorithm name -destalias <destalias> destination alias -dname <dname> distinguished name -startdate <startdate> certificate validity start date/time -ext <value> X.509 extension -validity <valDays> validity number of days -keypass <arg> key password -keystore <keystore> keystore name -storepass <arg> keystore password -storetype <storetype> keystore type -providername <providername> provider name -providerclass <providerclass> provider class name -providerarg <arg> provider argument -providerpath <pathlist> provider classpath -v verbose output -protected password through protected mechanism Use "keytool -help" for all available commands
CODE
keytool 을 사용할 경우 명시적으로 -keystore 옵션으로 키스토어 파일의 경로를 지정하지 않으면 기본적으로 사용자의 홈디렉터리에서 .keystore 파일을 찾게 된다.
keystore 는 여러 가지 타입을 지원하는데 기본적으로는 JKS(Java KeyStore) 라는 타입으로 처리된다.
다음은 jks_keystore 라는 파일 이름으로 JKS 방식의 키스토어를 생성하는 명령어로 JKS 는 기본 옵션이므로 -storetype jks 은 생략 가능하다.
keytool -genkeypair -keystore jks_keystore -storetype jks
CODE
인증서와 개인키를 저장하는 또 다른 표준인 PKCS12 타입을 사용할 경우 다음과 같이 -storetype 옵션을 추가하면 된다.
keytool -genkeypair -keystore pkcs12_keystore -storetype pkcs12
CODE
Windows 와 Mac OSX 는 OS 에 개인키와 인증서를 저장하는 공간이 따로 있는데 keytool 로 접근이 가능하다. Windows-MY 는 사용자의 인증서와 개인키를 저장하는 공간이며 Windows-ROOT 는 신뢰하는 루트 인증서를 저장하는 공간이다. OSX 의 키체인(KeyChain) 에 접근시 KeychainStore 를 타입으로 지정하면 된다. 그외 Bouncy Castle 를 JCE Provider 로 사용할 경우 BKS 타입을 사용할 수 있다.
인증서 목록 출력
다음 명령으로 KeyStore 내 인증서 목록을 출력할 수 있다.
$ keytool -list -keystore my-keystore.jks
BASH
JRE 에 포함되어 있는 기본 인증기관(ca) 인증서 파일은 jre/lib/security/cacerts/cacerts 파일에 존재한다. 다음 명령은 기본 ca 목록을 출력한다.
$ keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts
BASH
-importcert 명령으로 인증서를 임포트할 수 있다. 만약 인증기관 인증서라면 -trustcacerts 옵션을 추가한다.
$ keytool -importcert -keystore my-keystore.jks -storepass changeit -trustcacerts -alias rootca -file "rootca.der"
CODE
keytool 은 외부에서 생성된 private key 를 keystore 에 import 하는 방법을 제공하지 않는다. 한 가지 방법은 JDK 6 이상부터 PKCS#12 으로 된 인증서와 개인키를 keystore 에 import 하는게 가능하므로 openssl 로 pkcs#12 를 만들고 pkcs#12 를 KeyStore 로임포트하면 된다.
이미 외부에서 개인키(mycert.key)와 인증서(mycert.crt)는 생성되었다고 가정한다.
인증서와 개인키가 DER 방식으로 encoding 되어있으면 openssl 에서 pkcs12 로 변환하지 못하니 PEM 형식으로 변환해야 한다. 에디터로 열어서 다음과 같이 텍스트로 표시되면 PEM 이고 바이너리면 DER 이므로 변환해야 한다.
PEM 예제
-----BEGIN CERTIFICATE-----
MIIFeDCCBGCgAwIBAgIBGTANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJLUjEN
MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo
b3JpdHkgQ2VudHJhbDEbMBkGA1UEAwwSS2lzYSBUZXN0IFJvb3RDQSA1MB4XDTEx-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA6KLO6jGTx1NMZsN3QJh/YCrVgmZsHlaD8sSFIFUcc5wH0gy6
oKggrOD7gE9CPRb3MQG53hx29c92ih/cFKrN1IoeSPj0ftxZPhKUczfot2CAH3GX
BWh0OYeuCIv088aKhSMJJLP9ZruC6Zhb01HYJiWdpOMX53fSMRJZYgjlIHZMi76u
ofLnvuP2Ry8VJntw2RFJeei0Z+6+YpHJlQbuzIrUjzNe6aCZMerbCtMoO7GnNN0y
lYl2P+D9aDhypB4bH2tGQ4mYSSdCXslO46C9zeesStZkSanXbZCvP4dYmr2o7STeopenssl 로 변환
BASH
openssl 로 PKCS12 생성
$ openssl pkcs12 -export -in mycert.crt -inkey mycert.key -out mykeystore.p12 -name "some alias"
CODE
- Enter Export Password: 에 pkcs12 암호 입력(예: qwert123)
keytool 로 PKCS12 를 KeyStore 로 변환
$ keytool -importkeystore -deststorepass changeit -destkeypass changeit -destkeystore my-keystore.jks -srckeystore mykeystore.p12 -srcstoretype PKCS12 -srcstorepass qwert123 -alias "some alias"
BASH
$ keytool -changealias -keystore MY_KEYSTORE_2.jks -alias OLD_ALIAS -destalias NEW_ALIAS
CODE
Key Store 에 저장된 개인키를 보호하기 위해 key store 자체에 대해서 암호를 걸 수 있고 특정 alias 에 저장된 개인키에도 암호를 걸 수 있다.
keystore 암호 변경
jks_keystore 라는 키스토어 파일의 암호를 변경한다.
$ keytool -storepasswd -keystore jks_keystore Enter keystore password: New keystore password: Re-enter new keystore password:
CODE
key 암호 변경
jks_keystore 라는 키스토어 파일내의 mykey 라는 alias 를 가진 개인키의 암호를 변경한다.
$ keytool -keypasswd -alias mykey -keystore jks_keystore Enter keystore password: Enter key password for <mykey> New key password for <mykey>: Re-enter new key password for <mykey>:
CODE
- OpenSSL 자주 쓰는 명령어(command) 및 사용법, tip 정리
- Java 에서 ValidatorException 등 인증서 관련 에러 해결 - keystore에 SSL/TLS 인증서를 import 하기
- KeyStore Type 정리 - //stackoverflow.com/questions/11536848/keystore-type-which-one-to-use
- //docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html