Ruby 2.4
OpenSSL

OpenSSL::OCSP

模块 OpenSSL :: OCSP

OpenSSL :: OCSP 实现在线证书状态协议请求和响应。

创建和发送 OCSP 请求需要在authorityInfoAccess扩展中包含 OCSP URL 的主题证书以及主题证书的颁发者证书。首先,加载发行人和主体证书:

subject = OpenSSL::X509::Certificate.new subject_pem issuer = OpenSSL::X509::Certificate.new issuer_pem

为了创建请求,我们需要为主题证书创建一个证书 ID,以便 CA 知道我们询问的是哪个证书:

digest = OpenSSL::Digest::SHA1.new certificate_id = OpenSSL::OCSP::CertificateId.new subject, issuer, digest

然后创建一个请求并向其添加证书 ID:

request = OpenSSL::OCSP::Request.new request.add_certid certificate_id

在请求中添加一个 nonce 可防止重放攻击,但并非所有 CA 都处理 nonce。

request.add_nonce

要将请求提交给 CA 进行验证,我们需要从主题证书中提取 OCSP URI:

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]

要提交请求,我们会将请求发送到 OCSP URI(根据RFC 2560)。请注意,我们只处理 HTTP 请求,并且在本例中不处理任何重定向,所以这对于严重使用是不够的。

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

首先我们检查响应是否有有效签名。没有有效的签名,我们不能相信它。如果您在此遇到故障,则可能缺少系统证书存储或者可能缺少中间证书。

store = OpenSSL::X509::Store.new store.set_default_paths unless response_basic.verify [], store then raise 'response is not signed by a trusted certificate' end

该响应包含状态信息(成功/失败)。我们可以将状态显示为一个字符串:

puts response.status_string #=> successful

接下来,我们需要知道回复的详细信息,以确定回复是否符合我们的要求。首先我们检查nonce。同样,并非所有的 CA 都支持随机数。有关返回值的含义,请参阅 OpenSSL :: OCSP :: Request#check_nonce。

p request.check_nonce basic_response #=> value from -1 to 3

然后从基本响应中提取证书的状态信息。

single_response = basic_response.find_response(certificate_id) unless single_response raise 'basic_response does not have the status for the certificiate' end

然后检查有效性。未来发布的状态必须被拒绝。

unless single_response.check_validity raise 'this_update is in the future or next_update time has passed' end case single_response.cert_status when OpenSSL::OCSP::V_CERTSTATUS_GOOD puts 'certificate is still valid' when OpenSSL::OCSP::V_CERTSTATUS_REVOKED puts "certificate has been revoked at #{single_response.revocation_time}" when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN puts 'responder doesn't know about the certificate' end

常量

NOCASIGN

(这个标志不被 OpenSSL 1.0.1g 使用)

NOCERTS

不要在响应中包含证书

NOCHAIN

不要验证响应中的证书链

NOCHECKS

不要进行额外的签名证书检查

NODELEGATED

(这个标志不被 OpenSSL 1.0.1g 使用)

NOEXPLICIT

不要检查信任

NOINTERN

不要搜索签名者的响应中包含的证书

NOSIGS

不要在响应中检查签名

NOTIME

不包括产生的响应时间

NOVERIFY

根本不验证响应

RESPID_KEY

通过签署证书密钥 ID 来识别响应

RESPONSE_STATUS_INTERNALERROR

发行人内部错误

RESPONSE_STATUS_MALFORMEDREQUEST

非法确认请求

RESPONSE_STATUS_SIGREQUIRED

您必须签署请求并重新提交

RESPONSE_STATUS_SUCCESSFUL

响应有有效的确认

RESPONSE_STATUS_TRYLATER

稍后再试

RESPONSE_STATUS_UNAUTHORIZED

您的请求未经授权。

REVOKED_STATUS_AFFILIATIONCHANGED

证书主题的名称或其他信息已更改

REVOKED_STATUS_CACOMPROMISE

由于密钥泄露,此 CA 证书已被吊销

REVOKED_STATUS_CERTIFICATEHOLD

该证书处于暂停状态

REVOKED_STATUS_CESSATIONOFOPERATION

证书不再需要

REVOKED_STATUS_KEYCOMPROMISE

该证书因重大妥协而被撤销

REVOKED_STATUS_NOSTATUS

该证书因不明原因被撤销

REVOKED_STATUS_REMOVEFROMCRL

该证书先前被搁置,现在应该从 CRL 中删除

REVOKED_STATUS_SUPERSEDED

证书已被新证书取代

REVOKED_STATUS_UNSPECIFIED

该证书因不明原因被撤销

TRUSTOTHER

不要验证其他证书

V_CERTSTATUS_GOOD

表示证书未被吊销,但并不一定意味着已颁发证书或此响应在证书的有效期限内

V_CERTSTATUS_REVOKED

表示证书已被永久或暂时吊销(保留)。

V_CERTSTATUS_UNKNOWN

表示响应者不知道所请求的证书。

V_RESPID_KEY

响应者 ID 基于公钥。

V_RESPID_NAME

响应者 ID 基于密钥名称。