SSL – Verify Certificate Revocation List Against Multiple Paths

crlopensslsslssl-certificate

In a recent question, I outlined the steps for verifying a wildcard SSL certificate for connecting to PostgreSQL from a remote client (using the same wildcard certificate I use for my web server). Although I resolved that problem, one lingering thing I haven't yet figured out is how to confirm I have the correct CRL(s) for my certificate.

My certificate has two Certification Paths (screenshot from SSLLabs test):

Multiple trusted certificate paths

However, the CA only included the CRL for one of these paths (Path #2) with their issued certificate. I believe I have identified the correct CRL for the second path, but I'm not sure how to check it against my SSL certificate to confirm that it is correct. I can visually confirm that the CN matches, but there must be some OpenSSL command to validate the CRL against the corresponding certificate. I've come to the conclusion that I can't use the CRL fingerprints for this, since they change with each version of the CRL.

Question:

How can I validate each individual CRL against its specific trusted path via OpenSSL (either separately or in bundles)?

Can these two CRLs be bundled in the same way that certificates can be bundled (i.e., by simply appending PEM files)?

Essentially, I'm looking for a definitive way to test that "yes, this CRL (bundle?) contains the correct CRL for this certificate". With certificates and private keys, I can test the modulo, but would that be strong enough for a root certificate/CRL?

Here are the specific root certificates and CRLs I am working with (same as in above image).


Path #1 Root

Root certificate for Path #1 (USERTrust RSA Certification Authority):

# openssl x509 -fingerprint -noout -in USERTrustRSACertificationAuthority.crt
SHA1 Fingerprint=2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E

This is what I presume to be the correct CRL for above root certificate:

Download CRL from CA:

# wget http://crl.usertrust.com/USERTrustRSACertificationAuthority.crl

Convert DER to PEM:

# openssl crl -inform DER -in USERTrustRSACertificationAuthority.crl -outform PEM -out USERTrustRSACertificationAuthority.pem

Get the fingerprint of the CRL:

# openssl crl -fingerprint -noout -in USERTrustRSACertificationAuthority.pem
SHA1 Fingerprint=BA:32:A2:48:F9:72:C9:01:44:17:B0:EE:6D:7F:AB:29:50:6F:A2:D4

Print the text version of the CRL:

# openssl crl -in USERTrustRSACertificationAuthority.pem -text
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha384WithRSAEncryption
        Issuer: /C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
        Last Update: Aug 18 13:58:25 2019 GMT
        Next Update: Aug 22 13:58:25 2019 GMT
        CRL extensions:
            X509v3 Authority Key Identifier:
                keyid:53:79:BF:5A:AA:2B:4A:CF:54:80:E1:D8:9B:C0:9D:F2:B2:03:66:CB

            X509v3 CRL Number:
                3628
Revoked Certificates:
    Serial Number: D8C857CAE4BE66F913759FDDA3D5DB2B
        Revocation Date: Mar 16 12:21:54 2018 GMT
    Serial Number: A6DC2ED38830CC033D23ABCEB72564BF
        Revocation Date: Mar 16 12:21:54 2018 GMT
    Serial Number: 3291B976375B708A08E5322427BBC434
        Revocation Date: Mar 16 12:21:54 2018 GMT
    Signature Algorithm: sha384WithRSAEncryption
         65:73:d1:c2:b2:21:83:6b:10:9c:0d:83:e7:07:32:7a:8b:25:
         bf:1c:84:03:7b:f5:8f:c1:3b:4e:3f:b3:0c:c9:61:1d:be:4c:
         92:5e:cd:fe:56:07:0b:ff:52:38:f1:1b:0e:ad:40:a7:d8:28:
         59:76:c2:e7:24:77:29:71:e5:53:4c:2f:c3:65:ce:b3:49:9c:
         45:d3:4a:0a:a5:75:00:1f:65:85:9c:16:e2:d7:38:6f:ea:bf:
         d3:58:ef:7e:cb:10:7a:c8:9b:bb:e4:69:e6:35:b4:31:88:19:
         29:dc:2b:87:95:4f:9e:17:0a:f5:16:b7:70:1f:2a:7c:d0:ed:
         fd:00:a7:11:0c:68:e0:4f:f7:a0:d8:13:34:43:7f:09:e8:21:
         2a:9f:34:cc:ab:10:49:ba:ff:21:b9:97:57:25:c9:28:21:66:
         1e:e0:23:45:35:20:c6:8f:a8:93:b5:40:7f:e5:c3:73:ce:2a:
         d1:52:0c:9f:36:53:f7:e6:9b:03:18:94:56:9e:7b:34:20:ba:
         98:b9:fa:85:d9:95:7a:46:8e:d1:f1:b5:56:be:4c:30:be:4e:
         2d:28:37:a3:60:5b:91:b8:c5:38:30:94:3a:7f:fa:0b:bb:f0:
         af:fd:e8:67:78:55:42:11:32:71:57:0e:b3:66:17:83:52:76:
         d7:00:4a:24:87:a0:82:8e:7f:0e:21:64:a8:48:65:82:74:11:
         15:fa:99:6d:c7:5b:cf:5f:09:0b:2b:5a:a4:71:51:af:99:04:
         1e:49:14:01:fe:70:0d:a0:ec:2a:4e:c4:f5:3a:d6:bc:80:7d:
         6c:9c:53:c4:25:32:c8:8a:6f:b7:5a:61:7f:4c:a1:b2:95:c9:
         57:67:8f:45:81:d2:3d:b9:9e:86:91:61:03:2a:51:16:50:3b:
         d4:21:83:89:98:0f:93:4d:00:82:78:67:62:70:8d:c0:e9:3b:
         77:4b:b7:4d:52:1f:f7:cd:04:5e:e4:02:c2:89:7b:64:79:69:
         da:f4:57:3d:36:0d:9e:b4:fc:fc:71:cb:6d:dc:0d:1e:cc:f9:
         d9:5a:5e:36:e3:5c:56:8a:a2:70:75:c2:b4:70:8b:9f:b0:86:
         04:42:a5:35:5b:47:a4:df:e0:94:3a:5a:32:e6:9c:1f:02:10:
         d4:14:88:de:d2:46:fc:bb:b6:1c:71:90:88:6f:07:cb:5c:be:
         5c:e1:52:42:d6:af:e6:3a:7c:c0:10:6c:94:5b:2f:1c:cd:5a:
         a0:c1:de:8d:79:4c:54:9d:a6:60:21:b1:39:0d:bc:98:c9:54:
         ac:54:55:9b:05:44:c4:af:94:f4:2d:b3:cb:8f:31:d4:bf:0d:
         ea:60:66:92:7b:fa:8c:a6
-----BEGIN X509 CRL-----
MIIDcjCCAVoCAQEwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMV
VGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENl
cnRpZmljYXRpb24gQXV0aG9yaXR5Fw0xOTA4MTgxMzU4MjVaFw0xOTA4MjIxMzU4
MjVaMGswIgIRANjIV8rkvmb5E3Wf3aPV2ysXDTE4MDMxNjEyMjE1NFowIgIRAKbc
LtOIMMwDPSOrzrclZL8XDTE4MDMxNjEyMjE1NFowIQIQMpG5djdbcIoI5TIkJ7vE
NBcNMTgwMzE2MTIyMTU0WqAwMC4wHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd
8rIDZsswCwYDVR0UBAQCAg4sMA0GCSqGSIb3DQEBDAUAA4ICAQBlc9HCsiGDaxCc
DYPnBzJ6iyW/HIQDe/WPwTtOP7MMyWEdvkySXs3+VgcL/1I48RsOrUCn2ChZdsLn
JHcpceVTTC/DZc6zSZxF00oKpXUAH2WFnBbi1zhv6r/TWO9+yxB6yJu75GnmNbQx
iBkp3CuHlU+eFwr1FrdwHyp80O39AKcRDGjgT/eg2BM0Q38J6CEqnzTMqxBJuv8h
uZdXJckoIWYe4CNFNSDGj6iTtUB/5cNzzirRUgyfNlP35psDGJRWnns0ILqYufqF
2ZV6Ro7R8bVWvkwwvk4tKDejYFuRuMU4MJQ6f/oLu/Cv/ehneFVCETJxVw6zZheD
UnbXAEokh6CCjn8OIWSoSGWCdBEV+pltx1vPXwkLK1qkcVGvmQQeSRQB/nANoOwq
TsT1Ota8gH1snFPEJTLIim+3WmF/TKGylclXZ49FgdI9uZ6GkWEDKlEWUDvUIYOJ
mA+TTQCCeGdicI3A6Tt3S7dNUh/3zQRe5ALCiXtkeWna9Fc9Ng2etPz8cctt3A0e
zPnZWl4241xWiqJwdcK0cIufsIYEQqU1W0ek3+CUOloy5pwfAhDUFIje0kb8u7Yc
cZCIbwfLXL5c4VJC1q/mOnzAEGyUWy8czVqgwd6NeUxUnaZgIbE5DbyYyVSsVFWb
BUTEr5T0LbPLjzHUvw3qYGaSe/qMpg==
-----END X509 CRL-----

Path #2 Root

Root certificate for Path #2 (AddTrust External CA Root):

# openssl x509 -fingerprint -noout -in AddTrustExternalCARoot.crt
SHA1 Fingerprint=02:FA:F3:E2:91:43:54:68:60:78:57:69:4D:F5:E4:5B:68:85:18:68

Download CRL from CA:

# wget http://crl.comodoca.com/AddTrustExternalCARoot.crl

Convert DER to PEM:

# openssl crl -inform DER -in AddTrustExternalCARoot.crl -outform PEM -out AddTrustExternalCARoot.pem

Get the fingerprint of the CRL:

# openssl crl -fingerprint -noout -in AddTrustExternalCARoot.pem
SHA1 Fingerprint=3B:03:0D:23:1C:F5:1F:53:0A:CC:AA:7A:25:BF:EE:D5:3F:80:8A:BB

Print the text version of the CRL:

# openssl crl -in AddTrustExternalCARoot.pem -text
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
        Last Update: Aug 18 13:58:25 2019 GMT
        Next Update: Aug 22 13:58:25 2019 GMT
        CRL extensions:
            X509v3 Authority Key Identifier:
                keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A

            X509v3 CRL Number:
                5362
Revoked Certificates:
    Serial Number: 537B76564F297F14DC6943E922AD2C79
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 46EAF096054CC5E3FA65EA6E9F42C664
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 3ACDAB9C759886BCAF74E5DF81A9F4E8
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 79174AA9141736FE15A7CA9F2CFF4588
        Revocation Date: Apr 30 20:03:54 2018 GMT
    Serial Number: 74C18753F7EEB4EA238D8416B5AC7646
        Revocation Date: Oct  9 09:11:57 2018 GMT
    Signature Algorithm: sha1WithRSAEncryption
         a8:f8:d9:b4:e2:75:46:19:27:0f:88:68:69:fa:06:f9:6a:51:
         bd:17:6e:8f:35:7c:2d:27:28:84:b1:59:99:c5:59:12:60:bc:
         50:f6:32:47:5b:f7:72:b9:42:40:2a:00:e5:63:e0:af:45:04:
         99:72:6c:ee:30:e7:dd:53:f6:1c:7b:9e:01:b5:06:ea:86:5f:
         8a:66:65:12:37:75:55:8a:3b:91:dd:87:43:be:c4:ce:6c:29:
         80:33:38:f4:df:e6:ed:d3:c9:ea:5c:e6:ee:57:22:7e:ca:fe:
         58:bd:e9:1d:f6:1a:02:9c:a1:86:77:ed:c1:7b:ea:a1:c8:cf:
         0f:5f:5b:ad:92:38:fc:86:45:5f:fc:99:cb:19:25:62:b0:61:
         6b:a7:8b:70:71:38:5a:39:e6:7f:de:d1:84:db:1c:cc:f3:e2:
         88:c6:4f:89:7a:5b:04:3d:cf:71:51:60:41:6d:38:9a:3f:08:
         4b:35:00:63:87:97:70:1f:15:ff:e1:72:20:7b:59:1f:de:41:
         e4:81:6f:26:12:5e:c6:6f:cb:77:00:99:97:da:c2:68:fe:d5:
         07:3f:a5:e0:fa:33:6b:c9:f3:b8:7f:02:05:b4:23:9f:4b:5d:
         5c:2f:dd:81:7c:bf:5c:3f:87:f1:dd:03:03:f3:bc:3e:68:86:
         ae:a9:64:7d
-----BEGIN X509 CRL-----
MIICnTCCAYUCAQEwDQYJKoZIhvcNAQEFBQAwbzELMAkGA1UEBhMCU0UxFDASBgNV
BAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAg
TmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdBcNMTkw
ODE4MTM1ODI1WhcNMTkwODIyMTM1ODI1WjCBrzAhAhBTe3ZWTyl/FNxpQ+kirSx5
Fw0xNTEyMTQxNTU4MzBaMCECEEbq8JYFTMXj+mXqbp9CxmQXDTE1MTIxNDE1NTgz
MFowIQIQOs2rnHWYhryvdOXfgan06BcNMTUxMjE0MTU1ODMwWjAhAhB5F0qpFBc2
/hWnyp8s/0WIFw0xODA0MzAyMDAzNTRaMCECEHTBh1P37rTqI42EFrWsdkYXDTE4
MTAwOTA5MTE1N1qgMDAuMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1Qa
MAsGA1UdFAQEAgIU8jANBgkqhkiG9w0BAQUFAAOCAQEAqPjZtOJ1RhknD4hoafoG
+WpRvRdujzV8LScohLFZmcVZEmC8UPYyR1v3crlCQCoA5WPgr0UEmXJs7jDn3VP2
HHueAbUG6oZfimZlEjd1VYo7kd2HQ77EzmwpgDM49N/m7dPJ6lzm7lcifsr+WL3p
HfYaApyhhnftwXvqocjPD19brZI4/IZFX/yZyxklYrBha6eLcHE4Wjnmf97RhNsc
zPPiiMZPiXpbBD3PcVFgQW04mj8ISzUAY4eXcB8V/+FyIHtZH95B5IFvJhJexm/L
dwCZl9rCaP7VBz+l4Poza8nzuH8CBbQjn0tdXC/dgXy/XD+H8d0DA/O8PmiGrqlk
fQ==
-----END X509 CRL-----

CRL from CA (Path #2 Root, older CRL)

And here is the CRL supplied by the intermediate CA that signed the wildcard certificate:

# openssl crl -fingerprint -noout -in root.crl
SHA1 Fingerprint=E1:24:F4:35:3B:D0:B7:5B:AA:D9:AD:C7:33:F2:29:32:20:08:47:14

Here, I note that the above CRL fingerprint is different, but the X509v3 Authority Key Identifier is an exact match (this is an older version of the above CRL).

# openssl crl -in root.crl -text
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
        Last Update: May 28 00:12:38 2019 GMT
        Next Update: Jun  1 00:12:38 2019 GMT
        CRL extensions:
            X509v3 Authority Key Identifier:
                keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A

            X509v3 CRL Number:
                5275
Revoked Certificates:
    Serial Number: 537B76564F297F14DC6943E922AD2C79
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 46EAF096054CC5E3FA65EA6E9F42C664
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 3ACDAB9C759886BCAF74E5DF81A9F4E8
        Revocation Date: Dec 14 15:58:30 2015 GMT
    Serial Number: 79174AA9141736FE15A7CA9F2CFF4588
        Revocation Date: Apr 30 20:03:54 2018 GMT
    Serial Number: 74C18753F7EEB4EA238D8416B5AC7646
        Revocation Date: Oct  9 09:11:57 2018 GMT
    Signature Algorithm: sha1WithRSAEncryption
         38:3a:7d:3e:ee:be:48:e7:93:c3:91:0a:c3:47:46:11:87:83:
         60:85:19:2f:77:17:bd:e9:0f:02:de:04:60:33:38:5a:38:99:
         16:6b:81:51:83:f4:dc:97:83:2f:f9:97:18:5e:6a:24:5e:77:
         a0:39:dc:e1:09:24:c8:9c:05:e3:68:a2:ca:aa:1f:e7:85:fb:
         84:a0:07:96:4d:f0:53:68:6f:85:bd:d6:07:6d:57:34:9a:01:
         6e:51:b5:53:69:da:db:e1:c6:0d:c6:d9:d6:85:96:2e:b0:bf:
         71:25:49:97:66:8b:61:4a:7d:fd:ce:f3:07:d2:b5:bf:71:c0:
         01:6b:79:b2:20:5f:58:41:34:03:1b:88:a5:d7:f7:9b:ab:ff:
         49:fa:07:0b:0a:90:d8:f8:93:28:70:7a:f9:48:ed:40:b3:ae:
         31:f5:af:51:ed:00:ff:2e:0e:b9:3e:ee:6c:20:21:a0:d8:98:
         46:bd:9d:00:bb:aa:3d:30:8c:b2:72:00:af:cd:79:05:2f:40:
         5a:ae:2a:27:26:77:c3:40:79:88:4c:7b:2e:2e:df:2e:d5:4f:
         c5:b2:14:e1:aa:9a:29:4f:b5:e5:01:04:df:b7:89:59:17:1c:
         06:7b:a1:a8:9a:84:0c:cf:8c:2f:e9:3a:ec:78:f5:c9:e2:da:
         5f:16:1a:38
-----BEGIN X509 CRL-----
MIICnTCCAYUCAQEwDQYJKoZIhvcNAQEFBQAwbzELMAkGA1UEBhMCU0UxFDASBgNV
BAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAg
TmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdBcNMTkw
NTI4MDAxMjM4WhcNMTkwNjAxMDAxMjM4WjCBrzAhAhBTe3ZWTyl/FNxpQ+kirSx5
Fw0xNTEyMTQxNTU4MzBaMCECEEbq8JYFTMXj+mXqbp9CxmQXDTE1MTIxNDE1NTgz
MFowIQIQOs2rnHWYhryvdOXfgan06BcNMTUxMjE0MTU1ODMwWjAhAhB5F0qpFBc2
/hWnyp8s/0WIFw0xODA0MzAyMDAzNTRaMCECEHTBh1P37rTqI42EFrWsdkYXDTE4
MTAwOTA5MTE1N1qgMDAuMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1Qa
MAsGA1UdFAQEAgIUmzANBgkqhkiG9w0BAQUFAAOCAQEAODp9Pu6+SOeTw5EKw0dG
EYeDYIUZL3cXvekPAt4EYDM4WjiZFmuBUYP03JeDL/mXGF5qJF53oDnc4QkkyJwF
42iiyqof54X7hKAHlk3wU2hvhb3WB21XNJoBblG1U2na2+HGDcbZ1oWWLrC/cSVJ
l2aLYUp9/c7zB9K1v3HAAWt5siBfWEE0AxuIpdf3m6v/SfoHCwqQ2PiTKHB6+Ujt
QLOuMfWvUe0A/y4OuT7ubCAhoNiYRr2dALuqPTCMsnIAr815BS9AWq4qJyZ3w0B5
iEx7Li7fLtVPxbIU4aqaKU+15QEE37eJWRccBnuhqJqEDM+ML+k67Hj1yeLaXxYa
OA==
-----END X509 CRL-----

Best Answer

After reviewing the OpenSSL documentation for the verify command, I found that CRL PEMs can indeed be concatenated, and/or specified in separate files:

-CRLfile file

The file should contain one or more CRLs in PEM format. This option can be specified more than once to include CRLs from multiple files.

Additionally, after reviewing the OpenSSL documentation for the crl command, I found that there are four options available for checking the identity of a CRL (including the apparently undocumented -fingerprint option):

-hash

Output a hash of the issuer name. This can be use to lookup CRLs in a directory by issuer name.

-hash_old

Outputs the "hash" of the CRL issuer name using the older algorithm as used by OpenSSL before version 1.0.0.

-issuer

Output the issuer name.

Apparently, the only way to confirm the source of the CRL is via the issuer name (three of the four options).

Instead of using the -fingerprint option, which produces a unique hash for each version of a CRL, the -hash option can be used, which produces a hash of the issuer name. There is also a -hash_old option that uses an MD5 hash and an -issuer option to print the full text of the issuer name.

Although this doesn't seem like a strong way to ascertain the identity of a CRL, it appears to be the only method available. What I was hoping for was something like the -modulus option to check that the signing key of the CRL matches that of the root certificate, but no such option exists:

# openssl crl -modulus -noout -in AddTrustExternalCARoot.pem
unknown option -modulus

Further, I discovered that the root certificate(s) do not have CRLs, but that the intermediate certificate(s) for both Path #1 and Path #2 have CRLs. The download URL for the CRL can be extracted from the text version of the intermediate certificates:

# openssl x509 -noout -text -in 2_intermediate_sectigo.crt | grep -A 4 'X509v3 CRL Distribution Points'
  X509v3 CRL Distribution Points:

      Full Name:
        URI:http://crl.usertrust.com/USERTrustRSACertificationAuthority.crl

And the second CRL is from the second intermediate certificate (in Path #2 only):

# openssl x509 -noout -text -in 3_intermediate_usertrust.crt | grep -A 4 'X509v3 CRL Distribution Points'
 X509v3 CRL Distribution Points:

     Full Name:
       URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl

However, there are no CRL Distribution points for the root certificate of either Path #1 nor Path #2 (this is important at the end of this answer):

# openssl x509 -noout -text -in USERTrustRSACertificationAuthority.crt | grep -A 4 'X509v3 CRL Distribution Points'

# openssl x509 -noout -text -in AddTrustExternalCARoot.crt | grep -A 4 'X509v3 CRL Distribution Points'

This showed that for Path #2, I was downloading a CRL from the wrong source (it should be from UserTrust, not Comodo):

# wget http://crl.comodoca.com/AddTrustExternalCARoot.crl
# mv AddTrustExternalCARoot.crl AddTrustExternalCARoot_comodo.crl
# openssl crl -inform DER -in AddTrustExternalCARoot_comodo.crl -outform PEM -out AddTrustExternalCARoot_comodo.pem
# openssl crl -hash -noout -in AddTrustExternalCARoot_comodo.pem
157753a5

# wget http://crl.usertrust.com/AddTrustExternalCARoot.crl
# openssl crl -inform DER -in AddTrustExternalCARoot.crl -outform PEM -out AddTrustExternalCARoot.pem
# openssl crl -hash -noout -in AddTrustExternalCARoot.pem
157753a5

# sum AddTrustExternalCARoot_comodo.crl
15298     1

# sum AddTrustExternalCARoot.crl
15939     1

# openssl crl -noout -text -in AddTrustExternalCARoot_comodo.pem | grep -A 1 'X509v3 CRL Number'
  X509v3 CRL Number:
      5358

# openssl crl -noout -text -in AddTrustExternalCARoot.pem | grep -A 1 'X509v3 CRL Number'
  X509v3 CRL Number:
      5363

As shown above, although the CRL from UserTrust and Comodo have the same issuer and both should work, Comodo provided an older version.

Further, this seems to indicate that for Certification Path #1, only a single CRL should be needed, but for Certification Path #2, both CRLs could be required.


Path #1 Root

Root certificate hash for Path #1 (USERTrust RSA Certification Authority):

# openssl x509 -hash -noout -in USERTrustRSACertificationAuthority.crt
fc5a8f99

Hash of CRL for root certificate for Path #1:

# openssl crl -hash -noout -in USERTrustRSACertificationAuthority.pem
fc5a8f99

# openssl crl -issuer -noout -in USERTrustRSACertificationAuthority.pem
issuer=/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority

Path #2 Root

Root certificate for Path #2 (AddTrust External CA Root):

# openssl x509 -hash -noout -in AddTrustExternalCARoot.crt
157753a5

Hash of CRL for root certificate for Path #2:

# openssl crl -hash -noout -in AddTrustExternalCARoot.pem
157753a5

# openssl crl -issuer -noout -in AddTrustExternalCARoot.pem
issuer=/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

Hash of older version of CRL for root certificate for Path #2:

# openssl crl -hash -noout -in root.crl
157753a5

# openssl crl -issuer -noout -in root.crl
issuer=/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

In conclusion, the appropriate way to build the CRL file for multiple certificate paths is to first check each individual certificate for X509v3 CRL Distribution Points (see above), then for each CRL URL, retrieve the latest DER (binary file) and convert to PEM (ASCII file):

wget http://crl.usertrust.com/AddTrustExternalCARoot.crl
openssl crl -inform DER -in AddTrustExternalCARoot.crl -outform PEM -out AddTrustExternalCARoot_CRL.pem

wget http://crl.usertrust.com/USERTrustRSACertificationAuthority.crl
openssl crl -inform DER -in USERTrustRSACertificationAuthority.crl -outform PEM -out USERTrustRSACertificationAuthority_CRL.pem

Then catenate all of the PEM files into a single file:

cat USERTrustRSACertificationAuthority_CRL.pem AddTrustExternalCARoot_CRL.pem > root.crl

And finally, verify the certificate against the CA and CRL files:

# openssl verify -CAfile root.crt -CRLfile root.crl server.crt
server.crt: OK

However, if you encounter errors when attempting to check the CRL bundle, note that there is an open OpenSSL bug (CRL checks fail if the root CA certificate does not have a CRL distribution point):

# openssl verify -crl_check -CAfile root.crt -CRLfile root.crl server.crt
server.crt: OU = Domain Control Validated, OU = PositiveSSL Wildcard, CN = *.[REDACTED].org
error 3 at 0 depth lookup:unable to get certificate CRL

For reference I am using OpenSSL 1.0.2k (latest Amazon Linux version) and the bug was reported on OpenSSL 1.1.1:

# openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017