/rust/registry/src/index.crates.io-1949cf8c6b5b557f/openssl-0.10.62/src/ocsp.rs
Line | Count | Source |
1 | | use bitflags::bitflags; |
2 | | use foreign_types::ForeignTypeRef; |
3 | | use libc::{c_int, c_long, c_ulong}; |
4 | | use std::mem; |
5 | | use std::ptr; |
6 | | |
7 | | use crate::asn1::Asn1GeneralizedTimeRef; |
8 | | use crate::error::ErrorStack; |
9 | | use crate::hash::MessageDigest; |
10 | | use crate::stack::StackRef; |
11 | | use crate::util::ForeignTypeRefExt; |
12 | | use crate::x509::store::X509StoreRef; |
13 | | use crate::x509::{X509Ref, X509}; |
14 | | use crate::{cvt, cvt_p}; |
15 | | use openssl_macros::corresponds; |
16 | | |
17 | | bitflags! { |
18 | | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] |
19 | | #[repr(transparent)] |
20 | | pub struct OcspFlag: c_ulong { |
21 | | const NO_CERTS = ffi::OCSP_NOCERTS; |
22 | | const NO_INTERN = ffi::OCSP_NOINTERN; |
23 | | const NO_CHAIN = ffi::OCSP_NOCHAIN; |
24 | | const NO_VERIFY = ffi::OCSP_NOVERIFY; |
25 | | const NO_EXPLICIT = ffi::OCSP_NOEXPLICIT; |
26 | | const NO_CA_SIGN = ffi::OCSP_NOCASIGN; |
27 | | const NO_DELEGATED = ffi::OCSP_NODELEGATED; |
28 | | const NO_CHECKS = ffi::OCSP_NOCHECKS; |
29 | | const TRUST_OTHER = ffi::OCSP_TRUSTOTHER; |
30 | | const RESPID_KEY = ffi::OCSP_RESPID_KEY; |
31 | | const NO_TIME = ffi::OCSP_NOTIME; |
32 | | } |
33 | | } |
34 | | |
35 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
36 | | pub struct OcspResponseStatus(c_int); |
37 | | |
38 | | impl OcspResponseStatus { |
39 | | pub const SUCCESSFUL: OcspResponseStatus = |
40 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); |
41 | | pub const MALFORMED_REQUEST: OcspResponseStatus = |
42 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); |
43 | | pub const INTERNAL_ERROR: OcspResponseStatus = |
44 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); |
45 | | pub const TRY_LATER: OcspResponseStatus = |
46 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); |
47 | | pub const SIG_REQUIRED: OcspResponseStatus = |
48 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); |
49 | | pub const UNAUTHORIZED: OcspResponseStatus = |
50 | | OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); |
51 | | |
52 | 0 | pub fn from_raw(raw: c_int) -> OcspResponseStatus { |
53 | 0 | OcspResponseStatus(raw) |
54 | 0 | } |
55 | | |
56 | | #[allow(clippy::trivially_copy_pass_by_ref)] |
57 | 0 | pub fn as_raw(&self) -> c_int { |
58 | 0 | self.0 |
59 | 0 | } |
60 | | } |
61 | | |
62 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
63 | | pub struct OcspCertStatus(c_int); |
64 | | |
65 | | impl OcspCertStatus { |
66 | | pub const GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); |
67 | | pub const REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); |
68 | | pub const UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); |
69 | | |
70 | 0 | pub fn from_raw(raw: c_int) -> OcspCertStatus { |
71 | 0 | OcspCertStatus(raw) |
72 | 0 | } |
73 | | |
74 | | #[allow(clippy::trivially_copy_pass_by_ref)] |
75 | 0 | pub fn as_raw(&self) -> c_int { |
76 | 0 | self.0 |
77 | 0 | } |
78 | | } |
79 | | |
80 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
81 | | pub struct OcspRevokedStatus(c_int); |
82 | | |
83 | | impl OcspRevokedStatus { |
84 | | pub const NO_STATUS: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); |
85 | | pub const UNSPECIFIED: OcspRevokedStatus = |
86 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); |
87 | | pub const KEY_COMPROMISE: OcspRevokedStatus = |
88 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); |
89 | | pub const CA_COMPROMISE: OcspRevokedStatus = |
90 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); |
91 | | pub const AFFILIATION_CHANGED: OcspRevokedStatus = |
92 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); |
93 | | pub const STATUS_SUPERSEDED: OcspRevokedStatus = |
94 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); |
95 | | pub const STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = |
96 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); |
97 | | pub const STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = |
98 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); |
99 | | pub const REMOVE_FROM_CRL: OcspRevokedStatus = |
100 | | OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); |
101 | | |
102 | 0 | pub fn from_raw(raw: c_int) -> OcspRevokedStatus { |
103 | 0 | OcspRevokedStatus(raw) |
104 | 0 | } |
105 | | |
106 | | #[allow(clippy::trivially_copy_pass_by_ref)] |
107 | 0 | pub fn as_raw(&self) -> c_int { |
108 | 0 | self.0 |
109 | 0 | } |
110 | | } |
111 | | |
112 | | pub struct OcspStatus<'a> { |
113 | | /// The overall status of the response. |
114 | | pub status: OcspCertStatus, |
115 | | /// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation. |
116 | | pub reason: OcspRevokedStatus, |
117 | | /// If `status` is `CERT_STATUS_REVOKED`, the time at which the certificate was revoked. |
118 | | pub revocation_time: Option<&'a Asn1GeneralizedTimeRef>, |
119 | | /// The time that this revocation check was performed. |
120 | | pub this_update: &'a Asn1GeneralizedTimeRef, |
121 | | /// The time at which this revocation check expires. |
122 | | pub next_update: &'a Asn1GeneralizedTimeRef, |
123 | | } |
124 | | |
125 | | impl<'a> OcspStatus<'a> { |
126 | | /// Checks validity of the `this_update` and `next_update` fields. |
127 | | /// |
128 | | /// The `nsec` parameter specifies an amount of slack time that will be used when comparing |
129 | | /// those times with the current time to account for delays and clock skew. |
130 | | /// |
131 | | /// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit |
132 | | /// very old responses. |
133 | | #[corresponds(OCSP_check_validity)] |
134 | 0 | pub fn check_validity(&self, nsec: u32, maxsec: Option<u32>) -> Result<(), ErrorStack> { |
135 | | unsafe { |
136 | 0 | cvt(ffi::OCSP_check_validity( |
137 | 0 | self.this_update.as_ptr(), |
138 | 0 | self.next_update.as_ptr(), |
139 | 0 | nsec as c_long, |
140 | 0 | maxsec.map(|n| n as c_long).unwrap_or(-1), |
141 | | )) |
142 | 0 | .map(|_| ()) |
143 | | } |
144 | 0 | } |
145 | | } |
146 | | |
147 | | foreign_type_and_impl_send_sync! { |
148 | | type CType = ffi::OCSP_BASICRESP; |
149 | | fn drop = ffi::OCSP_BASICRESP_free; |
150 | | |
151 | | pub struct OcspBasicResponse; |
152 | | pub struct OcspBasicResponseRef; |
153 | | } |
154 | | |
155 | | impl OcspBasicResponseRef { |
156 | | /// Verifies the validity of the response. |
157 | | /// |
158 | | /// The `certs` parameter contains a set of certificates that will be searched when locating the |
159 | | /// OCSP response signing certificate. Some responders do not include this in the response. |
160 | | #[corresponds(OCSP_basic_verify)] |
161 | 0 | pub fn verify( |
162 | 0 | &self, |
163 | 0 | certs: &StackRef<X509>, |
164 | 0 | store: &X509StoreRef, |
165 | 0 | flags: OcspFlag, |
166 | 0 | ) -> Result<(), ErrorStack> { |
167 | | unsafe { |
168 | 0 | cvt(ffi::OCSP_basic_verify( |
169 | 0 | self.as_ptr(), |
170 | 0 | certs.as_ptr(), |
171 | 0 | store.as_ptr(), |
172 | 0 | flags.bits(), |
173 | | )) |
174 | 0 | .map(|_| ()) |
175 | | } |
176 | 0 | } |
177 | | |
178 | | /// Looks up the status for the specified certificate ID. |
179 | | #[corresponds(OCSP_resp_find_status)] |
180 | 0 | pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option<OcspStatus<'a>> { |
181 | | unsafe { |
182 | 0 | let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN; |
183 | 0 | let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS; |
184 | 0 | let mut revocation_time = ptr::null_mut(); |
185 | 0 | let mut this_update = ptr::null_mut(); |
186 | 0 | let mut next_update = ptr::null_mut(); |
187 | | |
188 | 0 | let r = ffi::OCSP_resp_find_status( |
189 | 0 | self.as_ptr(), |
190 | 0 | id.as_ptr(), |
191 | 0 | &mut status, |
192 | 0 | &mut reason, |
193 | 0 | &mut revocation_time, |
194 | 0 | &mut this_update, |
195 | 0 | &mut next_update, |
196 | | ); |
197 | 0 | if r == 1 { |
198 | 0 | let revocation_time = Asn1GeneralizedTimeRef::from_const_ptr_opt(revocation_time); |
199 | | |
200 | 0 | Some(OcspStatus { |
201 | 0 | status: OcspCertStatus(status), |
202 | 0 | reason: OcspRevokedStatus(status), |
203 | 0 | revocation_time, |
204 | 0 | this_update: Asn1GeneralizedTimeRef::from_ptr(this_update), |
205 | 0 | next_update: Asn1GeneralizedTimeRef::from_ptr(next_update), |
206 | 0 | }) |
207 | | } else { |
208 | 0 | None |
209 | | } |
210 | | } |
211 | 0 | } |
212 | | } |
213 | | |
214 | | foreign_type_and_impl_send_sync! { |
215 | | type CType = ffi::OCSP_CERTID; |
216 | | fn drop = ffi::OCSP_CERTID_free; |
217 | | |
218 | | pub struct OcspCertId; |
219 | | pub struct OcspCertIdRef; |
220 | | } |
221 | | |
222 | | impl OcspCertId { |
223 | | /// Constructs a certificate ID for certificate `subject`. |
224 | | #[corresponds(OCSP_cert_to_id)] |
225 | 0 | pub fn from_cert( |
226 | 0 | digest: MessageDigest, |
227 | 0 | subject: &X509Ref, |
228 | 0 | issuer: &X509Ref, |
229 | 0 | ) -> Result<OcspCertId, ErrorStack> { |
230 | | unsafe { |
231 | 0 | cvt_p(ffi::OCSP_cert_to_id( |
232 | 0 | digest.as_ptr(), |
233 | 0 | subject.as_ptr(), |
234 | 0 | issuer.as_ptr(), |
235 | | )) |
236 | 0 | .map(OcspCertId) |
237 | | } |
238 | 0 | } |
239 | | } |
240 | | |
241 | | foreign_type_and_impl_send_sync! { |
242 | | type CType = ffi::OCSP_RESPONSE; |
243 | | fn drop = ffi::OCSP_RESPONSE_free; |
244 | | |
245 | | pub struct OcspResponse; |
246 | | pub struct OcspResponseRef; |
247 | | } |
248 | | |
249 | | impl OcspResponse { |
250 | | /// Creates an OCSP response from the status and optional body. |
251 | | /// |
252 | | /// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`. |
253 | | #[corresponds(OCSP_response_create)] |
254 | 0 | pub fn create( |
255 | 0 | status: OcspResponseStatus, |
256 | 0 | body: Option<&OcspBasicResponseRef>, |
257 | 0 | ) -> Result<OcspResponse, ErrorStack> { |
258 | | unsafe { |
259 | 0 | ffi::init(); |
260 | | |
261 | 0 | cvt_p(ffi::OCSP_response_create( |
262 | 0 | status.as_raw(), |
263 | 0 | body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()), |
264 | | )) |
265 | 0 | .map(OcspResponse) |
266 | | } |
267 | 0 | } |
268 | | |
269 | | from_der! { |
270 | | /// Deserializes a DER-encoded OCSP response. |
271 | | #[corresponds(d2i_OCSP_RESPONSE)] |
272 | | from_der, |
273 | | OcspResponse, |
274 | | ffi::d2i_OCSP_RESPONSE |
275 | | } |
276 | | } |
277 | | |
278 | | impl OcspResponseRef { |
279 | | to_der! { |
280 | | /// Serializes the response to its standard DER encoding. |
281 | | #[corresponds(i2d_OCSP_RESPONSE)] |
282 | | to_der, |
283 | | ffi::i2d_OCSP_RESPONSE |
284 | | } |
285 | | |
286 | | /// Returns the status of the response. |
287 | | #[corresponds(OCSP_response_status)] |
288 | 0 | pub fn status(&self) -> OcspResponseStatus { |
289 | 0 | unsafe { OcspResponseStatus(ffi::OCSP_response_status(self.as_ptr())) } |
290 | 0 | } |
291 | | |
292 | | /// Returns the basic response. |
293 | | /// |
294 | | /// This will only succeed if `status()` returns `RESPONSE_STATUS_SUCCESSFUL`. |
295 | | #[corresponds(OCSP_response_get1_basic)] |
296 | 0 | pub fn basic(&self) -> Result<OcspBasicResponse, ErrorStack> { |
297 | 0 | unsafe { cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse) } |
298 | 0 | } |
299 | | } |
300 | | |
301 | | foreign_type_and_impl_send_sync! { |
302 | | type CType = ffi::OCSP_REQUEST; |
303 | | fn drop = ffi::OCSP_REQUEST_free; |
304 | | |
305 | | pub struct OcspRequest; |
306 | | pub struct OcspRequestRef; |
307 | | } |
308 | | |
309 | | impl OcspRequest { |
310 | | #[corresponds(OCSP_REQUEST_new)] |
311 | 0 | pub fn new() -> Result<OcspRequest, ErrorStack> { |
312 | | unsafe { |
313 | 0 | ffi::init(); |
314 | | |
315 | 0 | cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest) |
316 | | } |
317 | 0 | } |
318 | | |
319 | | from_der! { |
320 | | /// Deserializes a DER-encoded OCSP request. |
321 | | #[corresponds(d2i_OCSP_REQUEST)] |
322 | | from_der, |
323 | | OcspRequest, |
324 | | ffi::d2i_OCSP_REQUEST |
325 | | } |
326 | | } |
327 | | |
328 | | impl OcspRequestRef { |
329 | | to_der! { |
330 | | /// Serializes the request to its standard DER encoding. |
331 | | #[corresponds(i2d_OCSP_REQUEST)] |
332 | | to_der, |
333 | | ffi::i2d_OCSP_REQUEST |
334 | | } |
335 | | |
336 | | #[corresponds(OCSP_request_add0_id)] |
337 | 0 | pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> { |
338 | | unsafe { |
339 | 0 | let ptr = cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr()))?; |
340 | 0 | mem::forget(id); |
341 | 0 | Ok(OcspOneReqRef::from_ptr_mut(ptr)) |
342 | | } |
343 | 0 | } |
344 | | } |
345 | | |
346 | | foreign_type_and_impl_send_sync! { |
347 | | type CType = ffi::OCSP_ONEREQ; |
348 | | fn drop = ffi::OCSP_ONEREQ_free; |
349 | | |
350 | | pub struct OcspOneReq; |
351 | | pub struct OcspOneReqRef; |
352 | | } |