[pgsql-jp: 37623] Re: JAVAアプリケーションからのSSL接続

Masatoshi Sato okome @ siisise.net
2006年 10月 26日 (木) 04:15:09 JST


おこめです。

細かなところをいろいろつついてしまいます。
SSLは難しい。

岩瀬 肇 wrote:
> 岩瀬です。
> 
> PostgreSQLへJAVAアプリケーションからJDBC経由でSSL接続する手順を
> まとめましたので、提示します。
> 途中変な説明がありましたら、ご指摘いただけますと助かります。
> あと、ちょっと長いですし、色分けできないので読みにくいかもしれません。
> ご了承ください。
> 
> 
> 手順:
> 手順1.秘密鍵ファイルおよびサーバ証明書の作成
> openssl req -new -keyout 秘密鍵ファイル.pem -text -out サーバ証明書.req 
> というコマンドを使います。"-keyout 秘密鍵ファイル.pem" は
> 省略可能ですが、省略すると、"privkey.pem" という秘密鍵ファイルが
> 出来ます。

openssl genrsa -out server.key 1024

とするとパスワードなしで秘密鍵を生成できます。 -text は余計なので不要です。

次に
openssl req -new -key server.key -x509 -days 有効日数 -out server.crt
で自己署名証明書を作ります。
有効期限は初期値より長めに指定した方がいいので追加しておきましょう。手順
12は不要になるはずです。

openssl x509 -in server.crt -text で確認できます。

> 
>> openssl req -new -text -out cert.req
> Using configuration from /usr/share/ssl/openssl.cnf
> Generating a 1024 bit RSA private key
> ................++++++
> .++++++
> writing new private key to 'certkey.pem'
> Enter PEM pass phrase: password←適当な秘密鍵ファイル用パスワード
> Verifying password - Enter PEM pass phrase: password←再入力
> -----
> You are about to be asked to enter information that will be incorporated
> into your certificate request.
> What you are about to enter is what is called a Distinguished Name or a DN.
> There are quite a few fields but you can leave some blank
> For some fields there will be a default value,
> If you enter '.', the field will be left blank.
> -----
> Country Name (2 letter code) [AU]:JP
> State or Province Name (full name) [Some-State]:Tokyo
> Locality Name (eg, city) []:.
> Organization Name (eg, company) [Internet Widgits Pty Ltd]:company
> Organizational Unit Name (eg, section) []:.
> Common Name (eg, your name or your server's hostname) []:hostname
> Email Address []:hogehoge @ hoge.co.jp
> 
> Please enter the following 'extra' attributes
> to be sent with your certificate request
> A challenge password []:←未入力でOK
> An optional company name []:←未入力でOK
> 
> 
> 手順2.証明書の自己署名
> 次に、この証明書に自己署名をします。これにもやはり openssl コマンドを
> 使います。実際は、openssl req -x509 -in サーバ証明書.req -text -key 
> 秘密鍵ファイル.pem -out 署名済み証明書.crt という感じになります。
> パスワードを聞かれるので、先ほどの秘密鍵ファイルのパスワードを入力し
> てください。
>> openssl req -x509 -in cert.req -text -key privkey.pem -out server.crt

-textは不要です。

> Using configuration from /usr/share/ssl/openssl.cnf
> Enter PEM pass phrase:password←手順1で入力した秘密鍵ファイル用パスワード
> これで自己署名のされたサーバ証明書ができあがりました。
> 
> 
> 手順3.秘密鍵からのパスワードの削除
> PostgreSQLで SSL を使うには、この署名済みのサーバ証明書と、先ほどの
> 秘密鍵ファイルの二つのファイルが必要です。しかしこのままだと、
> PostgreSQLの起動時に、秘密鍵ファイルのパスワードを聞いてきてしまい、
> 自動で起動しなくなってしまいます。これを避けるために、秘密鍵ファイル
> からパスワードを削除してしまいます。
> 削除するには、openssl rsa -in 秘密鍵ファイル.pem -out パスワード無し
> 秘密鍵ファイル.pem とします。このときにもやはり、秘密鍵ファイルの
> パスワードを聞いてきます。
>> openssl rsa -in privkey.pem -out server.key
> read RSA key
> Enter PEM pass phrase:password←手順1で入力した秘密鍵ファイル用パスワード
> writing RSA key
> 
> ※ちなみに、パスワード無し秘密鍵ファイルにパスワードを付けるには、
> openssl rsa -des3 -in パスワード無し秘密鍵ファイル.pem -out パスワー
> ド付き秘密鍵ファイル.pem と実行すると、新たに付けるパスワードを聞いて
> きます。
> 
> ここまでで、パスワード無し秘密鍵ファイル(server.key)とサーバ証明書(server.crt)が作成されました。
> 
> 
> 手順4.SSL機能を有効にして、PostgreSQLをコンパイル
> PostgreSQLでSSL を使えるようにするには、SSL が利用できるように
> コンパイルされていなといけません。コンパイルの configure を実行すると
> きに、--with-openssl オプションを付ける必要があります。
> 
>> gzip -d postgresql-8.0.3.tar.gz
>> tar xvf postgresql-8.0.3.tar
>> cd postgresql-8.0.3
>> mkdir /usr/local/pgsql/ ←インストール先ディレクトリの作成
>> mkdir /usr/local/pgsql/data ←データディレクトリの作成
>> chmod -R postgres:postgres /usr/local/pgsql ←オーナーを変更します
>> ./configure --with-openssl ←SSL機能を有効にします
>> make check
>> make install
> 
> 手順5.PostgreSQLの初期化
> データディレクトリの初期化を行います。これを行うことで、データディレ
> クトリ配下に設定ファイル等が作成されます。
>> initdb -E EUC_JP -D /usr/local/pgsql/data
> 
> 
> 手順6.PostgreSQLへ秘密鍵ファイルとサーバ証明書を設定
> PostgreSQLではSSLモードで起動するときに、データディレクトリ配下の
> server.keyファイルとserver.crtファイルを探し、このキーと証明書を
> 利用します。
>> cp ../server.* /usr/local/pgsql/data
>> chmod 400 /usr/local/pgsql/data/server.*
> 
> 
> 手順7.PostgreSQLにてSSL接続をできるようpostgresql.confを編集
> SSLモードで起動するようにPostgreSQLの設定ファイルを編集します。
>> emacs -nw /usr/local/pgsql/data/postgresql.conf
> 以下のように編集します。
> #ssl = false
> ↓↓↓↓↓↓
> ssl = true
> 
> 
> 手順8.クライアントから接続できるようpg_hba.confを編集
> クライアントからSSLのみで接続できるようにpg_hba.confファイルを編集します。
> ※pg_hba.confの詳しい設定は以下のURLを参照してください。
> http://www.postgresql.jp/document/pg803doc/html/client-authentication.html#AUTH-PG-HBA-CONF
>> emacs -nw /usr/local/pgsql/data/pg_hba.conf
> 以下のように編集
> host		all	all	127.0.0.1/32	trust
> ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
> hostssl		all	all	0.0.0.0/0	md5←hostsslを指定します
>  
> 手順9.PostgreSQLを起動
> SSLを使用して、PostgreSQLを起動する場合にはpostmasterに -l オプション
> を指定して起動する必要があります。pg_ctlの -o オプション内で指定する
> postmasterのオプションに -l を追加してください。
> ※pg_ctlおよびpostmasterの詳しい設定は以下のURLを参照してください。
>  pg_ctl:
>   http://www.postgresql.jp/document/pg803doc/html/app-pg-ctl.html
>  postmaster:
>   http://www.postgresql.jp/document/pg803doc/html/app-postmaster.html
>> /usr/local/pgsql_ssl/bin/pg_ctl -o "-i -S -l -p 5432"
>  -D /usr/local/pgsql_ssl/data←本来は1行で入力します
> 
> 
> 手順10.psqlにて接続確認を行うユーザのホームに秘密鍵と証明書をコピー
> ここでひとまず、SSLでの接続ができるかローカル環境での接続確認を
> 行います。
> psql接続確認を行うにはユーザのホームディレクトリにある
> ~/.postgresql/postgresql.crtファイルに格納された証明書を送信します。
> また、一致する~/.postgresql/postgresql.key秘密キーファイルも存在しな
> ければならず、更に誰にでも読み取りできるような権限を付与してはなりま
> せん。 (Microsoft Windowsでは、このファイルの名前はそれぞれ
> %APPDATA%\postgresql\postgresql.crtと%APPDATA%\postgresql\postgresql.key
> です。)
>> cd
>> mkdir .postgresql
>> cp /usr/local/pgsql/data/server.crt /home/postgres/.postgresql/postgresql.crt
>> cp /usr/local/pgsql/data/server.key /home/postgres/.postgresql/postgresql.key

できれば認証局になる鍵ファイルをつくればいいのですが、とりあえず、

SSL接続ではクライアントとサーバが相互に相手を確認します。

サーバ側からコピーするのは server.crt だけです。これは
~/.postgresql/root.crt に置きます。
Javaでサーバ側の証明書をcacertsにインポートしたのと同じでブラウザのroot
証明書と同じ役割です。

クライアント側に置く postgresql.crt と postgresql.key はJavaと同様にクラ
イアント認証用のファイルです。サーバ側の root.crt と対になるファイルなの
で、サーバ用の鍵とは別に作り直した方がいいかもしれません。サーバ側で
root.crt がない場合は作っても意味がありません。

サーバ側の root.crt にはクライアント側で作った postgresql.crt をコピーし
ます。既に root.crtがある場合にはpostgresql.crtの中のBEGIN CERTIFICATEか
らEND CERTIFICATEまでのテキストを追加します。サーバを起動する前に行います。

> 手順11.psqlにてSSL接続できるか確認
> 上記手順10を行った後、psqlにて接続確認を行います。
> ここで、必ず -h オプションを指定してください。-h オプションを指定せ
> ずに接続を行った場合、Unix ドメインソケット経由の接続になり、TCP/IP
> 経由のSSLを使った接続とは異なります。
> また、今回のインストール以外にSSL機能を有効にしていないPostgreSQLが
> インストールされている場合、そのpsqlを利用しての接続は行えない可能性
> がありますので、ご注意ください。
>> /usr/local/pgsql/bin/psql -h 127.0.0.1 -p 5432 template1
> Welcome to psql 8.0.3, the PostgreSQL interactive terminal.
> 
> Type:  \copyright for distribution terms
>        \h for help with SQL commands
>        \? for help with psql commands
>        \g or terminate with semicolon to execute query
>        \q to quit
> 
> SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)←このメッセージが出力されればSSLでの接続が出来ていることが確認できます
> 
> template1 #

手順11で確認できるのはサーバ側の証明書ファイルで暗号化されたということだ
けです。手順10の確認にはなっていません。サーバに root.crtがなければ手順
10に関係なく接続できます。

> 手順12.サーバ証明書をJAVAが理解できる形に変換。
> サーバ証明をJavaから利用できるようにするには、まずJavaが理解できる
> 形式に変換します。
>> openssl x509 -in server.crt -out server.crt.der -outform der
> 
> 以上で、サーバ側の設定はほぼ終了です。以下、クライアント側の設定を行います。
> 
> 
> 手順13.FTPにて変換した証明書(server.crt.der)をクライアントへダウンロード。
> 
> 
> 手順14.Javaのシステムトラストストアに証明書をインポート。
> 証明書をJREに取込ます。
> ※下記で「$JAVA_HOME」はJDKがインストールされている場合は$JAVA_HOME/jre
> になりますので、ご注意ください。
>> keytool -keystore $JAVA_HOME/lib/security/cacerts -alias postgresql -import -file server.crt.der
> キーストアのパスワードを入力してください:  changeit←必ずchangeitです
> 所有者: EMAILADDRESS=hogehoge @ hoge.co.jp, CN=hostname, O=company, ST=Tokyo, C=JP
> 
> 実行者: EMAILADDRESS=hogehoge @ hoge.co.jp, CN=hostname, O=company, ST=Tokyo, C=JP
> 
> シリアル番号: 0
> 有効日: Fri Oct 13 13:34:13 JST 2006 有効期限: Sun Nov 12 13:34:13 JST 2006
> 証明書のフィンガープリント:
>          MD5:  XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
>          SHA1: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
> この証明書を信頼しますか? [no]:  yes
> 証明書がキーストアに追加されました。

有効期限を確認しましょう。

> 
> 手順15.クライアント認証用鍵生成
> 上記手順14までで、サーバ証明書内のパスワードだけのクライアント認証
> で接続はできます。ただ、クライアント認証を行うためにはこの後の設定も
> 必要になります。

上記手順14まででは、サーバが偽装されていない確認ができるだけです。Web
サーバの証明書と同じですね。クライアントの認証はパスワードです。

> クライアント認証にはクライアントのキーストアをサーバの鍵とは別に作成
> し、その証明書をサーバのデータディレクトリにroot.crtというファイル名
> で置きます。

root.crt は psql コマンド用のファイルと1つにまとめてください。


> まずはクライアント認証用の秘密鍵を作成します。
>> keytool -genkey -alias postgresql -keystore client.keystore

-validity 日数 で有効期限を指定することをおすすめします。初期値は90日で
した。

> キーストアのパスワードを入力してください:  password←適当なパスワード
> 姓名を入力してください。
>   [Unknown]:  .
> 組織単位名を入力してください。
>   [Unknown]:  .
> 組織名を入力してください。
>   [Unknown]:  company
> 都市名または地域名を入力してください。
>   [Unknown]:  Tokyo
> 州名または地方名を入力してください。
>   [Unknown]:  .
> この単位に該当する 2 文字の国番号を入力してください。
>   [Unknown]:  JP
> CN=., OU=., O=company, L=Tokyo, ST=., C=JP でよろしいですか?
>   [no]:  yes
> 
> <postgresql> の鍵パスワードを入力してください。
> (キーストアのパスワードと同じ場合は RETURN を押してください):password
>        最初に入力したキーストアのパスワードと同じにします↑
> 
> 
> 手順16.クライアント認証用鍵の証明書を作成
> クライアント認証用の証明書を作成します。以下のコマンドにて手順15で作成した鍵を含む証明書をファイルに書き出します。
>> keytool -export -rfc -alias postgresql -file root.crt -keystore client.keyst
> ore
> キーストアのパスワードを入力してください:  password
> 証明書がファイル <root.crt> に保存されました。
> 
> 
> 手順17.クライアント証明書をサーバに設置
> 手順16にて作成したクライアント証明書(root.crt)をサーバのデータディレクトリ配下に設置します。
> FTPで転送後、/usr/local/pgsql/data配下に設置します。

追加で登録するときは
cat root.crt >> /usr/local/pgsql/data/root.crt
でしょうか。
サーバの再起動が必要です。

> 手順18.ソースファイルの修正
> まず、JDBC ドライバを利用する際に指定するドライバURLにて、SSL 通信を利用するプロパティを追加すします。
> 
> <追加プロパティ>
> ssl=true
> 
> コード例:
> ============================================================
> String url =
> "jdbc:postgresql://localhost/test?user=fred&password=secret&ssl=true";
> Connection conn = DriverManager.getConnection(url);
> ============================================================
> 
> 詳しくは、Postgresql のJDBCドライバドキュメントを参照ください。
> [Connection Parameters]
> http://old.postgresql.jp/wg/jpugdoc/jdbc/jdbc-8.1dev-400/html/connect.html
> 
> 
> 手順19.実行パラメータの設定
> JAVAアプリケーション起動時のパラメータでクライアントのキーストアとパスワードを指定します。
> 
> -Djavax.net.ssl.keyStore=client.keystore
> -Djavax.net.ssl.keyStorePassword=password←手順15で入力したパスワード

プログラム中で
 System.setProperty("javax.net.ssl.keyStore", "client.keystore");
 System.setProperty("javax.net.ssl.keyStorePassword", "password");
と指定することもできます。

> 
> 
> 以上。
> 
> -------------------------------- 終了 --------------------------------
> 
>> 岩瀬です。
>>
>> 結果から言います。
>> おこめさまにご教示頂いたやり方でうまく動きました!
>> ありがとうございます。
>>
>> 後ほど接続に至るまでの手順をこちらに提示させて頂こうと
>> 思います。
>> おこめさま、大変助かりました。ありがとうございました!!
>>
>>
>>> おこめです。
>>>
>>> 岩瀬 肇 wrote:
>>>> 岩瀬です。
>>>>
>>>> おこめ様、コメントありがとうございます。
>>>> 結論から言うと、まだうまくできていません。
>>>>
>>>  > 一つ分かったことは、サーバのdataフォルダ配下に置いてある、
>>>> server.crtと同じroot.crtファイルを消した場合、
>>>> 接続できるようになりました。
>>>> ただ、本当にSSL接続できているのか?まではまだ確認できていません。
>>>> 以下のマニュアルを確認すると、
>>>> http://www.postgresql.jp/document/pg803doc/html/ssl-tcp.html
>>>> root.crtが無い場合、クライアントの認証は行わないと書いてある
>>>> ので、クライアントの証明書が何らかの理由で認証できていないようだと
>>>> いうところまではわかりました。
>>>>
>>>> 正直行き詰まっています。根本的にOpenSSLの処理が分かっていないのも
>>>> 問題だと感じており、OpenSSLについても調査が必要なのかとも考えています。
>>>>
>>>> すいません、何か他にアドバイスがあればお願い致します。
>>> サーバの証明書だけ見てクライアントはパスワードだけの認証で接続していました。
>>> クライアント認証については別の設定も必要になるので調べてみました。
>>>
>>> クライアントの認証はクライアントの keystore をサーバの鍵とは別に作成し
>>> て、その証明書をサーバの root.crt に置きます。
>>>
>>> ■鍵生成
>>> keytool -genkey -alias client1 -keystore client.keystore
>>> などなど。
>>> キーストアと鍵のパスワードは同じにしておきます。
>>> パスワード以外はとりあえず何でもいいと思います。
>>>
>>> ■証明書作成
>>> 鍵の証明書をファイルに書き出します。
>>>
>>> keytool -export -rfc -alias client1 -flie root.crt -keystore client.keystore
>>>
>>> 別の鍵で署名してもかまいませんし、クライアントが1つであれば、
>>> 書き出したファイルをそのままサーバの root.crt に置きます。
>>>
>>> ■実行パラメータ
>>> java のパラメータでクライアントのkeystoreとパスワードを指定します。
>>>
>>> -Djavax.net.ssl.keyStore=client.keystore
>>> -Djavax.net.ssl.keyStorePassword=keystorepassword
>>>
>>> サーバの証明書をcacerts以外に入れている場合は
>>>
>>> -Djavax.net.ssl.trustStore=cert.keystore
>>> -Djavax.net.ssl.trustStorePassword=certpassword
>>>
>>> でサーバ証明書の入っている keystoreファイルとkeystoreのパスワードも指定
>>> します。
>>>
>>> サーバの証明書だけを指定してクライアントの鍵を指定してなかったので接続で
>>> きなかったのでしょうね。
>>> これでクライアント認証もできましたが、どうでしょうか?
>>>
>>> -- 
>>> 佐藤 雅俊 (おこめ)
>>> okome @ siisise.net okome @ mozilla.gr.jp
>>> http://siisise.net/
>> -- 
>> 岩瀬 肇 <iwase-h @ cnt.mxy.nes.nec.co.jp>
> 


-- 
佐藤 雅俊 (おこめ)
okome @ siisise.net okome @ mozilla.gr.jp
http://siisise.net/



pgsql-jp メーリングリストの案内