早朝に一部のメールが滞留してたのでログを見たら。
1 2 |
Sep 30 23:06:30 metal postfix/smtp[61376]: 7224324829CA: Server certificate not trusted Sep 30 23:06:31 metal postfix/smtp[61376]: 7224324829CA: to=, relay=x, delay=5.4, delays=0.71/0.09/4.6/0, dsn=4.7.5, status=deferred (Server certificate not trusted) |
Let’s Encryptの証明書搭載のサーバなので、9月も終わりついにIdenTrustのX3が失効したか。にしても証明書の更新し損ねてたのだろか… と証明書のファイルの日付見ても9月1日のものです。古いサーバなので5年前のあれと同じだろうと思いつきますが、せっかくなので確認します。その機械から
1 2 3 4 5 6 7 8 9 |
> openssl version OpenSSL 1.0.2u-freebsd 20 Dec 2019 > openssl s_client -showcerts -connect x:25 -starttls smtp CONNECTED(00000003) depth=3 O = Digital Signature Trust Co., CN = DST Root CA X3 verify error:num=10:certificate has expired notAfter=Sep 30 14:01:15 2021 GMT --- |
他の機械から
1 2 3 4 5 6 7 8 9 10 |
> openssl version OpenSSL 1.1.1h-freebsd 24 Aug 2021 > openssl s_client -showcerts -connect x:25 -starttls smtp CONNECTED(00000003) depth=1 C = US, O = Let's Encrypt, CN = R3 verify return:1 depth=0 CN = x verify return:1 --- |
とか
1 2 3 4 5 6 7 8 9 10 11 12 |
$ openssl version OpenSSL 1.1.1f 31 Mar 2020 $ openssl s_client -showcerts -connect x:25 -starttls smtp CONNECTED(00000004) depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = R3 verify return:1 depth=0 CN = x verify return:1 --- |
R3をトラストアンカーにしている機械あり。サーバ側でできることはLet’s Encryptの場合はfullchain.pemおよびchain.pemのしっぽを一つ減らす、となるかと思います。
1 |
Certificate validation failed; subject='CN=DST Root CA X3, O=Digital Signature Trust Co.', issuer='CN=DST Root CA X3, O=Digital Signature Trust Co.', error='certificate has expired', depth='3' |
を引き起こす証明書を切り取る。クライアント側では当時の記録を読み返すとOpenSSLを1.1.0以降のやばくないものにするというのが解決方法になりそうです。
今回問題が起きるのはLet’s Encryptと同時にサポート期限を迎えたFreeBSD 11の1台だけ、内部のメールルーティング用で時間でき次第廃棄にする予定の機械、chain.pemもきっと3ヶ月以内の証明書更新の際に更新されるはず、ということでインバスケットの処理としてはサーバ側ではなくその人だけの対応で済ませるのが良さそうです。portsでsecurity/opensslを導入して、/etc/make.confにDEFAULT_VERSIONS += ssl=openssl を追加。mail/postfixを再インストールして対応完了。baseのOpenSSLとportsのOpenSSLを使ったportsが混在してますが廃棄間近なので気にしません。
2021-10-03追記
IdenTrustのX3の無くなったchain.pemが自動的に使われるようになるのかと思っていたら、2020年12月のExtending Android Device Compatibility for Let’s Encrypt Certificatesによれば
IdenTrust has agreed to issue a 3-year cross-sign for our ISRG Root X1 from their DST Root CA X3. The new cross-sign will be somewhat novel because it extends beyond the expiration of DST Root CA X3. This solution works because Android intentionally does not enforce the expiration dates of certificates used as trust anchors. ISRG and IdenTrust reached out to our auditors and root programs to review this plan and ensure there weren’t any compliance concerns.
ということでもう2年ちょいはDST Root CA X3がついてそうなのでした。AndroidはトラストアンカーのnotAfterを見ないという実装を採用しているからしばらくAndroidが救われるとのことです。
Today, some ACME clients are able to instead request an alternate chain, if their user has configured it. We currently provide the option of getting the chain: Subscriber Certificate < – R3 < – ISRG Root X1 We will continue to offer this same chain as an alternate. However, note that most ACME clients don’t yet have a way to select this alternate chain (for example, Certbot selects chains by looking to see if they contain a given Issuer Name, but this chain doesn’t contain any Issuer Names which the high compatibility chain above doesn’t). We’ll be working with ACME client developers to create more flexible chain selection mechanisms going forward.
今回こちらで問題になっているのはSMTPサーバだけでAndroid関係ないのでDST Root CA X3が無いchain.pemを自動的に使うように設定したいです。しかしCertbotはそれを選択できないとのことなので今度はそちらを見に行きます。
–preferred-chain を指定する際に、chain全部のIssuerを見るのではなく、尻尾のIssuerだけを見るようなPRを作成してくれた方がいて、早々にマージされています。
なるほどcertbot/certbot/crypto_util.py の find_chain_with_issuer() がシンプルになっているCertbotを利用すればよいのですね。利用中のCertbotはUbuntuで動いていてそこから各所に配布するようになっています。Ubuntuなのでportsのようなありがたい仕組みがないので、EFFのインストラクションに従ってちゃんとsnapを利用して動作させるように設定し直します。念のため /snap/certbot/current/lib/python3.8/site-packages/certbot/crypto_util.py の find_chain_with_issuer() がシンプルに尻尾である[-1]だけ見ていることを確認します。
証明書更新スクリプトが/snap/bin/certbotを利用するように変更して
1 |
--preferred-chain 'ISRG Root X1' |
というオプションを追加するか、letsencrypt/renewal/domain.confの[renewalparams]セクションにpreferred_chain = 行を追加、既存の場合は更新します。
1 2 3 |
[renewalparams] ... preferred_chain = ISRG Root X1 |
これで次の更新からDST Root CA X3のいないchain.pemが使われるはずです。きっと。更新期限が近いドメインは無いようなのでrenewを動かしたら全部スキップされました。後述の手動の変更を加えたドメインだけはエラーも出てました。
1 2 3 |
Renewal configuration file /etc/letsencrypt/renewal/x.conf is broken. The error was: expected /usr/local/etc/letsencrypt/live/x/chain.pem to be a symlink Skipping. |
これは更新時期過ぎたら元のsymlinkに戻して手動で再度renewすることにします。ランダムに更新してパラメータの調整や配布のスクリプトが流れるようにしているので、snapで追加された自動更新は実行されないようにします。
1 2 3 4 |
$ sudo rm /etc/systemd/system/snap.certbot.renew.timer $ sudo systemctl mask snap.certbot.renew.timer $ sudo rm /etc/systemd/system/snap.certbot.renew $ sudo systemctl mask snap.certbot.renew |
Production Chain Changesを見ると、ECDSA証明書を発行してもらう場合もchain.pemやfullchain.pemにDST Root CA X3が入ることはなさそうです。
2021-10-02追記
クライアント側は内部のメール処理だけでしたがサーバ側は一部外部からのメールも受けていたので、サーバ側も対応することにしました。インバスケットの優先順位付け失敗です。暫定措置として、live/ の下(certbot仕様)の該当ドメインの chain.pemとfullchain.pemのsymlinkを削除してsymlink先からコピー
1 2 3 4 |
$ cd letsencrypt/live/x/ $ rm chain.pem fullchain.pem $ cp -p ../../archive/x/chainXXX.pem chain.pem $ cp -p ../../archive/x/fullchainXXX.pem fullchain.pem |
して、それぞれのファイルの尻尾にある下と同じ証明書を消します。あとはこちらで利用させてもらってるのがワイルドカード証明書なので各所に自動的に配布されるようにしてあるので少し待って対応完了。次回のサーバ証明書更新までにcertbotで対応する情報などがわんさか出てくるでしょうからあとはそれを使って楽をします(前記のように週末ちょっと調べました)。
ググるとそれなりに影響あったようです。本件同様にクロス署名に対応できないOpenSSLで発生したものも含めて。
なんかY2K問題のお祭り騒ぎを思い出しました。昭和100年で問題起きるシステムがネットにつながってたらやだなと思いますが、2038年はどうでしょう。IoT機器も64bitになっててそんなに影響ないとかでしょうか。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
-----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- |
このCA証明書の情報。先のs_connectでも表示されていますが、Sep 30 14:01:15 2021 GMTなので、Sep 30 23:01:15 JSTです。エラーログの時間とも合います。CApathのhash(SHA-1)からpemを探す場合は
1 2 |
> openssl x509 -subject_hash -noout -in そのCA証明書 2e5ac55d |
なので、2e5ac55d.*を探すと良いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
Certificate: Data: Version: 3 (0x2) Serial Number: 44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b Signature Algorithm: sha1WithRSAEncryption Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3 Validity Not Before: Sep 30 21:12:19 2000 GMT Not After : Sep 30 14:01:15 2021 GMT Subject: O=Digital Signature Trust Co., CN=DST Root CA X3 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:df:af:e9:97:50:08:83:57:b4:cc:62:65:f6:90: 82:ec:c7:d3:2c:6b:30:ca:5b:ec:d9:c3:7d:c7:40: c1:18:14:8b:e0:e8:33:76:49:2a:e3:3f:21:49:93: ac:4e:0e:af:3e:48:cb:65:ee:fc:d3:21:0f:65:d2: 2a:d9:32:8f:8c:e5:f7:77:b0:12:7b:b5:95:c0:89: a3:a9:ba:ed:73:2e:7a:0c:06:32:83:a2:7e:8a:14: 30:cd:11:a0:e1:2a:38:b9:79:0a:31:fd:50:bd:80: 65:df:b7:51:63:83:c8:e2:88:61:ea:4b:61:81:ec: 52:6b:b9:a2:e2:4b:1a:28:9f:48:a3:9e:0c:da:09: 8e:3e:17:2e:1e:dd:20:df:5b:c6:2a:8a:ab:2e:bd: 70:ad:c5:0b:1a:25:90:74:72:c5:7b:6a:ab:34:d6: 30:89:ff:e5:68:13:7b:54:0b:c8:d6:ae:ec:5a:9c: 92:1e:3d:64:b3:8c:c6:df:bf:c9:41:70:ec:16:72: d5:26:ec:38:55:39:43:d0:fc:fd:18:5c:40:f1:97: eb:d5:9a:9b:8d:1d:ba:da:25:b9:c6:d8:df:c1:15: 02:3a:ab:da:6e:f1:3e:2e:f5:5c:08:9c:3c:d6:83: 69:e4:10:9b:19:2a:b6:29:57:e3:e5:3d:9b:9f:f0: 02:5d Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Subject Key Identifier: C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 Signature Algorithm: sha1WithRSAEncryption a3:1a:2c:9b:17:00:5c:a9:1e:ee:28:66:37:3a:bf:83:c7:3f: 4b:c3:09:a0:95:20:5d:e3:d9:59:44:d2:3e:0d:3e:bd:8a:4b: a0:74:1f:ce:10:82:9c:74:1a:1d:7e:98:1a:dd:cb:13:4b:b3: 20:44:e4:91:e9:cc:fc:7d:a5:db:6a:e5:fe:e6:fd:e0:4e:dd: b7:00:3a:b5:70:49:af:f2:e5:eb:02:f1:d1:02:8b:19:cb:94: 3a:5e:48:c4:18:1e:58:19:5f:1e:02:5a:f0:0c:f1:b1:ad:a9: dc:59:86:8b:6e:e9:91:f5:86:ca:fa:b9:66:33:aa:59:5b:ce: e2:a7:16:73:47:cb:2b:cc:99:b0:37:48:cf:e3:56:4b:f5:cf: 0f:0c:72:32:87:c6:f0:44:bb:53:72:6d:43:f5:26:48:9a:52: 67:b7:58:ab:fe:67:76:71:78:db:0d:a2:56:14:13:39:24:31: 85:a2:a8:02:5a:30:47:e1:dd:50:07:bc:02:09:90:00:eb:64: 63:60:9b:16:bc:88:c9:12:e6:d2:7d:91:8b:f9:3d:32:8d:65: b4:e9:7c:b1:57:76:ea:c5:b6:28:39:bf:15:65:1c:c8:f6:77: 96:6a:0a:8d:77:0b:d8:91:0b:04:8e:07:db:29:b6:0a:ee:9d: 82:35:35:10 SHA1 Fingerprint=DA:C9:02:4F:54:D8:F6:DF:94:93:5F:B1:73:26:38:CA:6A:D7:7C:13 |