模块 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.new('SHA1')
certificate_id =
  OpenSSL::OCSP::CertificateId.new subject, issuer, digest

然后创建一个请求,并将证书 ID 添加到其中

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

向请求中添加一个随机数可以防止重放攻击,但并非所有 CA 都会处理随机数。

request.add_nonce

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

ocsp_uris = subject.ocsp_uris

require 'uri'

ocsp_uri = URI ocsp_uris[0]

为了提交请求,我们将把请求 POST 到 OCSP URI(根据 RFC 2560)。请注意,在此示例中,我们仅处理 HTTP 请求,不处理任何重定向,因此这不足以用于严肃的用途。

require 'net/http'

http_response =
  Net::HTTP.start ocsp_uri.hostname, ocsp_uri.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

接下来,我们需要了解响应详细信息,以确定响应是否与我们的请求匹配。首先,我们检查随机数。同样,并非所有 CA 都支持随机数。有关返回值含义,请参阅 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 certificate'
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

不要在响应中包含 producedAt 时间

NOVERIFY

根本不验证响应

RESPID_KEY

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

RESPONSE_STATUS_INTERNALERROR

颁发者内部错误

RESPONSE_STATUS_MALFORMEDREQUEST

非法确认请求

RESPONSE_STATUS_SIGREQUIRED

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

RESPONSE_STATUS_SUCCESSFUL

Response 具有有效的确认

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 基于密钥名称。