エラーメッセージ
The remote certificate is invalid because of errors in the certificate chain: PartialChain
ほかのフラグと組み合わさって表示されることがよくあります(例:「PartialChain, RevocationStatusUnknown」)。HttpClient はこれを「The SSL connection could not be established, see inner exception.」でラップします。
.NET SslStream / HttpClient — X509ChainStatusFlags.PartialChain: the chain could not be built up to a root
このエラーの意味
.NET は、サーバーの証明書からいずれかのルートまでのチェーンを構築できませんでした。中間証明書が欠けています。ルートが信頼されていても(再現環境のように)、リーフとルートの間が途切れていると検証できません。.NET は、証明書の Authority Information Access 拡張に URL があり、そこに到達できる場合は、欠けている中間証明書をダウンロードできます。そのため、このエラーは主にプライベート CA、アクセスが制限されたネットワーク、コンテナーで発生します。
発生する理由
サーバーがリーフ証明書しか送信していない
よくあるリーフ証明書だけを含む証明書ファイルや PFX で設定された Kestrel、IIS のバインド、リバースプロキシが該当します。
中間証明書を取得できない
ときどきプライベート CA には AIA の URL がないことが多く、ファイアウォールの内側にあるホストやコンテナーはパブリック CA の URL に到達できないため、.NET は欠けている部分を自力で補えません。
中間証明書がほかのマシンにしかない
ときどきWindows では、CertificateAuthority ストアにキャッシュまたはインストールされた中間証明書のおかげで、一部のマシンではチェーンが機能しますが、新しく構築したサーバーや Linux コンテナーでは失敗します。
修正方法
- 1.
サーバーが送信している内容を確認する
中間 CA が発行した証明書がハンドシェイクに 1 つだけ含まれていれば、この問題で確定です。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' - 2.
サーバーから完全なチェーンを送信する
ecdsa.com のテストでは、Kestrel(.NET 10)は、フルチェーンの PEM を ServerCertificate だけで渡した場合はリーフしか送信せず、例のように ServerCertificateChain を設定すると中間証明書も送信しました。IIS の場合は、Windows が中間証明書を送信するよう、サーバーの「中間証明機関」ストアにインストールしてください。
csharp // Kestrel sends intermediates only when they are given as ServerCertificateChain builder.WebHost.ConfigureKestrel(k => k.ConfigureHttpsDefaults(o => { o.ServerCertificate = X509Certificate2.CreateFromPemFile("fullchain.pem", "server.key"); var chain = new X509Certificate2Collection(); chain.ImportFromPemFile("fullchain.pem"); // leaf + intermediates o.ServerCertificateChain = chain; })); - 3.
欠けている中間証明書を見つける
リーフ証明書の AIA 拡張は発行者の証明書を指しています。その証明書をサーバーの設定に追加してください。
bash # The leaf names where its issuer can be downloaded (Authority Information Access) openssl x509 -in server.pem -noout -ext authorityInfoAccess