「証明書エラーが出るので、とりあえず『詳細設定』から進んでもらっています」
「curlでエラーになるので、-kを付けて回避しました」
どちらも、その場はしのげます。でも、回避した端末だけが中間者攻撃に無防備になるうえに、原因は何も解決していません。
第9回までで、証明書とTLSの仕組み、発行と自動化、社内PKIとクラウドを見てきました。第10回では、その知識を使って、証明書のエラーが起きたときに原因を切り分ける手順をまとめます。最後に、連載全体の早見表と持ち帰りも載せます。
証明書エラーの種類と見え方
同じ原因でも、ツールによって見え方が違います。まずは対応を押さえましょう。

| 原因 | Chrome・Edge | curl(OpenSSL) | PowerShell(SslStream) |
|---|---|---|---|
| 期限切れ | NET::ERR_CERT_DATE_INVALID | certificate has expired (10) | RemoteCertificateChainErrors(NotTimeValid) |
| 名前の不一致 | NET::ERR_CERT_COMMON_NAME_INVALID | no alternative certificate subject name matches target hostname | RemoteCertificateNameMismatch |
| 信頼されない発行者(自己署名、ルートが未配布) | NET::ERR_CERT_AUTHORITY_INVALID | self-signed certificate (18)、self-signed certificate in certificate chain (19) | RemoteCertificateChainErrors(UntrustedRoot) |
| チェーンの不足(中間証明書が無い) | 多くは表示されない(AIA で補う) | unable to get local issuer certificate (20) | 多くは表示されない(Windows も AIA で補う) |
| 失効 | NET::ERR_CERT_REVOKED(CRLSets に載った場合など) | 既定では確認しない | 既定では確認しない |
$ curl -sS https://expired.badssl.com/ -o /dev/null
curl: (60) SSL certificate OpenSSL verify result: certificate has expired (10)
badssl.comは、エラーの見え方を試すための公開のテスト用サイトです(expired・wrong.host・self-signed・untrusted-root・incomplete-chain・revokedなど)。curlの検証エラーは終了コード60です。失効は、ブラウザーもcurlも確認しないことが多い点に注意します(第5回)。
ほかのエラー
| 原因 | Chrome・Edge | curl・openssl | 確認のポイント |
|---|---|---|---|
| 端末の時刻のずれ | NET::ERR_CERT_DATE_INVALID(「時計が遅れています」などの画面) | certificate is not yet valid (9) または has expired (10) | timedatectl、w32tm /query /status |
| 古いアルゴリズム(SHA-1 の署名) | NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM | CA signature digest algorithm too weak (68) | openssl x509 -noout -text の Signature Algorithm |
| 鍵の用途の不一致(Key Usage・EKU) | ERR_SSL_KEY_USAGE_INCOMPATIBLE など | unsuitable certificate purpose(error 26) | KU に digitalSignature、EKU に serverAuth(第4回) |
| 有効期間が長すぎる(公開証明書) | NET::ERR_CERT_VALIDITY_TOO_LONG | エラーにならない | 公開CA の上限は現在200日(第6回) |
| CT の記録が無い(公開証明書) | NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED | エラーにならない | 証明書の SCT(第5回) |
| TLS のバージョン・暗号スイートの不一致 | ERR_SSL_VERSION_OR_CIPHER_MISMATCH | curl: (35)、unsupported protocol | 後述 |
Edge(Chromium)は124版から、社内のルートにつながるRSAの証明書でもKey Usageを必ず確認するようになりました。古い機器の自己署名証明書で急に開けなくなる原因の1つです。PowerShellでは、用途の不一致がNotValidForUsageとして見えます。
中間証明書の入れ忘れ
第5回でも扱いましたが、いちばん多いトラブルなので改めて見ておきます。

サーバーは、自分の証明書に加えて中間証明書(ルートを除くチェーン)も送る必要があります。
- 入れ忘れても、Chrome・EdgeやWindowsは、証明書のAIAのURLから中間証明書を取りに行って補うため、ブラウザーでは正常に見える
- FirefoxはAIAを使わないが、公開CAの中間証明書をあらかじめ読み込んでいるため、やはり気づきにくい。社内CAの証明書では、Firefoxも失敗する
- curl・openssl・Java・Pythonや多くの機器は補わないため、「ブラウザーでは開けるのにAPI連携だけ失敗する」という形で見つかる
確認は、サーバーが送った本数を見ることです。openssl s_client -showcertsのCertificate chainに0番しか無ければ不足しています。ブラウザーで開けても、チェーンが正しいとは限りません。
TLSバージョン・暗号スイートの不一致
証明書は正しくても、交渉の段階で失敗するケースです。症状は、ChromeのERR_SSL_VERSION_OR_CIPHER_MISMATCH、curlの終了コード35、古いアプリの「ハンドシェイクに失敗しました」です。

よくある原因は次の5つです。
- 古い機器・Java・.NET FrameworkがTLS 1.2以上を話せない(TLS 1.0/1.1はRFC 8996で禁止、第7回)
- サーバーがECDSAの証明書だけで、クライアントがRSAしか扱えない
- 暗号スイートを絞りすぎた
- SNIを送らない古いクライアントに、既定の別の証明書が返る
- 通信を検査する中継装置が新しい方式(大きなClientHelloになるPQCの鍵交換など)に対応していない
$ openssl s_client -connect www.example.jp:443 -servername www.example.jp -tls1_2 </dev/null | grep -E "^(New|Protocol)"
$ openssl s_client -connect www.example.jp:443 -servername www.example.jp </dev/null | grep "Negotiated"
Negotiated TLS1.3 group: X25519MLKEM768
$ curl -sv https://www.example.jp/ -o /dev/null 2>&1 | grep "SSL connection"
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
Windowsでは、バージョンを指定して接続を試します(Tls12をTls13に変えて比べる)。サーバー側で有効な暗号スイートはGet-TlsCipherSuiteで確認します。
PS> $t=New-Object Net.Sockets.TcpClient('www.example.jp',443); $s=New-Object Net.Security.SslStream($t.GetStream())
PS> $s.AuthenticateAsClient('www.example.jp',$null,[Security.Authentication.SslProtocols]::Tls12,$false); $s.SslProtocol
切り分けの手順
証明書エラーの切り分けは、症状を固める → 名前と経路 → サーバーが送る証明書 → 端末での検証 → TLSのパラメーターの順に確かめます。図は、各段階をどこで確かめるかを示しています(番号は表の段階)。

| 段階 | 確認すること | コマンドの例 | 分かること |
|---|---|---|---|
| 0 症状を固める | 誰が・どの端末とブラウザーで・どの URL・いつから・エラーコード | 画面のエラーコード(NET::ERR_…)を控える | 全員か一部か。名前・期限・信頼のどれか |
| 1 名前と経路 | 名前がどの IP になり、どの機器(LB・プロキシ)に届くか | dig、Resolve-DnsName、Test-NetConnection 名前 -Port 443 | 意図しないサーバーや、検査用のプロキシに届いていないか |
| 2 サーバーが送る証明書 | 主体・SAN・期限・発行者、送られたチェーンの本数 | openssl s_client -showcerts、PowerShell の SslStream | 期限切れ、名前、中間証明書の不足 |
| 3 端末での検証 | 信頼ストアにルートがあるか、時刻、CRL・AIA に届くか | certutil -verify -urlfetch、Get-ChildItem Cert:\LocalMachine\Root、w32tm /query /status | ルートの未配布、時刻のずれ、失効の確認先に届かない |
| 4 TLS のパラメーター | バージョン、暗号スイート、SNI、クライアント証明書 | openssl s_client -tls1_2、curl -v | 交渉の不一致、SNI が無く別の証明書が返る |
全員に出るならサーバー側、一部の端末だけなら端末側(ルート・時刻・経路)から疑うのが基本です。
そして大事なことを1つ。端末で「詳細設定 → 進む」を押して回避したり、curl -kを設定に残したりしないでください。回避した端末だけが中間者攻撃に無防備になります(第1回)。なお、検査用のプロキシを通る端末では、発行者がプロキシのCAに置き換わって見えます。
コマンドで確かめる
Linux・Macでは、サーバーが送ったチェーンの本数と、証明書の期限・名前・用途を見ます。
$ openssl s_client -connect www.example.jp:443 -servername www.example.jp -showcerts </dev/null
Certificate chain
0 s:CN=www.example.jp
i:C=JP, O=Example Corp, CN=Example Issuing CA 01
a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
v:NotBefore: Jul 28 20:03:02 2026 GMT; NotAfter: Feb 13 20:03:01 2027 GMT
Verify return code: 21 (unable to verify the first certificate)
(抜粋。1 番の中間証明書が無い=入れ忘れ)
$ openssl x509 -in server.pem -noout -subject -issuer -enddate -ext subjectAltName,keyUsage,extendedKeyUsage
$ openssl x509 -in server.pem -noout -checkend 2592000 # 30日以内に切れるなら終了コード 1
$ openssl verify -crl_check -crl_download -untrusted chain.pem server.pem
error 23 at 0 depth lookup: certificate revoked
Windows(PowerShell)では、接続して証明書と検証の結果を表示します。失効とAIAの取得は、certutil -verify -urlfetchで1つずつ確かめます。
PS> $h='www.example.jp'; $t=New-Object Net.Sockets.TcpClient($h,443)
PS> $s=New-Object Net.Security.SslStream($t.GetStream(),$false,{param($a,$c,$ch,$e) $global:pe=$e; $global:st=$ch.ChainStatus.Status -join ','; $true})
PS> $s.AuthenticateAsClient($h); $c=[Security.Cryptography.X509Certificates.X509Certificate2]$s.RemoteCertificate
PS> $c | Format-List Subject, Issuer, NotAfter, @{n='SAN';e={$c.Extensions['2.5.29.17'].Format($false)}}
PS> "$($s.SslProtocol) $pe $st" # 例:Tls13 RemoteCertificateChainErrors NotTimeValid
PS> certutil -verify -urlfetch server.cer
原因と確認コマンドの対応表
ここまでを1枚の表にまとめます。障害対応のときに手元に置いておくと便利です。
| 原因 | 見える症状 | 確認コマンド(Linux・Mac/Windows) | 詳しくは |
|---|---|---|---|
| 期限切れ | DATE_INVALID、curl (60) has expired | openssl x509 -noout -enddate/PowerShell の NotAfter、certutil -dump | 第8回 |
| 名前の不一致 | COMMON_NAME_INVALID | openssl x509 -noout -ext subjectAltName/$c.Extensions[‘2.5.29.17’] | 第4回 |
| 中間証明書の不足 | ブラウザーは正常、curl・Java だけ (60) | openssl s_client -showcerts の本数/サーバーで Get-ChildItem Cert:\LocalMachine\CA | 第5回 |
| ルートが未配布 | 一部の端末だけ AUTHORITY_INVALID | openssl verify -CAfile/Get-ChildItem Cert:\LocalMachine\Root、certutil -verify | 第5回 |
| 失効、CRL に届かない | REVOKED、または接続が遅い・失敗 | openssl verify -crl_check -crl_download/certutil -verify -urlfetch | 第5回 |
| 時刻のずれ | 一部の端末だけ DATE_INVALID | timedatectl/w32tm /query /status | — |
| SHA-1・用途の不一致 | WEAK_SIGNATURE_ALGORITHM、KEY_USAGE_INCOMPATIBLE | openssl x509 -noout -text(Signature Algorithm、Key Usage)/certutil -dump | 第4回 |
| TLS のバージョン・暗号 | VERSION_OR_CIPHER_MISMATCH、curl (35) | openssl s_client -tls1_2、curl -v/Get-TlsCipherSuite(サーバー側) | 第7回 |
連載のまとめ:回ごとの要点の早見表
ここで、連載全体を振り返っておきます。困ったときは、この表から該当する回に戻ってください。
| 回 | テーマ | 押さえること | 使う場面 |
|---|---|---|---|
| 第1〜2回 | 脅威と暗号の基礎 | 盗聴・改ざん・なりすまし、ECDHE と前方秘匿性、HMAC と署名の違い | 仕組みの説明、設計の前提 |
| 第3〜4回 | 試す、証明書の中身 | openssl・PowerShell で作って読む。検証は SAN、EKU・AIA・CDP | 証明書の確認(第11回 問4) |
| 第5回 | PKI と信頼 | チェーンと信頼ストア、検証の手順、CRL は必須・OCSP は任意、CT・CAA | 信頼されない理由の調査 |
| 第6回 | 種類と発行 | DV・OV・EV、ワイルドカードは1階層、CSR、200日→100日→47日 | 証明書の手配(第11回 問1・問3) |
| 第7回 | TLS の仕組み | TLS 1.3、1.0/1.1 は禁止、SNI・mTLS、PQC のハイブリッド鍵交換 | 設定の見直し、接続の調査 |
| 第8回 | ライフサイクルと自動化 | 棚卸し、ACME と ARI、期限と CT の監視 | 47日への備え(第11回 問2) |
| 第9回 | 社内PKI とクラウド | AD CS の2層と ESC の対策、ACM・Private CA、LB の終端、VMCA | 社内の証明書、vSphere(第11回 問3・問5) |
| 第10回 | トラブルシュート | エラーコードの読み方、中間証明書の入れ忘れ、切り分けの順序 | 障害対応(第11回 問4) |
どの回も、「誰が、どの名前の、どの鍵を、誰の署名で信じているか」を意識すると理解しやすくなります。
持ち帰ってほしい3つのこと

1. 証明書は、名前と公開鍵の結び付き
エラーは回避せず、名前(SAN)・チェーン・期間・用途・時刻の順に、openssl s_client(WindowsはPowerShell・certutil)で確かめる。
2. 証明書は台数ではなく名前で数え、TLSをどこで終端するかで置き場所を決める
秘密鍵の置き場所は少ないほど安全で、更新も楽になる。
3. 更新は人から仕組みへ
有効期間は2029年に47日になる。棚卸し・ACMEによる自動化・期限とCTの監視を今から整え、社内CAは2層で作り、Tier 0として守る。
まずは自分が管理するサイトにopenssl s_client -showcertsを実行し、送られているチェーンと期限を確かめてみてください。
参考資料
- RFC:5280(X.509・CRL)、9525(名前の検証)、9846(TLS 1.3、2026年に8446を置き換え)、8996(TLS 1.0/1.1の廃止)、9325(TLSの推奨)、8555(ACME)、9773(ARI)、6962・9162(CT)、8659(CAA)、6960(OCSP)、2104(HMAC)
- CA/B Forum・ルートプログラム:Baseline RequirementsとBallot SC-081(有効期間の短縮)、Chrome Root Program、Mozilla Root Store Policy、Microsoft Trusted Root Program、Apple Root Certificate Program
- 公式ドキュメント:Microsoft Learn(AD CS、KB5014754)、AWS Certificate Manager・AWS Private CAユーザーガイド、Azure Key Vaultのドキュメント、Broadcom TechDocs(vSphere Authentication)、OpenSSLのマニュアル、Let’s Encryptのドキュメント
まとめ
- エラーは回避しない。
-kや「進む」は、その端末だけを中間者攻撃に無防備にする - 同じ原因でもツールで見え方が違う。ブラウザーのエラーコードから原因の見当をつける
- 中間証明書の入れ忘れは、ブラウザーでは見えずcurl・Java・機器だけで失敗する
- 証明書が正しくても、TLSの版・暗号スイート・SNI・中継装置で失敗することがある
- 切り分けは症状→名前と経路→サーバーの証明書→端末での検証→TLSのパラメーター。全員ならサーバー側、一部なら端末側
次回はいよいよ最終回。ここまでの知識を使って、5つの設計演習に取り組みます。
連載「証明書入門」全11回
- なぜ証明書が必要か
- 暗号の基礎
- openssl・PowerShellで試す
- X.509証明書の中身
- PKIと信頼の仕組み
- 証明書の種類と発行
- TLSの仕組み
- ライフサイクルと自動化
- 社内PKIとクラウド
- 証明書トラブルシュート(この記事)
- 証明書の設計演習


コメント