現象
$ echo|openssl s_client -connect helloworld.letsencrypt.org:443 -servername helloworld.letsencrypt.org
Verify return code: 20 (unable to get local issuer certificate)
- OpenSSLを使っている、curl やRuby なども影響を受ける
原因
- Let'sEncryptの証明書チェーンは、
R3 --> ISRG Root X1 --> DST Root CA X3
となっている - この、
DST Root CA X3
が 2021/09/30 に期限切れとなった - トラストストアには、
ISRG Root X1
とDST Root CA X3
が入っているが OpenSSL 1.0.x では、 証明書チェーンの中に「トラストストアにあるが期限切れ」の証明書があると検証が失敗扱いになる という挙動がある
歴史的経緯
Let'sEncrypt がルート証明書を DST Root CA X3
から ISRG Root X1
に変更しようとする流れ
- もともとの Let'sEncrypt のルート証明書は、
DST Root CA X3
- Let'sEncrypt は、ルート証明書を
ISRG Root X1
に変えようとしていた - しかし、古いクライアントでは、トラストストアに、
ISRG Root X1
が無いため、中間証明書をDST Root CA X3
とISRG Root X1
のクロスサイン証明書にしていた(これにより、どちらかがトラストストアにあれば検証が通る) - その後、2021/09/30 に
DST Root CA X3
の期限が切れるため、ルート証明書をISRG Root X1
だけにする動きが始まる
Android7.1 問題と苦肉の策
- しかし、Android7.1以前のバージョンにはISRGのルート証明書が入っていないため、ルート証明書を切り替えると、Android7.1以前でLet'sEncryptの証明書が使えなくなるという問題が判明
- で、Let'sEncryptは苦肉の策として、以下のようにルート証明書を変更するとアナウンス
R3 --> ISRG Root X1 --> DST Root CA X3
- ルート証明書の上にルート証明書をチェーンするという荒業
- これをすると、Android7.1以前では、ISRGがトラストストアにないため、DSTまで遡る。ここで、2021/09/30 以降は、DSTの有効期限が切れてしまうが... Android7.1では、証明書の有効期限チェックを行わない ため、問題が解決すると... 解決...?
- ISRGをトラストストアにもつ、他のクライアントではDSTまで遡らないため、特に問題はないはずだったが...
OpenSSL 1.0.x では Android互換チェーン の検証に失敗する
- しかし、OpenSSL 1.0.x では、上記の「Android互換チェーン」については検証が失敗扱いとなる。これは、OpenSSL1.0.xで、信頼チェーンの間に無効な証明書があって、さらにそれがトラストストアに登録済だと、検証が失敗するという挙動(仕様?)のため
👇 Let'sEncrypt による、OpenSSL 1.0.x では Android互換チェーン の検証に失敗する件の記事
- OpenSSL 1.1.0 では修正済みで、1.0.x はたくさんの脆弱性があるので、さっさとバージョンをあげようとアナウンスしている
対策
OpenSSL公式は、トラストストアにて、期限切れのDSTのルート証明書を削除するようにと、アナウンスしている
https://t.co/bL7HmxKqcr?amp=1 www.openssl.org
AWS(EC2)では、ルート証明書のyumパッケージである ca-certificates
にて、上記の対応を済ませたバージョンを配布しているので、yum update ca-certificates
すれば解決する
AWSでは、さらにこちらで手動対策方法もアナウンスしている