OpenSSL: Manually verify a certificate against an OCSP, check OCSP server for stale respones
This article assumes work is being done on a Linux based machine, you can install a Linux terminal on Windows 10 here https://docs.microsoft.com/en-us/windows/wsl/install-win10
This article shows you how to manually verify a certificate against an OCSP server. OCSP stands for the Online Certificate Status Protocol and is one way to validate a certificate status. It is an alternative to the CRL, certificate revocation list.
Compared to CRL's:
Since an OCSP response contains less information than a typical CRL (certificate revocation list), OCSP can use networks and client resources more efficiently.
Using OCSP, clients do not need to parse CRLs themselves, saving client-side complexity. However, this is balanced by the practical need to maintain a cache. In practice, such considerations are of little consequence, since most applications rely on third-party libraries for all X.509 functions.
OCSP discloses to the responder that a particular network host used a particular certificate at a particular time. OCSP does not mandate encryption, so other parties may intercept this information.
We will be using OpenSSL in this article. I'm using the following version:
$ openssl version
OpenSSL 1.0.1g 7 Apr 2014
Get a certificate with an OCSP
First we will need a certificate from a website. I'll be using Wikipedia as an example here. We can retrieve this with the following openssl command:
openssl s_client -connect wikipedia.org:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p'
Save this output to a file, for example, wikipedia.pem:
openssl s_client -connect wikipedia.org:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > wikipedia.pem
Now, check if this certificate has an OCSP URI:
openssl x509 -noout -ocsp_uri -in wikipedia.pem
http://ocsp.digicert.com
If it does not give any output, the certificate has no OCSP URI. You cannot validate it against an OCSP.
Getting the certificate chain
It is required to send the certificate chain along with the certificate you want to validate. So, we need to get the certificate chain for our domain, wikipedia.org. Using the -showcerts option with openssl s_client, we can see all the certificates, including the chain:
openssl s_client -connect wikipedia.org:443 -showcerts 2>&1 < /dev/null
Results in a boatload of output, but what we are interested in is the following:
1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
-----BEGIN CERTIFICATE-----
MIIGWDCCBUCgAwIBAgIQCl8RTQNbF5EX0u/UA4w/OzANBgkqhkiG9w0BAQUFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTA4MDQwMjEyMDAwMFoXDTIyMDQwMzAwMDAwMFowZjEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
Q0EtMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9hCikQH17+NDdR
CPge+yLtYb4LDXBMUGMmdRW5QYiXtvCgFbsIYOBC6AUpEIc2iihlqO8xB3RtNpcv
KEZmBMcqeSZ6mdWOw21PoF6tvD2Rwll7XjZswFPPAAgyPhBkWBATaccM7pxCUQD5
BUTuJM56H+2MEb0SqPMV9Bx6MWkBG6fmXcCabH4JnudSREoQOiPkm7YDr6ictFuf
1EutkozOtREqqjcYjbTCuNhcBoz4/yO9NV7UfD5+gw6RlgWYw7If48hl66l7XaAs
zPw82W3tzPpLQ4zJ1LilYRyyQLYoEt+5+F/+07LJ7z20Hkt8HEyZNp496+ynaF4d
32duXvsCAwEAAaOCAvowggL2MA4GA1UdDwEB/wQEAwIBhjCCAcYGA1UdIASCAb0w
ggG5MIIBtQYLYIZIAYb9bAEDAAIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH
AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy
AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj
AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg
AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ
AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt
AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj
AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl
AHIAZQBuAGMAZQAuMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm
MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgY8GA1UdHwSB
hzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGln
aEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNl
cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDAfBgNVHSME
GDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAdBgNVHQ4EFgQUUOpzidsp+xCPnuUB
INTeeZlIg/cwDQYJKoZIhvcNAQEFBQADggEBAB7ipUiebNtTOA/vphoqrOIDQ+2a
vD6OdRvw/S4iWawTwGHi5/rpmc2HCXVUKL9GYNy+USyS8xuRfDEIcOI3ucFbqL2j
CwD7GhX9A61YasXHJJlIR0YxHpLvtF9ONMeQvzHB+LGEhtCcAarfilYGzjrpDq6X
dF3XcZpCdF/ejUN83ulV7WkAywXgemFhM9EZTfkI7qA5xSU1tyvED7Ld8aW3DiTE
JiiNeXf1L/BXunwH1OH8zVowV36GEEfdMR/X/KLCvzB8XSSq6PmuX2p0ws5rs0bY
Ib4p1I5eFdZCSucyb6Sxa1GDWL4/bcf72gMhy2oWGU4K8K2Eyl2Us1p292E=
-----END CERTIFICATE-----
As you can see, this is number 1. Number 0 is the certificate for Wikipedia, we already have that. If your site has more certificates in its chain, you will see more here. Save them all, in the order OpenSSL sends them (as in, first the one which directly issued your server certificate, then the one that issues that certificate and so on, with the root or most-root at the end of the file) to a file, named chain.pem.
Sending the OCSP request
We now have all the data we need to do an OCSP request. Using either of the following Openssl commands we can send an OCSP request and only get the text output. The second example uses the serial number for the leaf certificate rather than pointing to a file on the filesystem.
openssl ocsp -issuer chain.pem -cert wikipedia.pem -text -url http://ocsp.digicert.com
openssl ocsp -issuer chain.pem -serial "0x0114195F66FAFF8FD66E12496E516F4F" -text -url http://ocsp.digicert.com
Results in:
OCSP Request Data:
Version: 1 (0x0)
Requestor List:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: ED48ADDDCB7B00E20E842AA9B409F1AC3034CF96
Issuer Key Hash: 50EA7389DB29FB108F9EE50120D4DE79994883F7
Serial Number: 0114195F66FAFF8FD66E12496E516F4F
Request Extensions:
OCSP Nonce:
0410DA634F2ADC31DC48AE89BE64E8252D12
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: 50EA7389DB29FB108F9EE50120D4DE79994883F7
Produced At: Apr 9 08:45:00 2014 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: ED48ADDDCB7B00E20E842AA9B409F1AC3034CF96
Issuer Key Hash: 50EA7389DB29FB108F9EE50120D4DE79994883F7
Serial Number: 0114195F66FAFF8FD66E12496E516F4F
Cert Status: good
This Update: Apr 9 08:45:00 2014 GMT
Next Update: Apr 16 09:00:00 2014 GMT
Signature Algorithm: sha1WithRSAEncryption
56:21:4c:dc:84:21:f7:a8:ac:a7:b9:bc:10:19:f8:19:f1:34:
c1:63:ca:14:7f:8f:5a:85:2a:cc:02:b0:f8:b5:05:4a:0f:28:
50:2a:4a:4d:04:01:b5:05:ef:a5:88:41:d8:9d:38:00:7d:76:
1a:aa:ff:21:50:68:90:d2:0c:93:85:49:e7:8e:f1:58:08:77:
a0:4e:e2:22:98:01:b7:e3:27:75:11:f5:b7:8f:e0:75:7d:19:
9b:74:cf:05:dc:ae:1c:36:09:95:b6:08:bc:e7:3f:ea:a2:e3:
ae:d7:8f:c0:9d:8e:c2:37:67:c7:5b:d8:b0:67:23:f1:51:53:
26:c2:96:b0:1a:df:4e:fb:4e:e3:da:a3:98:26:59:a8:d7:17:
69:87:a3:68:47:08:92:d0:37:04:6b:49:9a:96:9d:9c:b1:e8:
cb:dc:68:7b:4a:4d:cb:08:f7:92:67:41:99:b6:54:56:80:0c:
18:a7:24:53:ac:c6:da:1f:4d:f4:3c:7d:68:44:1d:a4:df:1d:
48:07:85:52:86:59:46:d1:35:45:1a:c7:6b:6b:92:de:24:ae:
c0:97:66:54:29:7a:c6:86:a6:da:9f:06:24:dc:ac:80:66:95:
e0:eb:49:fd:fb:d4:81:6a:2b:81:41:57:24:78:3b:e0:66:70:
d4:2e:52:92
wikipedia.pem: good
This Update: Apr 9 08:45:00 2014 GMT
Next Update: Apr 16 09:00:00 2014 GMT
If you want to have a more summarized output, leave out the -text option. I most of the time include it to find out problems with an OCSP.
This is how a good certificate status looks:
openssl ocsp -issuer chain.pem -cert wikipedia.pem -url http://ocsp.digicert.com
wikipedia.pem: good
This Update: Apr 9 08:45:00 2014 GMT
Next Update: Apr 16 09:00:00 2014 GMT
Revoked certificate
If you have a revoked certificate, you can also test it the same way as stated above. The response looks like this:
Response verify OK
test-revoked.pem: revoked
This Update: Apr 9 03:02:45 2014 GMT
Next Update: Apr 10 03:02:45 2014 GMT
Revocation Time: Mar 25 15:45:55 2014 GMT
You can test this using the certificate and chain on the Verisign revoked certificate test page: https://test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html
Other errors
If we send this request to another OCSP, one who did not issued this certificate, we should receive an unauthorized error:
openssl ocsp -issuer chain.pem -cert wikipedia.pem -url http://rapidssl-ocsp.geotrust.com
Responder Error: unauthorized (6)
The -text option here shows more information:
OCSP Request Data:
Version: 1 (0x0)
Requestor List:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: ED48ADDDCB7B00E20E842AA9B409F1AC3034CF96
Issuer Key Hash: 50EA7389DB29FB108F9EE50120D4DE79994883F7
Serial Number: 0114195F66FAFF8FD66E12496E516F4F
Request Extensions:
OCSP Nonce:
041015BB718C43C46C41122E841DB2282ECE
Responder Error: unauthorized (6)
Some OCSP's are configured differently and give out this error:
openssl ocsp -issuer chain.pem -cert wikipedia.pem -url http://ocsp.digidentity.eu/L4/services/ocsp
Response Verify Failure
140735308649312:error:2706B06F:OCSP routines:OCSP_CHECK_IDS:response contains no revocation data:ocsp_vfy.c:269:
140735308649312:error:2706B06F:OCSP routines:OCSP_CHECK_IDS:response contains no revocation data:ocsp_vfy.c:269:
wikipedia.pem: ERROR: No Status found.
If we do include the -text option here we can see that a response is sent, however, that it has no data in it:
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: C = NL, O = Digidentity B.V., CN = Digidentity OCSP
Produced At: Apr 9 12:02:00 2014 GMT
Responses:
Response Extensions:
OCSP Nonce:
0410EB540472EA2D8246E88F3317B014BEEF
Signature Algorithm: sha256WithRSAEncryption
Other OCSP's give out the "unknown" status:
openssl ocsp -issuer chain.pem -cert wikipedia.pem -url http://ocsp.quovadisglobal.com/
Response Verify Failure
140735308649312:error:27069070:OCSP routines:OCSP_basic_verify:root ca not trusted:ocsp_vfy.c:152:
wikipedia.pem: unknown
This Update: Apr 9 12:09:18 2014 GMT
The -text options shows us more:
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: C = CH, O = QuoVadis Limited, OU = OCSP Responder, CN = QuoVadis OCSP Authority Signature
Produced At: Apr 9 12:09:10 2014 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: ED48ADDDCB7B00E20E842AA9B409F1AC3034CF96
Issuer Key Hash: 50EA7389DB29FB108F9EE50120D4DE79994883F7
Serial Number: 0114195F66FAFF8FD66E12496E516F4F
Cert Status: unknown
This Update: Apr 9 12:09:10 2014 GMT
Another failure is a stale OCSP response, which shows this:
openssl ocsp -issuer windesktop/intm.cer -serial "0xD1ABD225C7BCFA1BBDD5F9CC0B716425" -text -url http://ocsp.sectigo.com -header "Host" "ocsp.sectigo.com"
OCSP Request Data:
Version: 1 (0x0)
Requestor List:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 430BD20E4F137A1A6C918F24E5DA7E324D4733C8
Issuer Key Hash: 8D8C5EC454AD8AE177E99BF99B05E1B8018D61E1
Serial Number: D1ABD225C7BCFA1BBDD5F9CC0B716425
Request Extensions:
OCSP Nonce:
0410238F3CC073E7316689B9A4F711690975
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: 8D8C5EC454AD8AE177E99BF99B05E1B8018D61E1
Produced At: Apr 6 14:01:41 2019 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 430BD20E4F137A1A6C918F24E5DA7E324D4733C8
Issuer Key Hash: 8D8C5EC454AD8AE177E99BF99B05E1B8018D61E1
Serial Number: D1ABD225C7BCFA1BBDD5F9CC0B716425
Cert Status: good
This Update: Apr 6 14:01:41 2019 GMT
Next Update: Apr 10 14:01:41 2019 GMT
Signature Algorithm: sha256WithRSAEncryption
8d:95:87:06:e6:51:53:ab:3c:9e:67:4e:6c:3a:4b:5b:0c:97:
2c:ea:5f:77:9d:f3:26:cd:af:38:9c:03:62:84:a1:8d:73:f2:
1a:53:ff:df:bf:d8:b2:ef:0c:1e:83:97:24:49:59:24:2a:15:
8a:14:18:df:7d:3a:9b:7d:d6:75:cc:a3:24:d3:f0:b3:18:1f:
76:ce:fa:aa:55:f7:72:d6:73:3b:a1:78:8a:b1:59:a6:80:86:
f5:57:04:e0:14:40:a4:ef:fc:dd:47:4e:32:e4:20:37:1c:63:
45:ba:0d:e3:f3:86:aa:61:d0:32:b8:b0:00:53:23:c8:a6:a1:
4a:86:58:69:68:a6:a7:a2:0e:ae:8c:6d:b3:af:0f:e6:49:f6:
2c:e2:61:cc:88:bb:3f:d9:96:e3:7b:ed:6e:ba:67:20:d5:f6:
28:86:82:cb:30:ad:8f:77:ff:2d:ac:b5:1a:4e:6b:3c:e8:7d:
ac:15:1e:c4:2c:27:f4:f7:07:e7:1f:a1:64:5b:3c:65:70:c0:
73:5a:a6:59:43:b5:d5:ec:d5:f5:a1:a6:c0:80:27:20:ac:af:
c7:d5:39:c3:55:9f:1f:61:c9:86:42:b7:7c:38:c5:8c:e5:e9:
6f:3f:3a:2d:da:a0:29:3f:05:fc:8a:7b:2a:aa:18:08:ca:7d:
a8:54:23:95
WARNING: no nonce in response
Response Verify Failure
139953377838744:error:27069076:OCSP routines:OCSP_basic_verify:signer certificate not found:ocsp_vfy.c:92:
0xD1ABD225C7BCFA1BBDD5F9CC0B716425: WARNING: Status times invalid.
139953377838744:error:2707307D:OCSP routines:OCSP_check_validity:status expired:ocsp_cl.c:370:
good
This Update: Apr 6 14:01:41 2019 GMT
Next Update: Apr 10 14:01:41 2019 GMT
This particular issue of stale OCSP responses is server side, meaning it's an issue on our OCSP server, and must be reported to ticketing.sectigo.com