Keytool 인증서 정보 확인 - Keytool injeungseo jeongbo hwag-in

안드로이드 어플리케이션은 .keystore 파일을 이용해 내 앱을 사인(signing)할 수 있다. 앱이나 키스토어(keystore)가 한두개라면 모르겠지만, 각 앱마다 다른 키스토어를 만들었다거나 테스트용, 릴리즈용 등으로 여러개의 앱을 가지고 있다보면 사인이 되긴 된건지, 어떤 키로 사인이 된건지 헷갈린다. (CI 환경을 만들어서 차곡차곡 정리해두면 헷갈리 없겠지만)

사인이 된 앱을 가지고 있고, 이 앱이 어떤 키스토어로 사인이 되었는지 확인하고 싶다면 어떻게 해야할까? 결론부터 이야기하면, 앱과 키스토어의 Certificate fingerprint를 비교하면 된다.

먼저 키스토어에서 fingerprint를 확인해보자.

>keytool -list -keystore my-keystore.keystore
Enter keystore password:

키스토어의 비밀번호를 입력하면 다음과 같이 키스토어에 포함된 alias 들의 정보가 출력된다.

Keystore type: JKS 
Keystore provider: SUN 

Your keystore contains 1 entry 

my-service, 2016. 10. 19, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 3C:B6:68:E2:8A:EC:9F:16:7E:2C:20:AA:B2:71:12:1B:98:F2:1E:D9

출력된 데이터에서 Certificate fingerprint 부분을 확인한다.

이번에는 사인된 앱에서 Certificate fingerprint를 확인해보자. 키스토어를 확인할 때와 마찬가지로 keytool을 이용한다.

>keytool -list -printcert -jarfile my-app.apk

위와 같이 커맨드라인에서 입력하면, 앱 안의 META-INF 폴더 안의 .RSA 파일에서 인증서 정보를 추출하여 인증서의 정보를 보여준다.

...
Certificate fingerprints:
MD5: D8:2A:99:53:1E:7E:9D:B5:3A:44:FC:2D:99:48:38:17
SHA1: 3C:B6:68:E2:8A:EC:9F:16:7E:2C:20:AA:B2:71:12:1B:98:F2:1E:D9
SHA256: 5E:9C:8E:B8:D0:8E:E7:44:7B:5D:B5:1D:83:1F:D3:80:84:0C:F2:DC:15:DC:71:1E:E6:20:70:D6:B4:7B:9C:AB
...

그 중에서 같은 방법으로 만들어진 Certificate fingerprint를 비교해서 같다면, 이 앱은 이 키스토어로 사인된 것으로 보면 된다.

그리고 위에서 언급했듯이 인증서의 위치가 META-INF/*.RSA로 고정되어 있다. 그러므로, .apk 파일을 압축해제 한 후에 META-INF/*.RSA 파일에 아래 명령어를 실행해도 Certificate fingerprint를 꺼낼 수 있다.

keytool -printcert -file CERT.RSA

참조

  • http://www.sysnet.pe.kr/2/0/1132
  • http://www.herongyang.com/Cryptography/keytool-Export-Key-printcert-Command.html
  • http://stackoverflow.com/questions/11331469/how-to-find-out-which-key-was-used-to-sign-an-app

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 로임포트하면 된다.

  1. 이미 외부에서 개인키(mycert.key)와 인증서(mycert.crt)는 생성되었다고 가정한다.

  2. 인증서와 개인키가 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+D9aDhypB4bH2tGQ4mYSSdCXslO46C9zeesStZkSanXbZCvP4dYmr2o7STe

    openssl 로 변환

    ## 인증서를 PEM 으로 변환
    $ openssl x509 -inform der -in mycert.der -out mycert.crt
    ## 개인키 변환
    $ openssl rsa -inform der -in mycert.key.der -out mycert.key 

    BASH

  3. openssl 로 PKCS12 생성

    $ openssl pkcs12 -export -in mycert.crt -inkey mycert.key -out mykeystore.p12 -name "some alias"

    CODE

  4. Enter Export Password: 에 pkcs12 암호 입력(예: qwert123)
  5. 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 정리 - http://stackoverflow.com/questions/11536848/keystore-type-which-one-to-use
  • http://docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html