$ cd ~/tool

$ SSL証明書チェック

ドメインを入れるだけで、SSL/TLS証明書の有効期限・発行者・中間証明書・SAN・対応TLSを確認します。

既定は443(HTTPS)。メールサーバーなら 465(SMTPS)/993(IMAPS)/995(POP3S) なども指定できます。

how to read — 結果の読み方

上の表は、まず3つの判定(有効期限・証明書チェーン・TLSバージョン)を信号色で示し、その下に詳細を並べています。それぞれの意味は次の通りです。

有効期限
証明書がいつまで有効か。残り30日以下で黄色、期限切れで赤になります。期限が切れると利用者のブラウザに「保護されていない通信」の警告が出て、多くの人は離脱します。更新は余裕をもって。
証明書チェーン
サーバーが提示した証明書の枚数。通常は「リーフ(あなたのドメインの証明書)+中間CA証明書」で2枚以上になります。1枚しか出ていないと「中間証明書なしの可能性」=設定漏れのサインです(後述)。
TLSバージョン
実際に張れた暗号化通信の世代。TLS 1.2 / 1.3なら安全、TLS 1.0 / 1.1は古く非推奨です。
CN / SAN
証明書が「どのドメイン向けか」を示します。今はSAN(subjectAltName)が本体で、ここに example.comwww.example.com両方が載っているかが要点。現在の主要ブラウザ(Chrome・Edge・Safari など)はCNを完全に無視し、SANだけで判定します。CNが正しくてもSANに無ければ「別ドメインの証明書」とみなされ警告になるため、SANへの正確な記載が必須です。
なお *.example.com のようなワイルドカード証明書1階層分だけ有効です。a.example.com は対象ですが、example.com 自身や a.b.example.com は対象外なので、必要なら apex やそれらも別途SANに併記します。
発行者
証明書を発行した認証局(Let's Encrypt / DigiCert など)。意図しない発行者になっていないかの確認に。

how it works — SSL証明書のしくみ

HTTPSは「通信の暗号化」と「相手が本物だという証明」をセットで行います。後者を担うのがサーバー証明書です。ブラウザは、サーバーが出した証明書を信頼の連鎖(チェーン)でたどって検証します。

このうちサーバーが送るべきなのはリーフ+中間CA。ルートは利用者側が最初から持っているので送りません。だから正しい設定では証明書は「2枚以上」提示されます。また、1つのIPで複数ドメインを運用できるよう、接続時にFQDNを伝えるSNIという仕組みで「どのドメインの証明書を出すか」を選んでいます。

troubleshooting — よくあるトラブルと見分け方

「中間証明書なしの可能性」と出た
最も厄介で、最も多いミスです。PCのブラウザでは繋がるのに、スマホアプリ・メールソフト・curl・他社APIからは「証明書エラー」になる——という症状はほぼこれ。PCブラウザは不足分をOSが補完してしまうため、テストでは気づけません。サーバー(Apache/nginx等)に中間CA証明書を結合した証明書を設定し直してください。
「発行者が信頼されていない/自己署名」と出る
発行者が公的なルートCA(Let's Encrypt・DigiCert 等)でない場合です。開発環境の自己署名証明書や社内プライベートCAでは、ブラウザが警告を出すのが正常な動作です(当ツールは「自己署名」と判定表示します)。一般公開するサーバーでは、信頼されたCAが発行した証明書に置き換えてください。
期限が切れている/残りわずか
Let's Encryptは90日で短いので自動更新(certbot等)が前提。更新フックが失敗していないか、cronが動いているかを確認します。
SANにアクセス先のドメインが無い/「ドメイン不一致」と出る
www有りで取った証明書にwww無しでアクセスしている(またはその逆)など。両方をSANに含めるか、リダイレクトで寄せます。また共用サーバーでHTTPSを設定していないと、別サイト向けの既定証明書(例: *.sakura.ne.jp)が返り「ドメイン不一致」になります。この場合はそのドメインで正式なSSL証明書を取得・設定してください。
TLS 1.0 / 1.1 が有効
古いTLSは無効化を。サーバー設定でTLS 1.2以上のみ許可するのが現在の標準です。
そもそも接続できない
ポート違い(HTTPSは443、メールは465/993/995)、ファイアウォール、対象がそのFQDNで証明書を出していない(SNI不一致)などが原因。ポート疎通そのものは portチェック で切り分けられます。
ツールは正常なのにブラウザで「保護されていない通信」と出る
証明書ではなくページの作り方が原因のことが多いです。HTML内で画像・CSS・JavaScript を http:// で読み込んでいると、ページ全体がHTTPSでも混在コンテンツ(Mixed Content)としてブラウザが警告・ブロックします。これは証明書のエラーではないため当ツールでは正常と表示されます。読み込みURLを https:// 始まりに直してください。

cli — 手元のコマンドでも確認できます

PS> $h='example.com'
PS> $c=[Net.Sockets.TcpClient]::new($h,443)
PS> $s=[Net.Security.SslStream]::new($c.GetStream())
PS> $s.AuthenticateAsClient($h)
PS> $s.RemoteCertificate.GetExpirationDateString()
$ echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates -issuer -subject

PowerShellは標準機能だけで期限を取得できます(openssl不要)。中間証明書の有無まで見たい場合は openssl s_client -showcerts で提示された証明書の枚数を確認します。

関連ツール