module OpenSSL::OCSP
OpenSSL::OCSP implements Online Certificate Status Protocol requests and responses.
Creating and sending an OCSP request requires a subject certificate that contains an OCSP URL in an authorityInfoAccess extension and the issuer certificate for the subject certificate. First, load the issuer and subject certificates:
subject = OpenSSL::X509::Certificate.new subject_pem issuer = OpenSSL::X509::Certificate.new issuer_pem
To create the request we need to create a certificate ID for the subject certificate so the CA knows which certificate we are asking about:
digest = OpenSSL::Digest::SHA1.new certificate_id = OpenSSL::OCSP::CertificateId.new subject, issuer, digest
Then create a request and add the certificate ID to it:
request = OpenSSL::OCSP::Request.new request.add_certid certificate_id
Adding a nonce to the request protects against replay attacks but not all CA process the nonce.
request.add_nonce
To submit the request to the CA for verification we need to extract the OCSP URI from the subject certificate:
authority_info_access = subject.extensions.find do |extension| extension.oid == 'authorityInfoAccess' end descriptions = authority_info_access.value.split "\n" ocsp = descriptions.find do |description| description.start_with? 'OCSP' end require 'uri' ocsp_uri = URI ocsp[/URI:(.*)/, 1]
To submit the request we'll POST the request to the OCSP URI (per RFC 2560). Note that we only handle HTTP requests and don't handle any redirects in this example, so this is insufficient for serious use.
require 'net/http' http_response = Net::HTTP.start ocsp_uri.hostname, ocsp.port do |http| http.post ocsp_uri.path, request.to_der, 'content-type' => 'application/ocsp-request' end response = OpenSSL::OCSP::Response.new http_response.body response_basic = response.basic
First we check if the response has a valid signature. Without a valid signature we cannot trust it. If you get a failure here you may be missing a system certificate store or may be missing the intermediate certificates.
store = OpenSSL::X509::Store.new store.set_default_paths unless response.verify [], store then raise 'response is not signed by a trusted certificate' end
The response contains the status information (success/fail). We can display the status as a string:
puts response.status_string #=> successful
Next we need to know the response details to determine if the response matches our request. First we check the nonce. Again, not all CAs support a nonce. See OpenSSL::OCSP::Request#check_nonce for the meanings of the return values.
p request.check_nonce basic_response #=> value from -1 to 3
Then extract the status information from the basic response. (You can check multiple certificates in a request, but for this example we only submitted one.)
response_certificate_id, status, reason, revocation_time, this_update, next_update, extensions = basic_response.status
Then check the various fields.
unless response_certificate_id == certificate_id then raise 'certificate id mismatch' end now = Time.now if this_update > now then raise 'update date is in the future' end if now > next_update then raise 'next update time has passed' end
Constants
- NOCASIGN
-
(This flag is not used by OpenSSL 1.0.1g)
- NOCERTS
-
Do not include certificates in the response
- NOCHAIN
-
Do not verify the certificate chain on the response
- NOCHECKS
-
Do not make additional signing certificate checks
- NODELEGATED
-
(This flag is not used by OpenSSL 1.0.1g)
- NOEXPLICIT
-
Do not check trust
- NOINTERN
-
Do not search certificates contained in the response for a signer
- NOSIGS
-
Do not check the signature on the response
- NOTIME
-
Do not include producedAt time in response
- NOVERIFY
-
Do not verify the response at all
- RESPID_KEY
-
Identify the response by signing the certificate key ID
- RESPONSE_STATUS_INTERNALERROR
-
Internal error in issuer
- RESPONSE_STATUS_MALFORMEDREQUEST
-
Illegal confirmation request
- RESPONSE_STATUS_SIGREQUIRED
-
You must sign the request and resubmit
- RESPONSE_STATUS_SUCCESSFUL
-
Response has valid confirmations
- RESPONSE_STATUS_TRYLATER
-
Try again later
- RESPONSE_STATUS_UNAUTHORIZED
-
Your request is unauthorized.
- REVOKED_STATUS_AFFILIATIONCHANGED
-
The certificate subject's name or other information changed
- REVOKED_STATUS_CACOMPROMISE
-
This CA certificate was revoked due to a key compromise
- REVOKED_STATUS_CERTIFICATEHOLD
-
The certificate is on hold
- REVOKED_STATUS_CESSATIONOFOPERATION
-
The certificate is no longer needed
- REVOKED_STATUS_KEYCOMPROMISE
-
The certificate was revoked due to a key compromise
- REVOKED_STATUS_NOSTATUS
-
The certificate was revoked for an unknown reason
- REVOKED_STATUS_REMOVEFROMCRL
-
The certificate was previously on hold and should now be removed from the CRL
- REVOKED_STATUS_SUPERSEDED
-
The certificate was superseded by a new certificate
- REVOKED_STATUS_UNSPECIFIED
-
The certificate was revoked for an unspecified reason
- TRUSTOTHER
-
Do not verify additional certificates
- V_CERTSTATUS_GOOD
-
Indicates the certificate is not revoked but does not necessarily mean the certificate was issued or that this response is within the certificate's validity interval
- V_CERTSTATUS_REVOKED
-
Indicates the certificate has been revoked either permanently or temporarily (on hold).
- V_CERTSTATUS_UNKNOWN
-
Indicates the responder does not know about the certificate being requested.
- V_RESPID_KEY
-
The responder ID is based on the public key.
- V_RESPID_NAME
-
The responder ID is based on the key name.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.