Class: OCSPResponseFetch::Fetcher

Inherits:
Object
  • Object
show all
Defined in:
lib/ocsp_response_fetch/fetcher.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(subject_cert, issuer_cert) ⇒ Fetcher

Returns a new instance of Fetcher.

Parameters:

  • subject_cert (OpenSSL::X509::Certificate)
  • issuer_cert (OpenSSL::X509::Certificate)

Raises:



11
12
13
14
15
16
17
18
19
20
# File 'lib/ocsp_response_fetch/fetcher.rb', line 11

def initialize(subject_cert, issuer_cert)
  @certs_chain = [subject_cert, issuer_cert]
  @cid = OpenSSL::OCSP::CertificateId.new(subject_cert, issuer_cert)
  @ocsp_uri = subject_cert.ocsp_uris
                &.find { |u| URI::DEFAULT_PARSER.make_regexp =~ u }
  return unless @ocsp_uri.nil?

  raise OCSPResponseFetch::Error::FetchFailedError,
        'Certificate does not contain OCSP URL'
end

Class Method Details

.gen_ocsp_request(cid) ⇒ OpenSSL::OCSP::Request

Parameters:

  • cid (OpenSSL::OCSP::CertificateId)

Returns:

  • (OpenSSL::OCSP::Request)


88
89
90
91
92
93
# File 'lib/ocsp_response_fetch/fetcher.rb', line 88

def gen_ocsp_request(cid)
  ocsp_request = OpenSSL::OCSP::Request.new
  ocsp_request.add_certid(cid)
  ocsp_request.add_nonce
  ocsp_request
end

.request_and_validate(cid, ocsp_uri, certs) ⇒ OpenSSL::OCSP::Response

rubocop: disable Metrics/CyclomaticComplexity rubocop: disable Metrics/MethodLength rubocop: disable Metrics/PerceivedComplexity

Parameters:

  • cid (OpenSSL::OCSP::CertificateId)
  • ocsp_uri (String)
  • certs (Array of OpenSSL::X509::Certificate)

Returns:

  • (OpenSSL::OCSP::Response)

Raises:



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ocsp_response_fetch/fetcher.rb', line 40

def request_and_validate(cid, ocsp_uri, certs)
  ocsp_request = gen_ocsp_request(cid)
  ocsp_response = nil
  begin
    Timeout.timeout(2) do
      ocsp_response = send_ocsp_request(ocsp_request, ocsp_uri)
    end
  rescue Timeout::Error, SystemCallError
    raise OCSPResponseFetch::Error::FetchFailedError,
          'Timeout to access OCSP Responder'
  end

  if ocsp_response&.status != OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL
    raise OCSPResponseFetch::Error::FetchFailedError,
          'OCSPResponseStatus is not successful'
  end

  check_nonce = ocsp_request.check_nonce(ocsp_response.basic)
  unless [-1, 1].include?(check_nonce)
    raise OCSPResponseFetch::Error::FetchFailedError,
          'OCSPResponse nonce is invalid'
  end

  store = OpenSSL::X509::Store.new
  store.set_default_paths
  unless ocsp_response.basic.verify(certs, store)
    raise OCSPResponseFetch::Error::FetchFailedError,
          'OCSPResponse signature is invalid'
  end

  status = ocsp_response.basic.find_response(cid)
  if status.cert_status == OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
    raise OCSPResponseFetch::Error::FetchFailedError,
          'OCSPResponse CertStatus is unknown'
  elsif status.cert_status == OpenSSL::OCSP::V_CERTSTATUS_REVOKED
    raise OCSPResponseFetch::Error::RevokedError,
          'OCSPResponse CertStatus is revoked'
  end

  ocsp_response
end

.send_ocsp_request(ocsp_request, uri_string) ⇒ OpenSSL::OCSP::Response

Parameters:

  • ocsp_request (OpenSSL::OCSP::Request)
  • uri_string (String)

Returns:

  • (OpenSSL::OCSP::Response)


99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ocsp_response_fetch/fetcher.rb', line 99

def send_ocsp_request(ocsp_request, uri_string)
  uri = URI.parse(uri_string)
  path = uri.path
  path = '/' if path.nil? || path.empty?
  http_response = Net::HTTP.start(uri.host, uri.port) do |http|
    http.post(
      path,
      ocsp_request.to_der,
      'content-type' => 'application/ocsp-request'
    )
  end

  OpenSSL::OCSP::Response.new(http_response.body)
end

Instance Method Details

#runOpenSSL::OCSP::Response

Returns:

  • (OpenSSL::OCSP::Response)

Raises:



25
26
27
# File 'lib/ocsp_response_fetch/fetcher.rb', line 25

def run
  Fetcher.request_and_validate(@cid, @ocsp_uri, @certs_chain)
end