有効期限切れのルート証明書を削除する

有効期限切れのルート証明書を削除するスクリプト(bash)を紹介します。

クライアントやサーバーの証明書リスト(バンドル)の中には既に有効期限が切れている証明書が含まれている場合があります。
今回は有効期限が切れた証明書のみを削除する方法を記載します。




# 実行環境

実行環境はwindows WSL2です。

```
$ bash --version
bash --version
GNU bash, version 5.0.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


$ openssl version
OpenSSL 1.1.1f  31 Mar 2020
```

# スクリプト本体

・確認する有効期限をパラメータとして設定
・読み込ませた証明書を1つずつ分割してフォルダに保存（1つ目のfor文)
・有効期限が切れている証明書のみ別フォルダへ移動（2つ目のfor文)
・有効期限が切れていない証明書のみを結合（3つ目のfor文)
```
#!/bin/bash

expiration_year=0 # (year)
check_date=$(($expiration_year*86400*365))  # (sec)

echo "Removing certificates expired within $expiration_year years"
echo "change 'expiration_year' in remove-expire-cert.sh if you want to change the expiration."

mkdir -p ./cert
mkdir -p ./cert_expire
mkdir -p ./list

cd ./cert

for cert; 
  do
  awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > "cert" n ".pem"}' < ../$cert
done


for pem in `ls -v`;
  do
  echo -n "$pem "  >>  ../list/subject.txt
  openssl x509 -noout -subject -in $pem >> ../list/subject.txt
  checkend=`openssl x509 -noout -checkend $check_date -in $pem`
  if [ "$checkend" = "Certificate will expire" ]; then
    echo -n "$pem "  >>  ../list/expire.txt
    echo $(openssl x509 -noout -subject -enddate -in $pem) >>  ../list/expire.txt
    mv "$pem" ../cert_expire/
  fi
done

for cert; 
  do
  cat * >> ../newcert_$(date +%Y%m%d).pem
done

echo ""
echo "./newcert_$(date +%Y%m%d)        : new certfile without expired certificates"
echo "./cert/*.pem              : not expired certfile"
echo "./cert_expire/*.pem       : expired certfile"
echo "./list/expire.txt         : expired certfile list"
echo "./list/subject.txt        : all certfile list"
echo ""
echo "completed"
```

## 1つ目のfor文

awkから始まるコマンド行により、証明書リストに含まれる複数の証明書を1つずつのファイルに分けて、certN.pemという名前でフォルダに保存
（[有効期限切れのルート証明書ファイルにより、SSL通信に失敗する際の対処法](https://qiita.com/y-ken/items/dac5ae8ad6bdbb0e0f17) の記載を参考にしました）
```
  awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > "cert" n ".pem"}' < ../$cert
```

## 2つ目のfor文

```
# lsの-vオプションによりcertN.pemをNの数字順に並べて出力
for pem in `ls -v`; 
  do
  # echoコマンドで、1つ目のfor文で作成したcertN.pemをNの数字順に並べてsubject.txtへ出力
  echo -n "$pem "  >>  ../list/subject.txt
  # opensslコマンドで、証明書のSubject情報をsubject.txtへ追記
  openssl x509 -noout -subject -in $pem >> ../list/subject.txt
  checkend=`openssl x509 -noout -checkend $check_date -in $pem`
  # 証明書の有効期限切れ(Certificate will expire)の場合に処理する条件文
  if [ "$checkend" = "Certificate will expire" ]; then
    # 条件に合致したcertN.pemをexpire.txtへ出力
    echo -n "$pem "  >>  ../list/expire.txt
    # 証明書のSubject情報と有効期限日をexpire.txtへ出力
    echo $(openssl x509 -noout -subject -enddate -in $pem) >>  ../list/expire.txt
　　# 条件に合致したcertN.pemを別フォルダへ移動
    mv "$pem" ../cert_expire/
  fi
done
```

参考：下記コマンド(checkendが0秒)の場合、現時点で有効期限切れの証明書を表示します。
```
$ openssl x509 -noout -checkend 0 -in $pem

Certificate will not expire  #有効期限内の場合
Certificate will expire  #有効期限切れの場合
```

## 3つ目のfor文

有効期限切れで移動されなかった証明書(＝有効期限内の証明書のみ)を結合

```
for cert; 
  do
  cat * >> ../newcert_$(date +%Y%m%d).pem
done
```


# 証明書リスト(バンドル)

今回は、ブラウザのMicrosoft Edge(バージョン 112.0.1722.34, 2023/04/08時点最新)から「信頼されたルート証明機関」を全てエクスポート(pfx形式)で出力した物を利用することにします。

```
openssl pkcs12 -in edge.pfx -out edge.pem -nodes
Enter Import Password: ※エクスポート時に設定したパスワードを入力
MAC verified OK
```


# 利用方法

コマンドの引数に処理したい証明書リスト(バンドル)を指定します。

```
# sh remove-expire-cert.sh edge.pem
Removing certificates expired within 0 years
change 'expiration_year' in remove-expire-cert.sh if you want to change the expiration.

./newcert_20230406        : new certfile without expired certificates
./cert/*.pem              : not expired certfile
./cert_expire/*.pem       : expired certfile
./list/expire.txt         : expired certfile list
./list/subject.txt        : all certfile list

completed
```

# 結果確認

newcert_YYYYMMDDのファイルが作成されたことを確認

```
# ls -lv
total 276
drwxr-xr-x 2 root  root    4096 Apr  6 18:28 cert
drwxr-xr-x 2 root  root    4096 Apr  6 18:28 cert_expire
-rw-r--r-- 1 root  root    141713 Apr  6 13:22 edge.pem
drwxr-xr-x 2 root  root    4096 Apr  6 18:28 list
-rw-r--r-- 1 root  root  120064 Apr  6 18:28 newcert_20230406.pem
-rw-r--r-- 1 root  root    1287 Apr  6 18:26 remove-expire-cert.sh
```

有効期限切れの証明書

```
# ls -lv ./cert_expire/
total 44
-rw-r--r-- 1 root root 2266 Apr  6 18:28 cert2.pem
-rw-r--r-- 1 root root 1333 Apr  6 18:28 cert4.pem
-rw-r--r-- 1 root root 1985 Apr  6 18:28 cert6.pem
-rw-r--r-- 1 root root 2977 Apr  6 18:28 cert15.pem
-rw-r--r-- 1 root root 1438 Apr  6 18:28 cert17.pem
-rw-r--r-- 1 root root 2296 Apr  6 18:28 cert21.pem
-rw-r--r-- 1 root root 1818 Apr  6 18:28 cert22.pem
-rw-r--r-- 1 root root 1698 Apr  6 18:28 cert26.pem
-rw-r--r-- 1 root root 1907 Apr  6 18:28 cert42.pem
-rw-r--r-- 1 root root 1409 Apr  6 18:28 cert53.pem
-rw-r--r-- 1 root root 2522 Apr  6 18:28 cert63.pem
```

有効期限切れ証明書のSubjectおよび有効期限を確認
(Windows Updateは最新の状態ですが、保持している「信頼されたルート証明機関」の中に11個の期限切れ証明書が含まれていた）

```
# cat ./list/expire.txt
cert2.pem subject=C = US, ST = UT, L = Salt Lake City, O = The USERTRUST Network, OU = http://www.usertrust.com, CN = UTN-USERFirst-Object notAfter=Jul 9 18:40:36 2019 GMT
cert4.pem subject=C = ZA, ST = Western Cape, L = Durbanville, O = Thawte, OU = Thawte Certification, CN = Thawte Timestamping CA notAfter=Dec 31 23:59:59 2020 GMT
cert6.pem subject=C = ZA, ST = Western Cape, L = Cape Town, O = Thawte Consulting cc, OU = Certification Services Division, CN = Thawte Premium Server CA, emailAddress = premium-server@thawte.com notAfter=Dec 31 23:59:59 2020 GMT
cert15.pem subject=C = BM, O = QuoVadis Limited, OU = Root Certification Authority, CN = QuoVadis Root Certification Authority notAfter=Mar 17 18:33:33 2021 GMT
cert17.pem subject=O = VeriSign Trust Network, OU = "VeriSign, Inc.", OU = VeriSign Time Stamping Service Root, OU = "NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc." notAfter=Jan 7 23:59:59 2004 GMT
cert21.pem subject=DC = com, DC = microsoft, CN = Microsoft Root Certificate Authority notAfter=May 9 23:28:13 2021 GMT
cert22.pem subject=OU = Copyright (c) 1997 Microsoft Corp., OU = Microsoft Corporation, CN = Microsoft Root Authority notAfter=Dec 31 07:00:00 2020 GMT
cert26.pem subject=C = US, O = MSFT, CN = Microsoft Authenticode(tm) Root Authority notAfter=Dec 31 23:59:59 1999 GMT
cert42.pem subject=O = Digital Signature Trust Co., CN = DST Root CA X3 notAfter=Sep 30 14:01:15 2021 GMT
cert53.pem subject=O = Microsoft Trust Network, OU = Microsoft Corporation, OU = Microsoft Time Stamping Service Root, OU = Copyright (c) 1997 Microsoft Corp. notAfter=Dec 30 23:59:59 1999 GMT
cert63.pem subject=C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root notAfter=May 30 10:48:38 2020 GMT
```


# 参考URL

有効期限切れのルート証明書を確認する方法として下記サイトを参考にしました。

有効期限切れのルート証明書ファイルにより、SSL通信に失敗する際の対処法
https://qiita.com/y-ken/items/dac5ae8ad6bdbb0e0f17


下記URL手順にて「信頼されたルート証明機関」タブのリストを全て選択した状態でエクスポートを行いました。

ブラウザから証明書をエクスポートするには
https://knowledge.digicert.com/ja/jp/solution/SO23796.html


ルート証明書の期限切れの影響
https://www.digicert.com/jp/blog/impacts-of-root-certificate-expiration