中間CA証明書の変更でTLS証明書更新が失敗した実例と対処

サーバー証明書の更新で、これまでどおり「サーバー証明書+中間CA証明書」の2枚でチェーンを組んだところ、検証が通らずに詰まりました。原因は2026年6月17日から中間CA証明書が変わり、あわせて「クロスルート証明書」の設置が必須になっていたことです(JPRSサーバー証明書の場合)。期限を延ばすだけの作業だと思っていると確実に踏みます。実際の切り分けと復旧手順を記録として残します。

この記事でわかること

  • 2026年6月17日に何が変わったのか(中間CA証明書の世代交代とクロスルート証明書の追加)
  • なぜクロスルート証明書が必要なのか
  • サーバー上の openssl verify が失敗してもブラウザでは信頼されることがある理由
  • チェーンを3枚構成で組み直す具体手順(コマンド付き)
  • SSLCertificateChainFile をやめて SSLCertificateFile に寄せる理由

何が変わったのか

JPRSは2026年6月17日付で、ルート証明書を「SECOM TLS RSA Root CA 2024」へ移行し、中間CA証明書を新しい世代に切り替えました。

項目 2026年6月16日まで 2026年6月17日以降
中間CA証明書(DV) JPRS Domain Validation Authority – G4 JPRS DV RSA CA 2024 G1
中間CA証明書(OV) JPRS Organization Validation Authority – G4 JPRS OV RSA CA 2024 G1
クロスルート証明書 不要 必要(DV/OV共通)
ウェブサーバーに置く枚数 2枚(サーバー証明書+中間CA) 3枚(+クロスルート)

押さえておきたい前提が2つあります。2026年6月16日までに発行された証明書は設定変更が不要で、有効期限まで使えます。またACME版(Certbot等の一般的なACMEクライアント)を使っている場合も対応は不要で、今回の作業が必要なのは従来版の証明書を手で入れ替えている環境です。なおACME版は有効期間が90日から88日へ変更されています。

なぜクロスルート証明書が必要なのか

新しいルート証明書が、まだOSやブラウザの信頼ストアに行き渡っていないためです。新ルート「SECOM TLS RSA Root CA 2024」を配布済みのクライアントなら問題ありませんが、そうでない環境では信頼の起点に辿り着けません。

クロスルート証明書は、新ルートを主体(subject)とし、旧ルート「Security Communication RootCA2」が発行者(issuer)となっている証明書です。これをチェーンの末尾に挟むことで、新ルートを持たないクライアントも「旧ルートまで辿れる」状態になります。JPRSはこれを「ルート証明書移行時に新旧両方のルートから信頼を確保するための標準的な手法」と説明しています。証明書チェーンそのものの考え方は公開鍵基盤(PKI)の解説も参考になります。

自分の環境に新ルートが入っているかは、信頼ストアを直接見れば分かります。

# 新ルートは未収録のことが多い(0 が返る)
grep -c 'SECOM TLS RSA Root CA 2024' /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

# 旧ルートは収録済み(1以上が返る)
grep -c 'Security Communication RootCA2' /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

ここで前者が0、後者が1以上という結果になるのが、クロスルート証明書が必要な理由の実測値です。

作業手順

以下、環境固有の情報を避けるため次の変数で表記します。自環境の値に読み替えてください。

# 証明書の配置ディレクトリ、対象ドメイン、サーバー証明書のベース名
CERTDIR=/path/to/tls/certs
DOMAIN=www.example.jp
SRV=server-YYYYMMDD

1. 中間CA証明書とクロスルート証明書を取得する

cd "$CERTDIR"

# 中間CA証明書(DV・2026年6月17日以降発行分)
curl -fsS -o JPRS_DV_RSA_CA_2024_G1.cer \
  https://jprs.jp/pubcert/service/certificate/2026/JPRS_DV_RSA_CA_2024_G1_PEM.cer

# クロスルート証明書(DV/OV共通・SECOMのリポジトリから)
curl -fsS -o SECOM_TLSRSA_RootCA2024_cross.cer \
  https://repository.secomtrust.net/SC-Root2/tlsrsarootca2024cross-pem.cer

ファイル名を推測で探すより確実な方法もあります。サーバー証明書のAIA拡張には、対応する中間CA証明書の配布元URLが書かれています。

openssl x509 -in "${SRV}.crt" -noout -ext authorityInfoAccess

2. 取得したファイルを検証する

取り違えを防ぐため、シリアルとSHA-1フィンガープリントを公式の値と突き合わせます。

# 中間CA:シリアルとSHA-1が下表と一致するか
openssl x509 -in JPRS_DV_RSA_CA_2024_G1.cer -noout -subject -issuer -serial -dates -fingerprint -sha1

# クロスルート:subject と issuer の組み合わせを確認
openssl x509 -in SECOM_TLSRSA_RootCA2024_cross.cer -noout -subject -issuer -dates
証明書 シリアル SHA-1 有効期間
JPRS DV RSA CA 2024 G1 47 a5 91 1d f5 0a 9b cf ba cc c9 4b 62 11 d5 7f b6 b1 7e f2 56 fb 53 6e 00 d5 b8 73 d7 ed d3 e1 17 5a c0 49 2024/04/04〜2039/01/12
クロスルート証明書 22 b9 b1 ad 80 e6 58 82 56 d0 70 53 0f 78 52 2d 86 3b 41 07 ce fb 4c 92 27 fe de 62 0e a7 28 6d 23 72 5c 52 2025/04/09〜2029/05/29

クロスルート証明書は subject が「SECOM TLS RSA Root CA 2024」、issuer が「Security Communication RootCA2」になっているはずです。ここが逆だったり、issuer が新ルートになっているファイルは目的のものではありません。

3. 現行のサーバー証明書を確認する

sudo openssl x509 -in "$CERTDIR/${SRV}.crt" -noout -subject -issuer -dates -serial

issuer を必ず見ます。ここが「JPRS DV RSA CA 2024 G1」になっていれば新世代の証明書で、サーバーに残っている旧中間CA(G4)では検証できません。期限しか見ていないと、この食い違いに気づけません。

4. 設置する

sudo install -m 644 -o root -g root \
  ~/JPRS_DV_RSA_CA_2024_G1.cer \
  ~/SECOM_TLSRSA_RootCA2024_cross.cer \
  "$CERTDIR/"

# SELinux が有効な環境ではコンテキストを戻す
sudo restorecon -Rv "$CERTDIR/"

5. チェーンが通るか検証する

sudo openssl verify -CAfile "$CERTDIR/ca-bundle.crt" \
  -untrusted "$CERTDIR/JPRS_DV_RSA_CA_2024_G1.cer" \
  -untrusted "$CERTDIR/SECOM_TLSRSA_RootCA2024_cross.cer" \
  "$CERTDIR/${SRV}.crt"

ここが失敗しても、すぐに「証明書が使えない」と結論づけないでください。サーバーの ca-certificates パッケージが新ルートに追いついていない場合、正しく組んでもサーバー側の検証だけが失敗します。この状態でもブラウザでは信頼されることが普通にあります。判断材料はクライアント側の信頼ストアです。Windowsなら次で確認できます。

certutil -verify -urlfetch leaf.pem

各段が dwErrorStatus=0 なら信頼されています。末尾に CRYPT_E_REVOCATION_OFFLINE が出ることがありますが、これは失効確認サーバーに繋がらなかっただけで信頼の失敗ではありません。サーバー側の検証も通したい場合は sudo dnf update ca-certificates を実行します(サーバー内のツールが自サイトへHTTPS接続する場合に効きます)。

6. fullchain を3枚構成で組み直す

戻せる状態を先に作ってから、連結します。

cd "$CERTDIR"

# 既存の fullchain を日付付きで退避
sudo cp -a "${DOMAIN}.fullchain.crt"{,.bak-$(date +%F)} 2>/dev/null

sudo bash -c "cat ${SRV}.crt \
  JPRS_DV_RSA_CA_2024_G1.cer \
  SECOM_TLSRSA_RootCA2024_cross.cer \
  > ${SRV}.fullchain.crt"

# 3 が返ること(サーバー証明書・中間CA・クロスルート)
grep -c 'BEGIN CERTIFICATE' "${SRV}.fullchain.crt"

sudo chmod 644 "${SRV}.fullchain.crt"
sudo chown root:root "${SRV}.fullchain.crt"
sudo restorecon -v "${SRV}.fullchain.crt"

grep -c3 を返すことがこの作業の要点です。2 のままなら、これまでと同じ壊れたチェーンを配信することになります。

7. Apacheの設定を差し替える

連結したファイルを SSLCertificateFile に指定し、SSLCertificateChainFile は無効化します。

STAMP=$(date +%F)
sudo cp -a /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak-${STAMP}

sudo sed -i \
  -e "s#^SSLCertificateFile .*#SSLCertificateFile ${CERTDIR}/${SRV}.fullchain.crt#" \
  -e 's#^SSLCertificateChainFile#\#SSLCertificateChainFile#' \
  /etc/httpd/conf.d/ssl.conf

# 意図した差分になっているか目視する
sudo diff -u /etc/httpd/conf.d/ssl.conf.bak-${STAMP} /etc/httpd/conf.d/ssl.conf

反映は必ず構文チェックと && でつないでから行います。構文エラーのまま reload させないための作法です。証明書ファイルが存在しない状態で SSLCertificateFile を書くと httpd が起動しなくなります。

sudo apachectl configtest && sudo systemctl reload httpd
sudo systemctl is-active httpd

8. 外から確認する

openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" -showcerts </dev/null 2>/dev/null \
  | grep -E '^ [0-9]+ s:|^   i:|Verify return code'

サーバー証明書・中間CA・クロスルートの3段が並びVerify return code: 0 (ok) になっていれば完了です。

なお検証はサーバーの外から行ってください。サーバー上から自分の公開FQDNへ接続するとヘアピンNATの経路を通り、環境によっては断続的に失敗します。アプリとhttpdの健全性はサーバー内から 127.0.0.1 で、公開経路の健全性は外から、と分けて測るのが確実です。

なぜ SSLCertificateChainFile をやめるのか

SSLCertificateChainFile はApache 2.4.8以降で非推奨となり、SSLCertificateFile が中間CA証明書も読み込めるよう拡張されました。今回のようにチェーンの枚数が増える変更では、1つのファイルに連結して SSLCertificateFile だけで管理するほうが取り回しが楽です。設定行が分散していると「3枚目をどこに書くのか」で迷いますし、片方だけ更新して不整合を起こす事故も減ります。

現場目線の課題

正直なところ、証明書更新は「期限を延ばす作業」として台帳に載っていることが多く、発行者や中間CAが変わる回があるという前提で手順書が書かれていません。更新チケットにも「有効期限:〇年〇月まで」としか書かれず、チェーン構成の変更は申し送りに乗ってこない。今回もそこで足をすくわれました。

さらに厄介なのが、3枚目のクロスルートを落としても、新ルートを持つ最新環境からは正常に見えてしまう点です。手元の最新ブラウザで確認して「問題なし」と判断すると、古い端末や組み込み機器、一部のライブラリからだけ弾かれる、という発見しにくい形で残ります。手元の1環境での確認は検証になりません。

そしてもう一つ。証明書の監視が「残り日数」だけを見ている場合、チェーン不備は検知できません。期限は正常なのでアラートは上がらず、利用者からの問い合わせで初めて気づく。監視項目にチェーン検証まで含めるべきだと、今回あらためて思いました(監視・検知の役割)。

情シスはどうすべきか

今回の対処自体は上記の手順で完結しますが、再発を防ぐには運用側の作り込みが要ります。

  • 監視にチェーン検証を含める:残り日数だけでなく、外部から openssl s_client で段数と Verify return code を定期確認する。
  • 更新手順書に「中間CAは変わりうる」と明記する:作業の最初に新旧の issuer を比較する工程を入れておく。
  • 設定は必ずバックアップと構文チェックを挟む:全サイトが依存するファイルを触るため、戻し方を1行で用意しておく。

TLSの設定そのものを点検するなら、IPA「TLS暗号設定ガイドライン」が起点として最適です。安全性と相互接続性のバランスで3つの設定基準が示されており、チェックリスト(PDF/Excel)も配布されているので、自環境の棚卸しにそのまま使えます。証明書は脆弱性管理と違って「壊れていても期限までは動く」ため、能動的に見に行く仕組みがないと放置されがちです。あわせて、更新作業を委託している場合はチェーン構成の変更が作業範囲に含まれるかを事前に確認しておくと安全です。

まとめ

  • 2026年6月17日以降に発行されたJPRSサーバー証明書は、中間CA証明書が新世代(DVなら JPRS DV RSA CA 2024 G1)に変わり、クロスルート証明書の設置が必須になった。チェーンは2枚から3枚構成になる。6月16日までに発行された証明書とACME版は対応不要。
  • クロスルート証明書は新ルートが信頼ストアに未収録なことを埋める仕組み。サーバー側の openssl verify が失敗してもブラウザでは信頼されることがあるため、クライアント側の信頼ストアで判断する。
  • 期限だけを見る運用では踏む。更新時は必ず issuer を新旧比較し、grep -c 'BEGIN CERTIFICATE' が3を返すこと、外部からの検証で3段が並ぶことを確認する。監視項目にチェーン検証を加える。

出典

タイトルとURLをコピーしました