openssl コマンドで証明書チェーンをまとめて確認する方法

## TL;DR

以下のコマンドで、証明書チェーンをまとめて確認することが可能です。

```
$ openssl crl2pkcs7 -nocrl -certfile <証明書チェーン> \
    | openssl pkcs7 -print_certs -text -noout
```

## 解説

`openssl crl2pkcs7` コマンドで X.509 形式の証明書チェーンを単一の PKCS #7 形式の証明書に変換して、それを `openssl pkcs7` コマンドで確認するといった方法です。コマンド名を見ると CRL が必要そうな雰囲気ですが、CRL を渡すかは Optional なので気にしなくて良いです。

## 実行例

以下の証明書チェーンが手元に存在しているとします。

```
$ cat cert-chain.pem   
-----BEGIN CERTIFICATE-----
MIIDgzCCAmugAwIBAgIUHUGJWVBS2JfjAHySNAM17H34jCgwDQYJKoZIhvcNAQEL
BQAwMzELMAkGA1UEBhMCSlAxDjAMBgNVBAcTBVRva3lvMRQwEgYDVQQDEwtEZXYg
Um9vdCBDQTAeFw0yMjA5MjgwNTM2MDBaFw0yMzA5MjgwNTM2MDBaMDsxCzAJBgNV
BAYTAkpQMQ4wDAYDVQQHEwVUb2t5bzEcMBoGA1UEAxMTRGV2IEludGVybWVkaWF0
ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALbKxTUvvLaBUzZt
SdVnRA91yKZw9IsnOyVEqjbLpnybkzguv0oukZ2SzZzjHiOTAFn9FdPoZmMVDGAX
DJQ6gTDG3ojSKjUtpgtUVNh+PF5111w+RlrZZPowYx31KaqzgOx5dHfTPj6GLoaT
tbqSBx3i12ip2JN6Ky+oJiiYREfuFR05HXuQ1qOJ2UvZR3arbLx3sdq6cfjDc3Pw
8TwZap51T23mk3f4Zs92mqBDmTLFxV9JfmTOmDyC+34fwVrw1EsC3jayaIq2+EeH
l5AXeaiL8xBuRLFA5f9YHOYvRT5ZGOQowg64i8myInO0Fsid/dx/e/qZj7GPLa1J
8XdFWVUCAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFP35
AweOatmWKOi0e9rhvwJyXgWVMB8GA1UdIwQYMBaAFIL6tvfJPxbk5JGCFyy9rObT
4CRmMA0GCSqGSIb3DQEBCwUAA4IBAQB2z/tY1RPOCuuMufiqf5cPhnb1viGEyfMQ
dUTUte8+UGc3Bi5nC88zBYC6LkbkjLkE4Qx0MW335GeIbTi/qhoNsnkfI5wfpa93
RoyM7diyBrZha24n7iJZ/gJ8tGOP5W/O4yvlzNtBs+uJE1Px2r/J8VPz67R5G/J9
1jved5vY5zGARiLhO/WLpFe/EBj1LLGD79cBTqERwQt/SXQ54ljKeVagjEdovzhp
Wif0PFK0YoTTRUbOBjkDql9CBDpXrOgw5Be5ZRfn4kFclK2hKTAFWQVa137pkBF4
QE02Pzz4msKyn3GG+QK9YYNmd7oP/nwVAXqPA6xkHqva1rGVWj/I
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDijCCAnKgAwIBAgIUBcmwSlj3dqApyN61cVAa54NRvLAwDQYJKoZIhvcNAQEL
BQAwOzELMAkGA1UEBhMCSlAxDjAMBgNVBAcTBVRva3lvMRwwGgYDVQQDExNEZXYg
SW50ZXJtZWRpYXRlIENBMB4XDTIyMDkyODA1NDAwMFoXDTIzMDkyODA1NDAwMFow
MjELMAkGA1UEBhMCSlAxDjAMBgNVBAcTBVRva3lvMRMwEQYDVQQDEwpEZXYgU2Vy
dmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp5IJlFlrWRx1g+vt
I+CoLSF+BZVOXEyWaxqzeBgFAoqHIXwC+S53EW7e4plppESBUqKKjlR+MMC6sjXE
P0z/x1z5JExIZ7ldzc1rqAv31uD2mElp3upYZbvmhb9beoeG3dW+6tUlGhUKcgce
bAPR8czFwZCRBtsyiFCfICguPDnaqbMQFJI18TfxJ4cZuv9E8y8h/y32sqFpDfpD
Jn7NKjJzhk4NX8lcSyXRw4FfnyVh8XiU5Vfcoqa4Vh9SB2Hyrw8RZ8LmTezwC3Ab
zWYf3SHM/D867UsTMm9kvzk3Lh9QBRD4iKIyFFzvM13uqDQCXSqYQg8Lc52fp4ns
z5JyJwIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEF
BQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRq9b+Rk3/+LYu1oGxgwuXyg1SC
WzAfBgNVHSMEGDAWgBT9+QMHjmrZlijotHva4b8Ccl4FlTAWBgNVHREEDzANggtl
eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAsRLxfdzxcOwNCzQFjLzflybO
kLTJ6EbUOcV4lRRIryD2iTZDOEC1e7TzJyt2ykzbnKrMPgXv44I2L53jbomyVBov
hfz4GZhk9ts819WxFkqTjmcQU5r4fR/w9SbBrqD4mSdgzYfXxXHuoxCWQfqh6rsX
Ga4G9ckF43abQD/mlLgEpDQBwvXpIngojMHyZD2IOFhdRhQEvYtOgUj4CQB+zwe8
3ymSSpKaN3phaA2F9RpgVq9FwcSPQkfz7+mBFd3c6W8NvzBRPfZnk+GVLY+HKL7S
byNSNdbYk7OMFPmBvlyO0QOPlbarsifBZii3P/Yp1ZtOjL28REHqlHKyHkXsgQ==
-----END CERTIFICATE-----
```

使用する `openssl` コマンドのバージョンは以下です。

```
$ openssl version                                  
LibreSSL 2.8.3
```

`openssl x509` コマンドでは、1つ目の証明書を確認することしかできません。

```
$  openssl x509 -text -noout -in cert-chain.pem 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            1d:41:89:59:50:52:d8:97:e3:00:7c:92:34:03:35:ec:7d:f8:8c:28
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, L=Tokyo, CN=Dev Root CA
        Validity
            Not Before: Sep 28 05:36:00 2022 GMT
            Not After : Sep 28 05:36:00 2023 GMT
        Subject: C=JP, L=Tokyo, CN=Dev Intermediate CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    (略)
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Subject Key Identifier: 
                FD:F9:03:07:8E:6A:D9:96:28:E8:B4:7B:DA:E1:BF:02:72:5E:05:95
            X509v3 Authority Key Identifier: 
                keyid:82:FA:B6:F7:C9:3F:16:E4:E4:91:82:17:2C:BD:AC:E6:D3:E0:24:66

    Signature Algorithm: sha256WithRSAEncryption
         (略)
```

しかし、先述のコマンドを使用することで証明書チェーンをまとめて確認することができます。

```
$ openssl crl2pkcs7 -nocrl -certfile cert-chain.pem \  
    | openssl pkcs7 -print_certs -text -noout

# 1つ目の証明書 (中間CA)
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            1d:41:89:59:50:52:d8:97:e3:00:7c:92:34:03:35:ec:7d:f8:8c:28
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, L=Tokyo, CN=Dev Root CA
        Validity
            Not Before: Sep 28 05:36:00 2022 GMT
            Not After : Sep 28 05:36:00 2023 GMT
        Subject: C=JP, L=Tokyo, CN=Dev Intermediate CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    (略)
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Subject Key Identifier: 
                FD:F9:03:07:8E:6A:D9:96:28:E8:B4:7B:DA:E1:BF:02:72:5E:05:95
            X509v3 Authority Key Identifier: 
                keyid:82:FA:B6:F7:C9:3F:16:E4:E4:91:82:17:2C:BD:AC:E6:D3:E0:24:66

    Signature Algorithm: sha256WithRSAEncryption
         (略)

# 2つ目の証明書 (サーバー証明書)
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            05:c9:b0:4a:58:f7:76:a0:29:c8:de:b5:71:50:1a:e7:83:51:bc:b0
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, L=Tokyo, CN=Dev Intermediate CA
        Validity
            Not Before: Sep 28 05:40:00 2022 GMT
            Not After : Sep 28 05:40:00 2023 GMT
        Subject: C=JP, L=Tokyo, CN=Dev Server
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    (略)
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier: 
                6A:F5:BF:91:93:7F:FE:2D:8B:B5:A0:6C:60:C2:E5:F2:83:54:82:5B
            X509v3 Authority Key Identifier: 
                keyid:FD:F9:03:07:8E:6A:D9:96:28:E8:B4:7B:DA:E1:BF:02:72:5E:05:95

            X509v3 Subject Alternative Name: 
                DNS:example.com
    Signature Algorithm: sha256WithRSAEncryption
         (略)
```

<details>
<summary>cfssl コマンドを使用した証明書チェーンの作成方法はこちら</summary>

[How to use cfssl to create self signed certificates](https://rob-blackbourn.medium.com/how-to-use-cfssl-to-create-self-signed-certificates-d55f76ba5781) を参考にしています。

### ルートCA作成

CSR 生成に必要な設定ファイルを作成する。

```bash
$ cat << EOF > root-ca-csr.json
{
  "CN": "Dev Root CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo"
    }
  ]
}
EOF
```

ルート CA を作成する。

```bash
$ cfssl gencert -initca root-ca-csr.json | cfssljson -bare root-ca
2022/09/28 14:35:26 [INFO] generating a new CA key and certificate from CSR
2022/09/28 14:35:26 [INFO] generate received request
2022/09/28 14:35:26 [INFO] received CSR
2022/09/28 14:35:26 [INFO] generating key: rsa-2048
2022/09/28 14:35:26 [INFO] encoded CSR
2022/09/28 14:35:26 [INFO] signed certificate with serial number 178649506250605055309701706963610210911826641790
```

### 中間CA作成

cfssl の設定ファイルを作成する。

```bash
$ cat << EOF > cfssl-config.json
{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "intermediate_ca": {
        "usages": [
            "signing",
            "digital signature",
            "key encipherment",
            "cert sign",
            "crl sign",
            "server auth",
            "client auth"
        ],
        "expiry": "8760h",
        "ca_constraint": {
            "is_ca": true,
            "max_path_len": 0,
            "max_path_len_zero": true
        }
      },
      "server": {
        "usages": [
          "signing",
          "digital signing",
          "key encipherment",
          "server auth"
        ],
        "expiry": "8760h"
      }
    }
  }
}
EOF
```

CSR 生成に必要な設定ファイルを作成する。

```bash
$ cat << EOF > intermediate-ca-csr.json
{
  "CN": "Dev Intermediate CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo"
    }
  ]
}
EOF
```

中間 CA を作成する。

```bash
$ cfssl gencert -initca intermediate-ca-csr.json | cfssljson -bare intermediate-ca
2022/09/28 14:38:53 [INFO] generating a new CA key and certificate from CSR
2022/09/28 14:38:53 [INFO] generate received request
2022/09/28 14:38:53 [INFO] received CSR
2022/09/28 14:38:53 [INFO] generating key: rsa-2048
2022/09/28 14:38:53 [INFO] encoded CSR
2022/09/28 14:38:53 [INFO] signed certificate with serial number 561176120556366469504048877619888407539553812892
```

ルート CA で、中間 CA に署名する。

```
$ cfssl sign -ca root-ca.pem -ca-key root-ca-key.pem -config cfssl-config.json -profile intermediate_ca intermediate-ca.csr \
    | cfssljson -bare intermediate-ca
2022/09/28 14:40:48 [INFO] signed certificate with serial number 167022245566867544863648569470867842276078947368
```

### サーバー証明書作成

CSR 生成に必要な設定ファイルを作成する。

```bash
$ cat << EOF > server-cert-csr.json
{
  "CN": "Dev Server",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo"
    }
  ],
  "hosts": [
    "example.com"
  ]
}
EOF
```

中間 CA を使用して、サーバー証明書を作成する。

```bash
$ cfssl gencert -ca intermediate-ca.pem -ca-key intermediate-ca-key.pem -config cfssl-config.json -profile=server server-cert-csr.json \
    | cfssljson -bare server
2022/09/28 14:44:30 [INFO] generate received request
2022/09/28 14:44:30 [INFO] received CSR
2022/09/28 14:44:30 [INFO] generating key: rsa-2048
2022/09/28 14:44:31 [INFO] encoded CSR
2022/09/28 14:44:31 [INFO] signed certificate with serial number 33042760700499961792372155555994717491800685744
```

### 証明書チェーンを作成する。

中間 CA とサーバー証明書を連結して、証明書チェーンを作成する。

```
$ cat intermediate-ca.pem server.pem > cert-chain.pem
```

ルート CA を使用して、証明書チェーンを検証できることを確認する。

```
$ openssl verify -CAfile root-ca.pem cert-chain.pem
cert-chain.pem: OK
```

以上の手順で証明書チェーンが作成できます。

</details>

## 参考資料

- https://serverfault.com/questions/590870/how-to-view-all-ssl-certificates-in-a-bundle