summaryrefslogtreecommitdiffstats
path: root/OpenSSL/OCSP.html
blob: 3d3a40e96dc29e315b1964344d27c73406d37bf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">

<title>module OpenSSL::OCSP - RDoc Documentation</title>

<script type="text/javascript">
  var rdoc_rel_prefix = "../";
  var index_rel_prefix = "../";
</script>

<script src="../js/navigation.js" defer></script>
<script src="../js/search.js" defer></script>
<script src="../js/search_index.js" defer></script>
<script src="../js/searcher.js" defer></script>
<script src="../js/darkfish.js" defer></script>

<link href="../css/fonts.css" rel="stylesheet">
<link href="../css/rdoc.css" rel="stylesheet">


<body id="top" role="document" class="module">
<nav role="navigation">
  <div id="project-navigation">
    <div id="home-section" role="region" title="Quick navigation" class="nav-section">
  <h2>
    <a href="../index.html" rel="home">Home</a>
  </h2>

  <div id="table-of-contents-navigation">
    <a href="../table_of_contents.html#pages">Pages</a>
    <a href="../table_of_contents.html#classes">Classes</a>
    <a href="../table_of_contents.html#methods">Methods</a>
  </div>
</div>

    <div id="search-section" role="search" class="project-section initially-hidden">
  <form action="#" method="get" accept-charset="utf-8">
    <div id="search-field-wrapper">
      <input id="search-field" role="combobox" aria-label="Search"
             aria-autocomplete="list" aria-controls="search-results"
             type="text" name="search" placeholder="Search" spellcheck="false"
             title="Type to search, Up and Down to navigate, Enter to load">
    </div>

    <ul id="search-results" aria-label="Search Results"
        aria-busy="false" aria-expanded="false"
        aria-atomic="false" class="initially-hidden"></ul>
  </form>
</div>

  </div>

  

  <div id="class-metadata">
    
    
    
    
    
  </div>
</nav>

<main role="main" aria-labelledby="module-OpenSSL::OCSP">
  <h1 id="module-OpenSSL::OCSP" class="module">
    module OpenSSL::OCSP
  </h1>

  <section class="description">
    
<p><a href="OCSP.html"><code>OpenSSL::OCSP</code></a> implements Online Certificate Status Protocol requests and responses.</p>

<p>Creating and sending an <a href="OCSP.html"><code>OCSP</code></a> request requires a subject certificate that contains an <a href="OCSP.html"><code>OCSP</code></a> URL in an authorityInfoAccess extension and the issuer certificate for the subject certificate.  First, load the issuer and subject certificates:</p>

<pre class="ruby"><span class="ruby-identifier">subject</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">X509</span><span class="ruby-operator">::</span><span class="ruby-constant">Certificate</span>.<span class="ruby-identifier">new</span> <span class="ruby-identifier">subject_pem</span>
<span class="ruby-identifier">issuer</span>  = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">X509</span><span class="ruby-operator">::</span><span class="ruby-constant">Certificate</span>.<span class="ruby-identifier">new</span> <span class="ruby-identifier">issuer_pem</span>
</pre>

<p>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:</p>

<pre class="ruby"><span class="ruby-identifier">digest</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span>.<span class="ruby-identifier">new</span>(<span class="ruby-string">&#39;SHA1&#39;</span>)
<span class="ruby-identifier">certificate_id</span> =
  <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">OCSP</span><span class="ruby-operator">::</span><span class="ruby-constant">CertificateId</span>.<span class="ruby-identifier">new</span> <span class="ruby-identifier">subject</span>, <span class="ruby-identifier">issuer</span>, <span class="ruby-identifier">digest</span>
</pre>

<p>Then create a request and add the certificate ID to it:</p>

<pre class="ruby"><span class="ruby-identifier">request</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">OCSP</span><span class="ruby-operator">::</span><span class="ruby-constant">Request</span>.<span class="ruby-identifier">new</span>
<span class="ruby-identifier">request</span>.<span class="ruby-identifier">add_certid</span> <span class="ruby-identifier">certificate_id</span>
</pre>

<p>Adding a nonce to the request protects against replay attacks but not all CA process the nonce.</p>

<pre class="ruby"><span class="ruby-identifier">request</span>.<span class="ruby-identifier">add_nonce</span>
</pre>

<p>To submit the request to the CA for verification we need to extract the <a href="OCSP.html"><code>OCSP</code></a> URI from the subject certificate:</p>

<pre class="ruby"><span class="ruby-identifier">ocsp_uris</span> = <span class="ruby-identifier">subject</span>.<span class="ruby-identifier">ocsp_uris</span>

<span class="ruby-identifier">require</span> <span class="ruby-string">&#39;uri&#39;</span>

<span class="ruby-identifier">ocsp_uri</span> = <span class="ruby-constant">URI</span> <span class="ruby-identifier">ocsp_uris</span>[<span class="ruby-value">0</span>]
</pre>

<p>To submit the request we’ll POST the request to the <a href="OCSP.html"><code>OCSP</code></a> 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.</p>

<pre class="ruby"><span class="ruby-identifier">require</span> <span class="ruby-string">&#39;net/http&#39;</span>

<span class="ruby-identifier">http_response</span> =
  <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTP</span>.<span class="ruby-identifier">start</span> <span class="ruby-identifier">ocsp_uri</span>.<span class="ruby-identifier">hostname</span>, <span class="ruby-identifier">ocsp</span>.<span class="ruby-identifier">port</span> <span class="ruby-keyword">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">http</span><span class="ruby-operator">|</span>
    <span class="ruby-identifier">http</span>.<span class="ruby-identifier">post</span> <span class="ruby-identifier">ocsp_uri</span>.<span class="ruby-identifier">path</span>, <span class="ruby-identifier">request</span>.<span class="ruby-identifier">to_der</span>,
              <span class="ruby-string">&#39;content-type&#39;</span> <span class="ruby-operator">=&gt;</span> <span class="ruby-string">&#39;application/ocsp-request&#39;</span>
<span class="ruby-keyword">end</span>

<span class="ruby-identifier">response</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">OCSP</span><span class="ruby-operator">::</span><span class="ruby-constant">Response</span>.<span class="ruby-identifier">new</span> <span class="ruby-identifier">http_response</span>.<span class="ruby-identifier">body</span>
<span class="ruby-identifier">response_basic</span> = <span class="ruby-identifier">response</span>.<span class="ruby-identifier">basic</span>
</pre>

<p>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.</p>

<pre class="ruby"><span class="ruby-identifier">store</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">X509</span><span class="ruby-operator">::</span><span class="ruby-constant">Store</span>.<span class="ruby-identifier">new</span>
<span class="ruby-identifier">store</span>.<span class="ruby-identifier">set_default_paths</span>

<span class="ruby-keyword">unless</span> <span class="ruby-identifier">response_basic</span>.<span class="ruby-identifier">verify</span> [], <span class="ruby-identifier">store</span> <span class="ruby-keyword">then</span>
  <span class="ruby-identifier">raise</span> <span class="ruby-string">&#39;response is not signed by a trusted certificate&#39;</span>
<span class="ruby-keyword">end</span>
</pre>

<p>The response contains the status information (success/fail).  We can display the status as a string:</p>

<pre class="ruby"><span class="ruby-identifier">puts</span> <span class="ruby-identifier">response</span>.<span class="ruby-identifier">status_string</span> <span class="ruby-comment">#=&gt; successful</span>
</pre>

<p>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 <a href="OCSP/Request.html#method-i-check_nonce"><code>Request#check_nonce</code></a> for the meanings of the return values.</p>

<pre class="ruby"><span class="ruby-identifier">p</span> <span class="ruby-identifier">request</span>.<span class="ruby-identifier">check_nonce</span> <span class="ruby-identifier">basic_response</span> <span class="ruby-comment">#=&gt; value from -1 to 3</span>
</pre>

<p>Then extract the status information for the certificate from the basic response.</p>

<pre class="ruby"><span class="ruby-identifier">single_response</span> = <span class="ruby-identifier">basic_response</span>.<span class="ruby-identifier">find_response</span>(<span class="ruby-identifier">certificate_id</span>)

<span class="ruby-keyword">unless</span> <span class="ruby-identifier">single_response</span>
  <span class="ruby-identifier">raise</span> <span class="ruby-string">&#39;basic_response does not have the status for the certificiate&#39;</span>
<span class="ruby-keyword">end</span>
</pre>

<p>Then check the validity. A status issued in the future must be rejected.</p>

<pre>unless single_response.check_validity
  raise &#39;this_update is in the future or next_update time has passed&#39;
end

case single_response.cert_status
when OpenSSL::OCSP::V_CERTSTATUS_GOOD
  puts &#39;certificate is still valid&#39;
when OpenSSL::OCSP::V_CERTSTATUS_REVOKED
  puts &quot;certificate has been revoked at #{single_response.revocation_time}&quot;
when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
  puts &#39;responder doesn&#39;t know about the certificate&#39;
end</pre>

  </section>

  <section id="5Buntitled-5D" class="documentation-section">


    <section class="constants-list">
      <header>
        <h3>Constants</h3>
      </header>
      <dl>
        <dt id="NOCASIGN">NOCASIGN
        <dd><p>(This flag is not used by <a href="../OpenSSL.html"><code>OpenSSL</code></a> 1.0.1g)</p>
        <dt id="NOCERTS">NOCERTS
        <dd><p>Do not include certificates in the response</p>
        <dt id="NOCHAIN">NOCHAIN
        <dd><p>Do not verify the certificate chain on the response</p>
        <dt id="NOCHECKS">NOCHECKS
        <dd><p>Do not make additional signing certificate checks</p>
        <dt id="NODELEGATED">NODELEGATED
        <dd><p>(This flag is not used by <a href="../OpenSSL.html"><code>OpenSSL</code></a> 1.0.1g)</p>
        <dt id="NOEXPLICIT">NOEXPLICIT
        <dd><p>Do not check trust</p>
        <dt id="NOINTERN">NOINTERN
        <dd><p>Do not search certificates contained in the response for a signer</p>
        <dt id="NOSIGS">NOSIGS
        <dd><p>Do not check the signature on the response</p>
        <dt id="NOTIME">NOTIME
        <dd><p>Do not include producedAt time in response</p>
        <dt id="NOVERIFY">NOVERIFY
        <dd><p>Do not verify the response at all</p>
        <dt id="RESPID_KEY">RESPID_KEY
        <dd><p>Identify the response by signing the certificate key ID</p>
        <dt id="RESPONSE_STATUS_INTERNALERROR">RESPONSE_STATUS_INTERNALERROR
        <dd><p>Internal error in issuer</p>
        <dt id="RESPONSE_STATUS_MALFORMEDREQUEST">RESPONSE_STATUS_MALFORMEDREQUEST
        <dd><p>Illegal confirmation request</p>
        <dt id="RESPONSE_STATUS_SIGREQUIRED">RESPONSE_STATUS_SIGREQUIRED
        <dd><p>You must sign the request and resubmit</p>
        <dt id="RESPONSE_STATUS_SUCCESSFUL">RESPONSE_STATUS_SUCCESSFUL
        <dd><p><a href="OCSP/Response.html"><code>Response</code></a> has valid confirmations</p>
        <dt id="RESPONSE_STATUS_TRYLATER">RESPONSE_STATUS_TRYLATER
        <dd><p>Try again later</p>
        <dt id="RESPONSE_STATUS_UNAUTHORIZED">RESPONSE_STATUS_UNAUTHORIZED
        <dd><p>Your request is unauthorized.</p>
        <dt id="REVOKED_STATUS_AFFILIATIONCHANGED">REVOKED_STATUS_AFFILIATIONCHANGED
        <dd><p>The certificate subject’s name or other information changed</p>
        <dt id="REVOKED_STATUS_CACOMPROMISE">REVOKED_STATUS_CACOMPROMISE
        <dd><p>This CA certificate was revoked due to a key compromise</p>
        <dt id="REVOKED_STATUS_CERTIFICATEHOLD">REVOKED_STATUS_CERTIFICATEHOLD
        <dd><p>The certificate is on hold</p>
        <dt id="REVOKED_STATUS_CESSATIONOFOPERATION">REVOKED_STATUS_CESSATIONOFOPERATION
        <dd><p>The certificate is no longer needed</p>
        <dt id="REVOKED_STATUS_KEYCOMPROMISE">REVOKED_STATUS_KEYCOMPROMISE
        <dd><p>The certificate was revoked due to a key compromise</p>
        <dt id="REVOKED_STATUS_NOSTATUS">REVOKED_STATUS_NOSTATUS
        <dd><p>The certificate was revoked for an unknown reason</p>
        <dt id="REVOKED_STATUS_REMOVEFROMCRL">REVOKED_STATUS_REMOVEFROMCRL
        <dd><p>The certificate was previously on hold and should now be removed from the CRL</p>
        <dt id="REVOKED_STATUS_SUPERSEDED">REVOKED_STATUS_SUPERSEDED
        <dd><p>The certificate was superseded by a new certificate</p>
        <dt id="REVOKED_STATUS_UNSPECIFIED">REVOKED_STATUS_UNSPECIFIED
        <dd><p>The certificate was revoked for an unspecified reason</p>
        <dt id="TRUSTOTHER">TRUSTOTHER
        <dd><p>Do not verify additional certificates</p>
        <dt id="V_CERTSTATUS_GOOD">V_CERTSTATUS_GOOD
        <dd><p>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</p>
        <dt id="V_CERTSTATUS_REVOKED">V_CERTSTATUS_REVOKED
        <dd><p>Indicates the certificate has been revoked either permanently or temporarily (on hold).</p>
        <dt id="V_CERTSTATUS_UNKNOWN">V_CERTSTATUS_UNKNOWN
        <dd><p>Indicates the responder does not know about the certificate being requested.</p>
        <dt id="V_RESPID_KEY">V_RESPID_KEY
        <dd><p>The responder ID is based on the public key.</p>
        <dt id="V_RESPID_NAME">V_RESPID_NAME
        <dd><p>The responder ID is based on the key name.</p>
      </dl>
    </section>



  </section>
</main>


<footer id="validator-badges" role="contentinfo">
  <p><a href="https://validator.w3.org/check/referer">Validate</a>
  <p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> 6.3.2.
  <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
</footer>