Documentation

§X.509 証明書の生成

§X.509 証明書

公開鍵証明書は本人性に関する問題を解決します。暗号化だけでもセキュアな接続をセットアップするには十分ですが、会話しているサーバが、あなたが会話していると思っているサーバである保証はありません。リモートサーバの本人性を検証する手段がなければ、攻撃者は依然としてリモートサーバとして居座り続けて、セキュアな接続をリモートサーバにフォワードすることができます。

公開鍵証明書はパスポートシステムとして考えるのがもっとも良い方法です。証明書は、偽造することが困難な方法で情報の運搬に関する情報を確立するために使われます。これが、証明書の検証がとても重要である理由です: すべての 証明書を受け入れることは、攻撃者の証明書さえ盲目的に受け入れてしまうことを意味します。

§キーツールを使う

JDK 8 に付属するバージョンのキーツールを使います:

以下の例では、CA の使い方、またはホスト名のための証明書を、キーツール 1.8 を使って作ります。

§ランダムなパスワードの生成

pwgem を使ってランダムなパスワードを作ります (Mac の場合は brew install pwgen):

export PW=`pwgen -Bs 10 1`
echo $PW > password

§サーバの設定

ホスト名検証のために、ホスト名が登録された DNS サーバが必要になります。この例では、ホスト名を example.com と仮定します。

§サーバ証明書の生成

はじめの一歩は、example.com 証明書に署名する認証局を作成することです。ルート CA 証明書は、それが CA 証明書であることを示すいくつかの追加属性 (ca:true や keyCertSign) を持っており、トラストストアに保持されます。

export PW=`cat password`

# Create a self signed key pair root CA certificate.
keytool -genkeypair -v \
  -alias exampleca \
  -dname "CN=exampleCA, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US" \
  -keystore exampleca.jks \
  -keypass:env PW \
  -storepass:env PW \
  -keyalg RSA \
  -keysize 4096 \
  -ext KeyUsage:critical="keyCertSign" \
  -ext BasicConstraints:critical="ca:true" \
  -validity 9999

# Export the exampleCA public certificate as exampleca.crt so that it can be used in trust stores.
keytool -export -v \
  -alias exampleca \
  -file exampleca.crt \
  -keypass:env PW \
  -storepass:env PW \
  -keystore exampleca.jks \
  -rfc

§example.com 証明書の生成

example.com 証明書は、以下のハンドシェイクで example.com サーバより提示されます。

export PW=`cat password`

# Create a server certificate, tied to example.com
keytool -genkeypair -v \
  -alias example.com \
  -dname "CN=example.com, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US" \
  -keystore example.com.jks \
  -keypass:env PW \
  -storepass:env PW \
  -keyalg RSA \
  -keysize 2048 \
  -validity 385

# Create a certificate signing request for example.com
keytool -certreq -v \
  -alias example.com \
  -keypass:env PW \
  -storepass:env PW \
  -keystore example.com.jks \
  -file example.com.csr

# Tell exampleCA to sign the example.com certificate. Note the extension is on the request, not the
# original certificate.
# Technically, keyUsage should be digitalSignature for DHE or ECDHE, keyEncipherment for RSA.
keytool -gencert -v \
  -alias exampleca \
  -keypass:env PW \
  -storepass:env PW \
  -keystore exampleca.jks \
  -infile example.com.csr \
  -outfile example.com.crt \
  -ext KeyUsage:critical="digitalSignature,keyEncipherment" \
  -ext EKU="serverAuth" \
  -ext SAN="DNS:example.com" \
  -rfc

# Tell example.com.jks it can trust exampleca as a signer.
keytool -import -v \
  -alias exampleca \
  -file exampleca.crt \
  -keystore example.com.jks \
  -storetype JKS \
  -storepass:env PW << EOF
yes
EOF

# Import the signed certificate back into example.com.jks 
keytool -import -v \
  -alias example.com \
  -file example.com.crt \
  -keystore example.com.jks \
  -storetype JKS \
  -storepass:env PW

# List out the contents of example.com.jks just to confirm it.  
# If you are using Play as a TLS termination point, this is the key store you should present as the server.
keytool -list -v \
  -keystore example.com.jks \
  -storepass:env PW

以下のように表示されるはずです:

Alias name: example.com
Creation date: ...
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: CN=example.com, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US
Issuer: CN=exampleCA, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US

注意: より詳しくは Configuring HTTPS の章を参照してください。

§example.com 証明書を Nginx に設定する

example.com が TLS 終端に Java を使用しておらず、nginx を使っている場合は、証明書を PEM フォーマットで出力する必要があります。

残念ながらキーツールは秘密鍵の情報を出力しないので、これを引っ張り出すために openssl をインストールする必要があります。

export PW=`cat password`

# Export example.com's public certificate for use with nginx.
keytool -export -v \
  -alias example.com \
  -file example.com.crt \
  -keypass:env PW \
  -storepass:env PW \
  -keystore example.com.jks \
  -rfc

# Create a PKCS#12 keystore containing the public and private keys.
keytool -importkeystore -v \
  -srcalias example.com \
  -srckeystore example.com.jks \
  -srcstoretype jks \
  -srcstorepass:env PW \
  -destkeystore example.com.p12 \
  -destkeypass:env PW \
  -deststorepass:env PW \
  -deststoretype PKCS12

# Export the example.com private key for use in nginx.  Note this requires the use of OpenSSL.
openssl pkcs12 \
  -nocerts \
  -nodes \
  -passout env:PW \
  -passin env:PW \
  -in example.com.p12 \
  -out example.com.key

# Clean up.
rm example.com.p12

これで example.com.crt (公開鍵証明書) と example.com.key (秘密鍵) の両方が手に入ったので、HTTPS サーバをセットアップすることができます。

例えば、この鍵を nginx で使う場合は nginx.conf を以下のように設定します:

ssl_certificate      /etc/nginx/certs/example.com.crt;
ssl_certificate_key  /etc/nginx/certs/example.com.key;

(次の クライアントの設定 で触れる) クライアント認証を使う場合、以下も追加する必要があります:

ssl_client_certificate /etc/nginx/certs/clientca.crt;
ssl_verify_client on;

サーバを確認することで、期待している証明書であることを確認できます:

keytool -printcert -sslserver example.com

注意: より詳しくは フロントエンド HTTP サーバの設定 の章を参照してください。

§クライアントの設定

クライアントの設定は二箇所あります – トラストストアの設定と、クライアント認証の設定です。

§トラストストアの設定

どのようなクライアントでも、example.com サーバの証明書が信頼できることを確認する必要がありますが、秘密鍵を確認する必要はありません。この証明書だけを含み、そしてこれをクライアントに手渡すトラストストアを生成しましょう。多くの Java クライアントは JKS フォーマットのトラストストアを好んでいます。

export PW=`cat password`

# Create a JKS keystore that trusts the example CA, with the default password.
keytool -import -v \
  -alias exampleca \
  -file exampleca.crt \
  -keypass:env PW \
  -storepass changeit \
  -keystore exampletrust.jks << EOF
yes
EOF

# List out the details of the store password.
keytool -list -v \
  -keystore exampletrust.jks \
  -storepass changeit

exampleca の trustedCertEntry が確認できるはずです:

Alias name: exampleca
Creation date: ...
Entry type: trustedCertEntry

Owner: CN=exampleCA, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US
Issuer: CN=exampleCA, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US

exampletrust.jks ストアはトラストマネージャで使われます。

play.ws.ssl {
  trustManager = {
    stores = [
      { path = "/Users/wsargent/work/ssltest/conf/exampletrust.jks" }
    ]
  }
}

注意: より詳しくは トラストストアとキーストアの設定 の章を参照してください。

§クライアント認証の設定

クライアント認証はドキュメントが貧弱で曖昧になりがちですが、以下の手順によって成り立っています。

  1. サーバは、署名されたクライアント証明書を期待する CA を提示することで、クライアント証明書を要求します。この場合は、CN=clientCA (デバッグ例 を参照してください) がこれに当たります。
  2. クライアントは chooseClientAliascertRequest.getAuthorities を使って、キーマネージャの中から clientCA によって署名された証明書を探します。
  3. キーマネージャは client 証明書をサーバに返します。
  4. サーバはこのハンドシェイクにおいて、さらに ClientKeyExchange を行います。

クライアント CA と署名したクライアント証明書を作成する手順は、サーバー証明書の生成と大部分で似ていますが、利便性のために単一のスクリプトを提供しています:

export PW=`cat password`

# Create a self signed certificate & private key to create a root certificate authority.
keytool -genkeypair -v \
  -alias clientca \
  -keystore client.jks \
  -dname "CN=clientca, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US" \
  -keypass:env PW \
  -storepass:env PW \
  -keyalg RSA \
  -keysize 4096 \
  -ext KeyUsage:critical="keyCertSign" \
  -ext BasicConstraints:critical="ca:true" \
  -validity 9999

# Create another key pair that will act as the client.
keytool -genkeypair -v \
  -alias client \
  -keystore client.jks \
  -dname "CN=client, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US" \
  -keypass:env PW \
  -storepass:env PW \
  -keyalg RSA \
  -keysize 2048

# Create a certificate signing request from the client certificate.
keytool -certreq -v \
  -alias client \
  -keypass:env PW \
  -storepass:env PW \
  -keystore client.jks \
  -file client.csr

# Make clientCA create a certificate chain saying that client is signed by clientCA.
keytool -gencert -v \
  -alias clientca \
  -keypass:env PW \
  -storepass:env PW \
  -keystore client.jks \
  -infile client.csr \
  -outfile client.crt \
  -ext EKU="clientAuth" \
  -rfc

# Export the client-ca certificate from the keystore.  This goes to nginx under "ssl_client_certificate"
# and is presented in the CertificateRequest.
keytool -export -v \
  -alias clientca \
  -file clientca.crt \
  -storepass:env PW \
  -keystore client.jks \
  -rfc

# Import the signed certificate back into client.jks.  This is important, as JSSE won't send a client
# certificate if it can't find one signed by the client-ca presented in the CertificateRequest.
keytool -import -v \
  -alias client \
  -file client.crt \
  -keystore client.jks \
  -storetype JKS \
  -storepass:env PW

# Export the client CA's certificate and private key to pkcs12, so it's safe.
keytool -importkeystore -v \
  -srcalias clientca \
  -srckeystore client.jks \
  -srcstorepass:env PW \
  -destkeystore clientca.p12 \
  -deststorepass:env PW \
  -deststoretype PKCS12

# Import the client CA's public certificate into a JKS store for Play Server to read.  We don't use
# the PKCS12 because it's got the CA private key and we don't want that.
keytool -import -v \
  -alias clientca \
  -file clientca.crt \
  -keystore clientca.jks \
  -storepass:env PW << EOF
yes
EOF

# Then, strip out the client CA alias from client.jks, just leaving the signed certificate.
keytool -delete -v \
 -alias clientca \
 -storepass:env PW \
 -keystore client.jks

# List out the contents of client.jks just to confirm it.
keytool -list -v \
  -keystore client.jks \
  -storepass:env PW

以下のような client というエイリアスがあるはずです:

Your keystore contains 1 entry

Alias name: client
Creation date: ...
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: CN=client, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US
Issuer: CN=clientCA, OU=Example Org, O=Example Company, L=San Francisco, ST=California, C=US

そして、client.jks をキーマネージャに配置します:

play.ws.ssl {
  keyManager = {
    stores = [
      { type = "JKS", path = "conf/client.jks", password = $PW }
    ]
  }
}

注意: より詳しくは トラストストアとキーストアの設定 の章を参照してください:

§証明書管理ツール

コマンドラインツールよりも、グラフィカルなツールで証明書を検査したい場合は Keystore Explorerxca を使うことができます。Keystore Explorer は JKS フォーマットを認識するので特に便利です。このツールは、手動インストールするとよく良く動作し、出力ポリシーにちょっとした調整が必要です。

キーツールよりも柔軟なコマンドラインツールを使いたい場合は、マルチパート PEM フォーマット証明書と JKS を理解する java-keyutil を試してみてください。

§証明書の設定

§セキュリティ

最高のセキュリティを求める場合は、(キーツールでは -sigalg EC であろう) 署名アルゴリズムに ECDSA を使うことを検討してください。ECDSA は “ECC SSL Certificate” としても知られています。

§互換性

古いシステムとの互換性には、署名アルゴリズムに 2048 bit 鍵の RSA と SHA256 を使ってください。独自の CA 証明書を作成している場合は、4096 bit のルートを使用してください。

§併せて読みたい

Next: トラストストアとキーストアの設定


このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。