TT Lab
はじめる
学ぶ 学習パス コース

証明書は更新されたのに、ブラウザは古いものを表示した

更新したのに古い証明書が出ていく

TT Labで続きを見る

目標

証明書を起動時に一度だけ読み込むHTTPSサーバーについて、更新事故を再現し、ディスクではなくサーバーが提示する証明書を監視するスクリプトを2つ作ります。

なぜ重要なのか

更新ツールはファイルを書き換え、サーバーはメモリのものを提示します。その間に再起動がなければ、「更新成功」のログと「期限切れ間近」の警告が、同時に真になります。用意されているサーバー/opt/app/tlsserve.pyは、load_cert_chainをたった一度だけ呼ぶPythonのHTTPSサーバーで、実際のサーバーの大半がそうであるように、ファイルが変わっても読み直しません。このラボの監視スクリプトは、採点ツールが別に立ち上げたサーバーで、双方向(同じファイルならFRESH、違うファイルならSTALE)の検査を受けます。

ステップ

  1. 次のファイルを作成してください。CAの鍵と証明書(/root/renew/ca.key・/root/renew/ca.crt、CN=Lab Root CA)、サーバーの鍵(/root/renew/server.key)、そしてCAが署名した3日間の証明書(/root/renew/v1.crt、SAN DNS:www.lab.internal)です。
  2. v1.crtをコピーして(コピー先: /root/renew/live.crt)、server.keyもコピーし(コピー先: /root/renew/live.key)、python3 /opt/app/tlsserve.py --cert /root/renew/live.crt --key /root/renew/live.key --port 8443を起動してください。openssl s_clientで受け取った証明書のserial=行を保存してください(保存先: /root/renew/02-served.txt)。
  3. 同じ鍵で30日間の証明書(/root/renew/v2.crt)を発行し、live.crtに上書きしてください(更新ツールがすることです)。サーバーは再起動しないでください。
  4. もう一度s_clientでserial=を保存し(保存先: /root/renew/04-served.txt)、curl -sk https://127.0.0.1:8443/の本文も保存してください(保存先: /root/renew/04-body.txt)。ディスクはv2なのに、サーバーはv1のままである必要があります。
  5. 次のスクリプトを作成してください: /root/renew/certdiff.sh <인증서파일> <host:port>(プレースホルダーは証明書ファイルとhost:portです)。ディスクのファイルとサーバーが提示する証明書のSHA-256フィンガープリントが同じならFRESHを出力して0、異なればSTALEを出力して1で終了する必要があります。live.crtと127.0.0.1:8443に対して実行した出力を保存してください(保存先: /root/renew/05-detect.txt)。
  6. サーバーを終了して再び起動したあと、s_clientのserial=を保存してください(保存先: /root/renew/06-served.txt)。
  7. 次のスクリプトを作成してください: /root/renew/servedcheck.sh <host:port> <초>(プレースホルダーはhost:portと秒数です)。サーバーが提示する証明書がその秒数以内に期限切れになるならEXPIRINGを出力して1、そうでなければOKを出力して0で終了する必要があります。127.0.0.1:8443 604800で実行した出力を保存してください(保存先: /root/renew/07-monitor.txt)。
  8. まとめを書いてください(保存先: /root/renew/08-report.md)。v1とv2のシリアル番号、サーバーに新しいファイルを読み込ませた方法、監視はディスクではなくサーバーが提示する証明書を見る必要がある理由を書いてください。

参考

CAと3日間のv1

/root/renew/にca.key・ca.crt(CN=Lab Root CA)・server.keyと、3日間のv1.crt(SAN DNS:www.lab.internal)を作成してください。

前のモジュールと同じ手順です。CAの自己署名、SAN付きのCSR、x509 -reqでの署名(-copy_extensions copy)です。CSRはステップ3でまた使うので、server.csrとして残しておいてください。

サーバーが持っている証明書を読む

v1.crt→live.crt、server.key→live.keyにコピーしてtlsserve.pyを8443で起動し、s_clientで受け取ったserial=行を/root/renew/02-served.txtに保存してください。

サーバーはnohupでバックグラウンドに置き、ログは/root/renew/server.logに出力してください。s_clientの出力全体をx509 -noout -serialに渡すと、serial=の行が1行出ます。

更新: ファイルを上書きする

同じ鍵で30日間の/root/renew/v2.crtを発行し、live.crtに上書きしてください。サーバーは再起動しないでください。

同じCSRにもう一度署名すればよいです(-days 30)。serialが新しく割り振られ、有効期限が延びます。cp v2.crt live.crtが、更新ツールがすることのすべてです。

ディスクはv2、サーバーはv1

s_clientのserial=を/root/renew/04-served.txtに、curl -sk https://127.0.0.1:8443/の本文を/root/renew/04-body.txtに保存してください。

サーバーは、起動時に読み込んだものを提示し続けます。2つのファイルとも、v1のserialが見えれば、事故が再現されたことになります。curlの-kは、自前のCAなので検証をオフにするもので、本文にはサーバー自身が語るserialがあります。

ディスクとサーバーを比べるスクリプト

/root/renew/certdiff.sh <인증서파일> <host:port>(プレースホルダーは証明書ファイルとhost:portです)を作成し(同じならFRESH・0、異なればSTALE・1)、live.crtと127.0.0.1:8443に対する出力を/root/renew/05-detect.txtに保存してください。

2つのフィンガープリントを求めます。ファイルはx509 -in ファイル -fingerprint -sha256、サーバーはs_clientの出力をx509 -fingerprint -sha256に渡します。サーバーから証明書を受け取れないなら、ERRORとして2を返すとよいです。採点ツールは、自分のサーバーで、同じファイルと違うファイルの2つのケースを実行します。

再起動: サーバーが新しいファイルを読む

サーバーを終了して再び起動したあと、s_clientのserial=を/root/renew/06-served.txtに保存してください。

pkill -f tlsserve.pyで終了し、同じコマンドで再び起動します。起動時にlive.crtを新しく読み込むので、今度はv2のserialが出るはずです。

サーバーが提示する証明書の期限監視

/root/renew/servedcheck.sh <host:port> <초>(プレースホルダーはhost:portと秒数です)を作成し(その秒数以内に期限切れならEXPIRING・1、そうでなければOK・0)、127.0.0.1:8443 604800の出力を/root/renew/07-monitor.txtに保存してください。

s_clientで受け取った証明書を、一時ファイルにx509 -outで保存したあと、-checkend <秒数>をかければよいです。ディスクのlive.crtを見てはいけません。採点ツールは、2日間の証明書を持つ自分のサーバーに、7日のウィンドウを与えて、EXPIRINGが出るかを見ます。

事故レポート

/root/renew/08-report.mdに、v1・v2のシリアル番号、サーバーに新しいファイルを読み込ませた方法、監視がサーバーの提示する証明書を見る必要がある理由を書いてください。

2つのserialは、v1.crtとv2.crtから-serialで取り出して、そのまま入れてください。「再起動」という言葉と「s_client」が入っていれば、採点ツールが結論を見つけます。