pkilintのインストールと利用方法(Rocky Linux 8.9)

pkilintとは

pkilintは、DigiCertが2023年5月に開発したASN.1を使用してエンコードされたドキュメントのリンティングフレームワーク。
pkilintはASN.1構造、「ドキュメント」タイプのリンターを素早く作成し、準拠状況やPolicyを確認するための非常に拡張可能なツールボックスである。
認証局の自己監査や外部監査でも利用できると思われる。

インストール方法

Linux環境が必要で、Python 3.9以降がインストールされている必要がある。
ここでは、Rocky Linux v.8.9を使用する。

[root@localhost ~]# cat /etc/redhat-release
Rocky Linux release 8.9 (Green Obsidian)
[root@localhost ~]# python3 --version
Python 3.6.8                                                                                                                                                                                                
[root@localhost bin]# dnf install python39
メタデータの期限切れの最終確認: 1:42:00 前の 2024年xx月xx日 xx時xx分xx秒 に実施しました。
依存関係が解決しました。
================================================================================
 パッケージ        Arch   バージョン                            Repo      サイズ
================================================================================
インストール:
 python39          x86_64 3.9.18-1.module+el8.9.0+1581+c29ce980 appstream  33 k
依存関係のインストール:
 python39-libs     x86_64 3.9.18-1.module+el8.9.0+1581+c29ce980 appstream 8.2 M
 python39-pip-wheel
                   noarch 20.2.4-8.module+el8.9.0+1581+c29ce980 appstream 1.1 M
 python39-setuptools-wheel
                   noarch 50.3.2-5.module+el8.9.0+1581+c29ce980 appstream 496 k
弱い依存関係のインストール:
 python39-pip      noarch 20.2.4-8.module+el8.9.0+1581+c29ce980 appstream 1.9 M
 python39-setuptools
                   noarch 50.3.2-5.module+el8.9.0+1581+c29ce980 appstream 870 k
モジュールストリームの有効化中:
 python39                 3.9                                                  

トランザクションの概要
================================================================================
インストール  6 パッケージ

ダウンロードサイズの合計: 12 M
インストール後のサイズ: 45 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
(1/6): python39-3.9.18-1.module+el8.9.0+1581+c2 334 kB/s |  33 kB     00:00    
(2/6): python39-pip-wheel-20.2.4-8.module+el8.9 2.9 MB/s | 1.1 MB     00:00    
(3/6): python39-setuptools-50.3.2-5.module+el8. 2.5 MB/s | 870 kB     00:00    
(4/6): python39-pip-20.2.4-8.module+el8.9.0+158 2.1 MB/s | 1.9 MB     00:00    
(5/6): python39-setuptools-wheel-50.3.2-5.modul 3.0 MB/s | 496 kB     00:00    
(6/6): python39-libs-3.9.18-1.module+el8.9.0+15 5.8 MB/s | 8.2 MB     00:01    
--------------------------------------------------------------------------------
合計                                            5.8 MB/s |  12 MB     00:02     
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                        1/1 
  インストール中   : python39-setuptools-wheel-50.3.2-5.module+el8.9.0+15   1/6 
  インストール中   : python39-pip-wheel-20.2.4-8.module+el8.9.0+1581+c29c   2/6 
  インストール中   : python39-libs-3.9.18-1.module+el8.9.0+1581+c29ce980.   3/6 
  インストール中   : python39-3.9.18-1.module+el8.9.0+1581+c29ce980.x86_6   4/6 
  scriptletの実行中: python39-3.9.18-1.module+el8.9.0+1581+c29ce980.x86_6   4/6 
  インストール中   : python39-setuptools-50.3.2-5.module+el8.9.0+1581+c29   5/6 
  scriptletの実行中: python39-setuptools-50.3.2-5.module+el8.9.0+1581+c29   5/6 
  インストール中   : python39-pip-20.2.4-8.module+el8.9.0+1581+c29ce980.n   6/6 
  scriptletの実行中: python39-pip-20.2.4-8.module+el8.9.0+1581+c29ce980.n   6/6 
  検証             : python39-3.9.18-1.module+el8.9.0+1581+c29ce980.x86_6   1/6 
  検証             : python39-libs-3.9.18-1.module+el8.9.0+1581+c29ce980.   2/6 
  検証             : python39-pip-20.2.4-8.module+el8.9.0+1581+c29ce980.n   3/6 
  検証             : python39-pip-wheel-20.2.4-8.module+el8.9.0+1581+c29c   4/6 
  検証             : python39-setuptools-50.3.2-5.module+el8.9.0+1581+c29   5/6 
  検証             : python39-setuptools-wheel-50.3.2-5.module+el8.9.0+15   6/6 

インストール済み:
  python39-3.9.18-1.module+el8.9.0+1581+c29ce980.x86_64                         
  python39-libs-3.9.18-1.module+el8.9.0+1581+c29ce980.x86_64                    
  python39-pip-20.2.4-8.module+el8.9.0+1581+c29ce980.noarch                     
  python39-pip-wheel-20.2.4-8.module+el8.9.0+1581+c29ce980.noarch               
  python39-setuptools-50.3.2-5.module+el8.9.0+1581+c29ce980.noarch              
  python39-setuptools-wheel-50.3.2-5.module+el8.9.0+1581+c29ce980.noarch        

完了しました!
[root@localhost bin]# dnf module enable python39
メタデータの期限切れの最終確認: 1:42:43 前の 2024年xx月xx日 xx時xx分xx秒 に実施しました。
依存関係が解決しました。
行うべきことはありません。
完了しました!
[root@localhost bin]# dnf module list | grep python
libselinux-python    2.8             common                                   Python 2 bindings for libselinux                                                                                                                                                                                                          
python27             2.7 [d]         common [d]                               Python programming language, version 2.7                                                                                                                                                                                                  
python36             3.6 [d][e]      build, common [d]                        Python programming language, version 3.6                                                                                                                                                                                                  
python38             3.8 [d]         build, common [d]                        Python programming language, version 3.8                                                                                                                                                                                                  
python39             3.9 [d][e]      build, common [d]                        Python programming language, version 3.9                                                                                                                                                                                                  
[root@localhost bin]# dnf module enable python39
メタデータの期限切れの最終確認: 1:45:15 前の 2024年xx月xx日 xx時xx分xx秒 に実施しました。
依存関係が解決しました。
行うべきことはありません。
完了しました!
[root@localhost bin]# dnf module list | grep python
libselinux-python    2.8             common                                   Python 2 bindings for libselinux                                                                                                                                                                                                          
python27             2.7 [d]         common [d]                               Python programming language, version 2.7                                                                                                                                                                                                  
python36             3.6 [d][e]      build, common [d]                        Python programming language, version 3.6                                                                                                                                                                                                  
python38             3.8 [d]         build, common [d]                        Python programming language, version 3.8                                                                                                                                                                                                  
python39             3.9 [d][e]      build, common [d]                        Python programming language, version 3.9                                                                                                                                                                                                  
[root@localhost bin]# alternatives --list | grep python
python              	auto  	/usr/libexec/no-python
python3             	auto  	/usr/bin/python3.6
[root@localhost bin]# alternatives --display python3
python3 -ステータスは自動です。
リンクは現在 /usr/bin/python3.6 を指しています。
/usr/bin/python3.6 - 優先度 1000000
 スレーブ easy_install-3: /usr/bin/easy_install-3.6
 スレーブ pip-3: /usr/bin/pip-3.6
 スレーブ pip3: /usr/bin/pip3.6
 スレーブ pydoc-3: /usr/bin/pydoc3.6
 スレーブ pydoc3: /usr/bin/pydoc3.6
 スレーブ pyvenv-3: /usr/bin/pyvenv-3.6
 スレーブ python3-man: /usr/share/man/man1/python3.6.1.gz
/usr/bin/python3.11 - 優先度 31100
 スレーブ easy_install-3: (null)
 スレーブ pip-3: (null)
 スレーブ pip3: (null)
 スレーブ pydoc-3: /usr/bin/pydoc3.11
 スレーブ pydoc3: /usr/bin/pydoc3.11
 スレーブ pyvenv-3: (null)
 スレーブ python3-man: /usr/share/man/man1/python3.11.1.gz
/usr/bin/python3.9 - 優先度 3900
 スレーブ easy_install-3: /usr/bin/easy_install-3.9
 スレーブ pip-3: /usr/bin/pip-3.9
 スレーブ pip3: /usr/bin/pip3.9
 スレーブ pydoc-3: /usr/bin/pydoc3.9
 スレーブ pydoc3: /usr/bin/pydoc3.9
 スレーブ pyvenv-3: (null)
 スレーブ python3-man: /usr/share/man/man1/python3.9.1.gz
現在の「最適」バージョンは /usr/bin/python3.6 です。
[root@localhost bin]# alternatives --set python3 /usr/bin/python3.9
[root@localhost bin]# alternatives --list | grep python
python              	auto  	/usr/libexec/no-python
python3             	manual	/usr/bin/python3.9
[root@localhost bin]# python3 --version
Python 3.9.18

pkilint のパッケージの依存関係がマシンにグローバルにインストールされているパッケージと競合しないようにするには、pipx を使用して pkilint 用に別の Python 環境を作成するのが良い。
pipx ホームページの指示に従って pipx をインストールする。

[root@localhost ~]# python3 -m pip install --user pipx
WARNING: Running pip install with root privileges is generally not a good idea. Try `python3 -m pip install --user` instead.
Collecting pipx
  Downloading pipx-1.4.3-py3-none-any.whl (65 kB)
     |████████████████████████████████| 65 kB 3.3 MB/s 
Collecting userpath!=1.9.0,>=1.6
  Downloading userpath-1.9.2-py3-none-any.whl (9.1 kB)
Collecting packaging>=20
  Downloading packaging-24.0-py3-none-any.whl (53 kB)
     |████████████████████████████████| 53 kB 4.4 MB/s 
Collecting tomli; python_version < "3.11"
  Downloading tomli-2.0.1-py3-none-any.whl (12 kB)
Collecting argcomplete>=1.9.4
  Downloading argcomplete-3.2.3-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 2.6 MB/s 
Collecting platformdirs>=2.1
  Downloading platformdirs-4.2.0-py3-none-any.whl (17 kB)
Collecting click
  Downloading click-8.1.7-py3-none-any.whl (97 kB)
     |████████████████████████████████| 97 kB 5.9 MB/s 
Installing collected packages: click, userpath, packaging, tomli, argcomplete, platformdirs, pipx
  WARNING: The script userpath is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script pipx is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed argcomplete-3.2.3 click-8.1.7 packaging-24.0 pipx-1.4.3 platformdirs-4.2.0 tomli-2.0.1 userpath-1.9.2
[root@localhost ~]# python3 -m pipx ensurepath
Success! Added /root/.local/bin to the PATH environment variable.

Consider adding shell completions for pipx. Run 'pipx completions' for
instructions.

You will need to open a new terminal or re-login for the PATH changes to take
effect.

Otherwise pipx is ready to go! ✨ 🌟 ✨

一度、端末(Terminal)画面を閉じ、新しく開く。これを行わないと、pipxが認識されない。

[root@localhost ~]# pipx install pkilint
  installed package pkilint 0.9.10, installed using Python 3.9.18
  These apps are now globally available
    - lint_cabf_serverauth_cert
    - lint_cabf_smime_cert
    - lint_crl
    - lint_ocsp_response
    - lint_pkix_cert
    - lint_pkix_signer_signee_cert_chain
done! ✨ 🌟 ✨

インストールが完了すると、バンドルされたコマンドラインアプリケーションとPython APIがマシンで使用できるようになる。

アップグレード

pipx upgrade pkilint

利用方法

S/MIME証明書 検査でERRORなしの場合

[root@localhost ドキュメント]# lint_cabf_smime_cert lint -d smime.cer 
CertificatePolicyQualifierValidator @ certificate.tbsCertificate.extensions.3.extnValue.certificatePolicies.1
    pkix.certificate_policies_policy_has_qualifier (NOTICE)
SubjectKeyIdentifierValidator @ certificate.tbsCertificate.extensions.6.extnValue.subjectKeyIdentifier
    pkix.subject_key_identifier_method_1_identified (INFO)

S/MIME証明書 検査でERRORありの場合

(TLSサーバー証明書を読み込んでErrorを出現)

[root@localhost ドキュメント]# lint_cabf_smime_cert lint -d google.co.jp.crt
CommonNameValidator @ certificate.tbsCertificate.subject.rdnSequence.0.0.value.x520CommonName
    cabf.smime.common_name_value_unknown_source (ERROR): Unknown CN value source: "*.google.co.jp"
AllowedExtendedKeyUsageValidator @ certificate.tbsCertificate.extensions.1.extnValue.extKeyUsageSyntax
    cabf.smime.emailprotection_eku_missing (ERROR)
    cabf.smime.prohibited_eku_present (ERROR): Prohibited EKU(s) present: 1.3.6.1.5.5.7.3.1
SubjectKeyIdentifierValidator @ certificate.tbsCertificate.extensions.3.extnValue.subjectKeyIdentifier
    pkix.subject_key_identifier_method_1_identified (INFO)
SubjectAlternativeNameContainsEmailAddressValidator @ certificate.tbsCertificate.extensions.6.extnValue.subjectAltName
    cabf.smime.san_does_not_contain_email_address (ERROR)
SubjectAlternativeNameProhibitedGeneralNameTypesValidator @ certificate.tbsCertificate.extensions.6.extnValue.subjectAltName
    cabf.smime.prohibited_generalname_type_present (ERROR): Prohibited GeneralName type(s) present: dNSName
GeneralNameDnsNameSyntaxValidator @ certificate.tbsCertificate.extensions.6.extnValue.subjectAltName.0.dNSName
    pkix.invalid_domain_name_syntax (ERROR): Invalid domain name syntax: "*.google.co.jp"
RequiredPolicyIdentifierValidator @ certificate.tbsCertificate.extensions.7.extnValue.certificatePolicies
    cabf.smime.no_required_reserved_policy_oid (ERROR): Required policy OID 2.23.140.1.5.1.3 is missing

TLSサーバー証明書 検査でERRORなしの場合

[root@localhost ドキュメント]# lint_cabf_serverauth_cert lint -d google.co.jp.crt 
DvSubcriberAttributeAllowanceValidator @ certificate.tbsCertificate.subject.rdnSequence
    cabf.serverauth.dv.common_name_attribute_present (WARNING)
SubjectKeyIdentifierValidator @ certificate.tbsCertificate.extensions.3.extnValue.subjectKeyIdentifier
    pkix.subject_key_identifier_method_1_identified (INFO)
SubscriberExtensionAllowanceValidator @ certificate.tbsCertificate.extensions
    cabf.serverauth.subscriber.subject_key_identifier_extension_present (WARNING)

上記検査で使用したTLSサーバー証明書は以下のコマンドでダウンロード。(3階層の証明書ファイルとしてダウンロードされるので、TLSサーバー証明書の部分を抜き出す必要がある)

[root@localhost ドキュメント]# openssl s_client -connect www.google.co.jp:443 -showcerts -servername www.google.co.jp >/root/ドキュメント/www.google.co.jp.cer
depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1
verify return:1
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1
depth=0 CN = *.google.co.jp
verify return:1
read:errno=0

証明書の内容表示。

[root@localhost ドキュメント]# openssl x509 -text -in google.co.jp.crt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            d0:f4:fa:14:49:5d:db:f7:12:fc:1c:75:ba:fa:22:e8
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
        Validity
            Not Before: Feb 19 08:21:08 2024 GMT
            Not After : May 13 08:21:07 2024 GMT
        Subject: CN = *.google.co.jp
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:d4:4a:3b:fa:e1:76:f9:72:37:db:6b:09:17:a2:
                    01:7a:22:a1:21:09:92:5d:4f:92:fa:eb:0e:b8:6e:
                    50:a8:b5:bb:b2:de:22:ce:55:e3:c3:98:e5:dd:55:
                    7a:f8:bc:c6:2f:f3:c0:24:ed:dd:38:88:56:ce:55:
                    c0:c4:65:3e:db
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier: 
                43:C2:96:90:4E:0C:16:71:89:86:D1:C0:55:1C:E4:95:A1:D5:97:76
            X509v3 Authority Key Identifier: 
                keyid:8A:74:7F:AF:85:CD:EE:95:CD:3D:9C:D0:E2:46:14:F3:71:35:1D:27

            Authority Information Access: 
                OCSP - URI:http://ocsp.pki.goog/gts1c3
                CA Issuers - URI:http://pki.goog/repo/certs/gts1c3.der

            X509v3 Subject Alternative Name: 
                DNS:*.google.co.jp, DNS:google.co.jp
            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.2.1
                Policy: 1.3.6.1.4.1.11129.2.5.3

            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crls.pki.goog/gts1c3/QqFxbi9M48c.crl

            CT Precertificate SCTs: 
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 76:FF:88:3F:0A:B6:FB:95:51:C2:61:CC:F5:87:BA:34:
                                B4:A4:CD:BB:29:DC:68:42:0A:9F:E6:67:4C:5A:3A:74
                    Timestamp : Feb 19 09:21:09.417 2024 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:21:00:A4:62:D4:A4:DA:2D:16:2A:55:4E:3B:
                                59:FC:61:68:09:E6:03:0C:90:74:13:FA:FE:7A:13:F4:
                                90:4A:16:31:32:02:20:32:AC:11:8F:69:07:D9:37:DD:
                                B4:2C:25:05:EB:41:37:5A:F4:C3:78:51:96:BF:FD:30:
                                38:1D:31:95:97:36:AC
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : A2:E2:BF:D6:1E:DE:2F:2F:07:A0:D6:4E:6D:37:A7:DC:
                                65:43:B0:C6:B5:2E:A2:DA:B7:8A:F8:9A:6D:F5:17:D8
                    Timestamp : Feb 19 09:21:09.399 2024 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:20:2C:5B:F7:CC:33:E7:18:C4:1D:6A:29:FD:
                                82:91:F5:44:0C:15:76:42:9A:E2:62:68:F3:0D:DB:FB:
                                98:67:26:3B:02:21:00:CC:9F:05:96:54:71:F5:A9:85:
                                24:48:39:91:5F:E4:B8:82:66:20:7D:D0:76:39:55:89:
                                FD:BD:9B:DD:C1:42:DE
    Signature Algorithm: sha256WithRSAEncryption
         d1:60:a7:10:a2:6a:d7:5f:a3:7b:10:54:e3:9b:a6:fa:c4:b7:
         91:0e:1d:46:04:f1:80:53:16:00:c4:41:82:c8:ba:37:cf:5b:
         9b:c0:94:15:88:ae:fc:1e:4b:0a:10:95:f2:a5:14:4a:5b:c8:
         37:9e:6d:96:b0:16:7f:02:cf:3f:23:91:0a:2f:03:3b:a8:4c:
         66:03:84:f5:e2:6b:26:38:68:01:97:5c:b6:ff:99:9c:8c:89:
         04:e2:f9:1e:71:9b:c6:e7:28:31:ba:f3:2f:40:70:b3:37:a5:
         1f:f1:c6:26:a6:a3:a5:7b:43:b8:a4:d5:8b:af:59:be:b9:b8:
         60:a2:93:0d:0e:de:4e:84:c6:49:68:32:8c:10:4e:c7:97:89:
         2a:5d:ef:67:a2:a9:0d:0f:98:6f:ba:58:53:cb:28:f0:85:c3:
         d4:cd:04:94:7a:cb:e2:ca:94:ce:ba:df:36:e3:b9:e2:0d:e5:
         e5:7b:e1:65:bd:15:e2:d4:f9:7b:b3:12:3d:dc:5e:74:16:86:
         0b:0b:4c:a7:e1:78:82:97:d5:bb:91:55:90:09:2c:ca:7e:62:
         7d:28:77:d4:cc:60:a0:c0:6a:e3:d7:ae:28:1e:6c:78:c5:c9:
         7b:d0:50:2a:32:0f:08:53:50:d9:5f:73:64:c4:62:86:82:36:
         ea:10:4b:67
-----BEGIN CERTIFICATE-----
MIIEljCCA36gAwIBAgIRAND0+hRJXdv3Evwcdbr6IugwDQYJKoZIhvcNAQELBQAw
RjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM
TEMxEzARBgNVBAMTCkdUUyBDQSAxQzMwHhcNMjQwMjE5MDgyMTA4WhcNMjQwNTEz
MDgyMTA3WjAZMRcwFQYDVQQDDA4qLmdvb2dsZS5jby5qcDBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABNRKO/rhdvlyN9trCReiAXoioSEJkl1PkvrrDrhuUKi1u7Le
Is5V48OY5d1Vevi8xi/zwCTt3TiIVs5VwMRlPtujggJ1MIICcTAOBgNVHQ8BAf8E
BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
FgQUQ8KWkE4MFnGJhtHAVRzklaHVl3YwHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ
4kYU83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz
cC5wa2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9y
ZXBvL2NlcnRzL2d0czFjMy5kZXIwJwYDVR0RBCAwHoIOKi5nb29nbGUuY28uanCC
DGdvb2dsZS5jby5qcDAhBgNVHSAEGjAYMAgGBmeBDAECATAMBgorBgEEAdZ5AgUD
MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmxzLnBraS5nb29nL2d0czFjMy9R
cUZ4Ymk5TTQ4Yy5jcmwwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgB2/4g/Crb7
lVHCYcz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAY3Aq1EpAAAEAwBHMEUCIQCkYtSk
2i0WKlVOO1n8YWgJ5gMMkHQT+v56E/SQShYxMgIgMqwRj2kH2TfdtCwlBetBN1r0
w3hRlr/9MDgdMZWXNqwAdgCi4r/WHt4vLweg1k5tN6fcZUOwxrUuotq3iviabfUX
2AAAAY3Aq1EXAAAEAwBHMEUCICxb98wz5xjEHWop/YKR9UQMFXZCmuJiaPMN2/uY
ZyY7AiEAzJ8FllRx9amFJEg5kV/kuIJmIH3QdjlVif29m93BQt4wDQYJKoZIhvcN
AQELBQADggEBANFgpxCiatdfo3sQVOObpvrEt5EOHUYE8YBTFgDEQYLIujfPW5vA
lBWIrvweSwoQlfKlFEpbyDeebZawFn8Czz8jkQovAzuoTGYDhPXiayY4aAGXXLb/
mZyMiQTi+R5xm8bnKDG68y9AcLM3pR/xxiamo6V7Q7ik1YuvWb65uGCikw0O3k6E
xkloMowQTseXiSpd72eiqQ0PmG+6WFPLKPCFw9TNBJR6y+LKlM663zbjueIN5eV7
4WW9FeLU+XuzEj3cXnQWhgsLTKfheIKX1buRVZAJLMp+Yn0od9TMYKDAauPXrige
bHjFyXvQUCoyDwhTUNlfc2TEYoaCNuoQS2c=
-----END CERTIFICATE-----

TLSサーバー証明書 検査でERRORありの場合

(S/MIME証明書を読み込んでErrorを出現)

[root@localhost ドキュメント]# lint_cabf_serverauth_cert lint -d smime.cer 
SubscriberValidityPeriodValidator @ certificate.tbsCertificate.validity.notBefore
    cabf.certificate_validity_period_exceeds_398_days (ERROR): Validity period of 761 days, 0:00:01 exceeds maximum value of 398 days, 0:00:00
DvSubcriberAttributeAllowanceValidator @ certificate.tbsCertificate.subject.rdnSequence
    cabf.serverauth.dv.common_name_attribute_present (WARNING)
SubscriberCommonNameValidator @ certificate.tbsCertificate.subject.rdnSequence.0.0.value.x520CommonName
    cabf.serverauth.subscriber_common_name_unknown_source (ERROR): Unknown source for value of common name: "xxxx@xxxxx.co.jp"
SubscriberSanGeneralNameTypeValidator @ certificate.tbsCertificate.extensions.2.extnValue.subjectAltName.0
    cabf.serverauth.prohibited_san_type (ERROR): Prohibited SAN GeneralName type: rfc822Name
SubscriberPoliciesValidator @ certificate.tbsCertificate.extensions.3.extnValue.certificatePolicies
    cabf.serverauth.subscriber_missing_reserved_policy_oid (ERROR): Required policy OID "2.23.140.1.2.1" missing
CertificatePolicyQualifierValidator @ certificate.tbsCertificate.extensions.3.extnValue.certificatePolicies.1.policyQualifiers.0
    cabf.serverauth.certificate_policy_qualifier_present (WARNING)
SubscriberEkuAllowanceValidator @ certificate.tbsCertificate.extensions.4.extnValue.extKeyUsageSyntax
    cabf.serverauth.subscriber.emailprotection_eku_present (ERROR)
    cabf.serverauth.subscriber.serverauth_eku_absent (ERROR)
SubjectKeyIdentifierValidator @ certificate.tbsCertificate.extensions.6.extnValue.subjectKeyIdentifier
    pkix.subject_key_identifier_method_1_identified (INFO)
SubscriberKeyUsageValidator @ certificate.tbsCertificate.extensions.7.extnValue.keyUsage
    cabf.serverauth.subscriber_rsa_digitalsignature_and_keyencipherment_present (WARNING)
SubscriberExtensionAllowanceValidator @ certificate.tbsCertificate.extensions
    cabf.serverauth.subscriber.subject_key_identifier_extension_present (WARNING)

CRL 検査でERRORなしの場合

(DER形式でも、PEM形式でも検査可能)

[root@localhost ドキュメント]# lint_crl lint -t CRL -p BR -s ALL -f TEXT google-pem.crl

crt.sh IDから検査

TLSサーバー証明書証明書

crt.sh IDを指定してpkilintを実行できる。

curl -s [https://crt.sh/?d=crt.sh ID] | lint_cabf_serverauth_cert lint -d - -s ERROR
(Example)
curl -s https://crt.sh/?d=12428602531 | lint_cabf_serverauth_cert lint -d - -s ERROR
(Example)
curl -s https://crt.sh/?d=12428602531 | lint_cabf_serverauth_cert lint -d - -s INFO

help画面

S/MIME証明書

[root@localhost ドキュメント]# lint_cabf_smime_cert lint -h
usage: lint_cabf_smime_cert lint [-h]
                                 (-d | -g | -t {MAILBOX-LEGACY,ORGANIZATION-LEGACY,SPONSORED-LEGACY,INDIVIDUAL-LEGACY,MAILBOX-MULTIPURPOSE,ORGANIZATION-MULTIPURPOSE,SPONSORED-MULTIPURPOSE,INDIVIDUAL-MULTIPURPOSE,MAILBOX-STRICT,ORGANIZATION-STRICT,SPONSORED-STRICT,INDIVIDUAL-STRICT})
                                 [-m MAPPING] [-o] [-s {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}] [-f {TEXT,CSV,JSON}]
                                 file

positional arguments:
  file                  The certificate to lint

optional arguments:
  -h, --help            show this help message and exit
  -d, --detect          Detect the type of S/MIME certificate from reserved CA/B Forum policy OID. If the type cannot be detected,
                        then refuse to lint the certificate.
  -g, --guess           Detect the type of S/MIME certificate from reserved CA/B Forum policy OID. If the type cannot be detected,
                        then use heuristics to determine the type of S/MIME certificate.
  -t {MAILBOX-LEGACY,ORGANIZATION-LEGACY,SPONSORED-LEGACY,INDIVIDUAL-LEGACY,MAILBOX-MULTIPURPOSE,ORGANIZATION-MULTIPURPOSE,SPONSORED-MULTIPURPOSE,INDIVIDUAL-MULTIPURPOSE,MAILBOX-STRICT,ORGANIZATION-STRICT,SPONSORED-STRICT,INDIVIDUAL-STRICT}, --type {MAILBOX-LEGACY,ORGANIZATION-LEGACY,SPONSORED-LEGACY,INDIVIDUAL-LEGACY,MAILBOX-MULTIPURPOSE,ORGANIZATION-MULTIPURPOSE,SPONSORED-MULTIPURPOSE,INDIVIDUAL-MULTIPURPOSE,MAILBOX-STRICT,ORGANIZATION-STRICT,SPONSORED-STRICT,INDIVIDUAL-STRICT}
                        The type (validation level and generation) of S/MIME certificate
  -m MAPPING, --mapping MAPPING
                        Mapping file which contains OID to validation level and generation mappings. Each line of the mapping file
                        starts with a policy OID followed by a non-numeric character and the certificate type to which the OID maps
                        (see -t/--type option for possible values)
  -o, --output          Output the type of S/MIME certificate to standard error. This option may be useful when using the --detect,
                        --guess, or --mapping options.
  -s {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}, --severity {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}
                        The finding severity threshold; findings with a lesser severity will not be reported.
  -f {TEXT,CSV,JSON}, --format {TEXT,CSV,JSON}
                        The format in which results will be output.

TLSサーバー証明書

[root@localhost ~]# lint_cabf_serverauth_cert lint -s -h?
usage: lint_cabf_serverauth_cert lint [-h]
                                      (-d | -t {ROOT-CA,INTERNAL-CROSS-CA,EXTERNAL-CROSS-CA,NON-TLS-CA,PRECERT-SIGNING-CA,INTERNAL-UNCONSTRAINED-TLS-CA,INTERNAL-CONSTRAINED-TLS-CA,EXTERNAL-UNCONSTRAINED-TLS-CA,EXTERNAL-UNCONSTRAINED-EV-TLS-CA,EXTERNAL-CONSTRAINED-TLS-CA,EXTERNAL-CONSTRAINED-EV-TLS-CA,DV-FINAL-CERTIFICATE,IV-FINAL-CERTIFICATE,OV-FINAL-CERTIFICATE,EV-FINAL-CERTIFICATE,OCSP-RESPONDER,DV-PRE-CERTIFICATE,IV-PRE-CERTIFICATE,OV-PRE-CERTIFICATE,EV-PRE-CERTIFICATE})
                                      [-o] [-r]
                                      [-s {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}]
                                      [-f {TEXT,CSV,JSON}]
                                      file
lint_cabf_serverauth_cert lint: error: argument -s/--severity: expected one argument

CRL

[root@localhost ドキュメント]# lint_crl lint -h
usage: lint_crl lint [-h] -t {CRL,ARL} -p {PKIX,BR} [-s {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}] [-f {TEXT,CSV,JSON}] file

positional arguments:
  file                  The CRL file to lint

optional arguments:
  -h, --help            show this help message and exit
  -t {CRL,ARL}, --type {CRL,ARL}
                        The type of CRL (whether the CRL in question is a CRL or an ARL)
  -p {PKIX,BR}, --profile {PKIX,BR}
                        The profile against which to lint
  -s {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}, --severity {FATAL,ERROR,WARNING,NOTICE,INFO,DEBUG,ALL}
                        The finding severity threshold; findings with a lesser severity will not be reported.
  -f {TEXT,CSV,JSON}, --format {TEXT,CSV,JSON}
                        The format in which results will be output.

Scriptファイルの作成例

指定フォルダー内にある証明書について全件検査する方法。

S/MIME証明書(smime.sh)

審査対象ファイルを入れるフォルダー:/root/ドキュメント/smime

#!/bin/bash
folder_path=/root/ドキュメント/smime
output_file="PKILINT_SMIME_"

start_date=$(date +'%Y%m%d-%H%M%S')
output_file+=$start_date
output_file+=".txt"
> $output_file
echo "START $start_date"
echo "START $start_date" >> $output_file

i_count=0
i_error=0
i_ok=0

for file in "$folder_path"/*; do
	((i_count++))
	if [ -f "$file" ]; then
		program_output=$(lint_cabf_smime_cert lint -d "$file")
		if [[ "$program_output" == *"ERROR"* ]]; then
			echo "ERROR " "(" "$i_count" ")" "$file" 
			echo "ERROR " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		elif [[ "$program_output" == *"FATAL"* ]]; then
			echo "FATAL " "(" "$i_count" ")" "$file" 
			echo "FATAL " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		elif [[ "$program_output" == "" ]]; then
			echo "NO OUTPUT " "(" "$i_count" ")" "$file" 
			echo "NO OUTPUT " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		else
			echo "OK " "(" "$i_count" ")" "$file"
			#To display output, remove the # below
			#echo "OK " "(" "$i_count" ")" "$file" >> $output_file
			#echo $program_output
			#echo $program_output >> $output_file
			((i_ok++))
		fi
   	fi
done
echo "All:$i_count"
echo "All:$i_count" >> $output_file
echo "OK:$i_ok"
echo "OK:$i_ok" >> $output_file
echo "ERROR:$i_error"
echo "ERROR:$i_error" >> $output_file
end_date=$(date +'%Y%m%d-%H%M%S')
echo "END $end_date"
echo "END $end_date" >> $output_file
echo "$output_file"

TLSサーバー証明書(serverauth.sh)

審査対象ファイルを入れるフォルダー:/root/ドキュメント/serverauth

#!/bin/bash
folder_path=/root/ドキュメント/serverauth
output_file="PKILINT_SERVERAUTH_"

start_date=$(date +'%Y%m%d-%H%M%S')
output_file+=$start_date
output_file+=".txt"
> $output_file
echo "START $start_date"
echo "START $start_date" >> $output_file

i_count=0
i_error=0
i_ok=0

for file in "$folder_path"/*; do
	((i_count++))
	if [ -f "$file" ]; then
		program_output=$(lint_cabf_serverauth_cert lint -d "$file")
		if [[ "$program_output" == *"ERROR"* ]]; then
			echo "ERROR " "(" "$i_count" ")" "$file" 
			echo "ERROR " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		elif [[ "$program_output" == *"FATAL"* ]]; then
			echo "FATAL " "(" "$i_count" ")" "$file" 
			echo "FATAL " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		elif [[ "$program_output" == "" ]]; then
			echo "NO OUTPUT " "(" "$i_count" ")" "$file" 
			echo "NO OUTPUT " "(" "$i_count" ")" "$file" >> $output_file
			echo $program_output >> $output_file
			((i_error++))
		else
			echo "OK " "(" "$i_count" ")" "$file"
			#To display output, remove the # below
			#echo "OK " "(" "$i_count" ")" "$file" >> $output_file
			#echo $program_output
			#echo $program_output >> $output_file
			((i_ok++))
		fi
   	fi
done
echo "All:$i_count"
echo "All:$i_count" >> $output_file
echo "OK:$i_ok"
echo "OK:$i_ok" >> $output_file
echo "ERROR:$i_error"
echo "ERROR:$i_error" >> $output_file
end_date=$(date +'%Y%m%d-%H%M%S')
echo "END $end_date"
echo "END $end_date" >> $output_file
echo "$output_file"

1ファイルにPEMファイルが複数行記載されている場合の分割方法

「input.txt」のサンプル

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

「devide.sh」の記載内容

#!/usr/bin/env python3
import os

#Delete All Files
def delete_all_files_in_folder(folder_path):
    for filename in os.listdir(folder_path):
        file_path = os.path.join(folder_path, filename)
        if os.path.isfile(file_path):
            os.remove(file_path)
            print(f"Delete file: {file_path}")

#Make PEM File(one line)
def split_file_by_lines_for_loop(input_file, output_path_name):
    with open(input_file, 'r') as file:
        lines = file.readlines()
    for i, line in enumerate(lines):
        output_file = f"{output_path_name}/output_{str(i+1).zfill(8)}.cer"
        with open(output_file, 'w') as output:
            output.write(line)
        print(f"Make file'{output_file}'")

#Make PEM File(Line break after 64 characters)
def process_all_files_in_folder(folder_path):
	file_list = os.listdir(folder_path)
	i_count=0
	for filename in file_list:
		input_file = os.path.join(folder_path, filename)
		if os.path.isfile(input_file):
			#Display read and write files
			print(f"r: {input_file}")
			output_file = output_path + filename
			print(f"w: {output_file}")		

			with open(input_file, 'r') as infile:
				content1 = infile.read()
			#Line break every 64 characters
			lines = [content1[i:i+64] for i in range(0, len(content1), 64)]
			with open(output_file, 'w') as outfile:
				for line in lines:
					outfile.write(line + '\n')
			
			#Add END to the end
			def append_to_file(output_file, content3):
				with open(output_file, 'a') as file:
					file.write(content3 + '\n')
			content_to_append = '-----END CERTIFICATE-----'
			append_to_file(output_file, content_to_append)

			#Add BEGIN first
			def prepend_to_file(output_file, content2):
				with open(output_file, 'r+') as file:
					original_content2 = file.read()
					 #Move to beginning of file
					file.seek(0, 0) 
					file.write(content2 + '\n' + original_content2)
			content2_to_prepend = '-----BEGIN CERTIFICATE-----'
			prepend_to_file(output_file, content2_to_prepend)

			#Deleting a line with just a newline
			def remove_empty_lines_isspace(file_name):
				with open(file_name, 'r') as file:
					lines = file.readlines()
				lines = [line for line in lines if not line.isspace()]
				with open(file_name, 'w') as file:
					file.writelines(lines)
			remove_empty_lines_isspace(output_file)

#Run the program
input_multi_file_name = 'input.txt'
input_path = '/root/ドキュメント/output1/'
input_path_name = 'output1'
output_path = '/root/ドキュメント/output2/'

delete_all_files_in_folder(input_path)
delete_all_files_in_folder(output_path)
split_file_by_lines_for_loop(input_multi_file_name, input_path_name)
process_all_files_in_folder(input_path)

タイトルとURLをコピーしました