• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The standard defining the format of public key certificates.
2 //!
3 //! An `X509` certificate binds an identity to a public key, and is either
4 //! signed by a certificate authority (CA) or self-signed. An entity that gets
5 //! a hold of a certificate can both verify your identity (via a CA) and encrypt
6 //! data with the included public key. `X509` certificates are used in many
7 //! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
8 //! the secure protocol for browsing the web.
9 
10 use cfg_if::cfg_if;
11 use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
12 use libc::{c_int, c_long, c_uint, c_void};
13 use std::cmp::{self, Ordering};
14 use std::convert::{TryFrom, TryInto};
15 use std::error::Error;
16 use std::ffi::{CStr, CString};
17 use std::fmt;
18 use std::marker::PhantomData;
19 use std::mem;
20 use std::net::IpAddr;
21 use std::path::Path;
22 use std::ptr;
23 use std::slice;
24 use std::str;
25 
26 use crate::asn1::{
27     Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef,
28     Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type,
29 };
30 use crate::bio::MemBioSlice;
31 use crate::conf::ConfRef;
32 use crate::error::ErrorStack;
33 use crate::ex_data::Index;
34 use crate::hash::{DigestBytes, MessageDigest};
35 use crate::nid::Nid;
36 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
37 use crate::ssl::SslRef;
38 use crate::stack::{Stack, StackRef, Stackable};
39 use crate::string::OpensslString;
40 use crate::util::{ForeignTypeExt, ForeignTypeRefExt};
41 use crate::{cvt, cvt_n, cvt_p};
42 use openssl_macros::corresponds;
43 
44 #[cfg(any(ossl102, libressl261))]
45 pub mod verify;
46 
47 pub mod extension;
48 pub mod store;
49 
50 #[cfg(test)]
51 mod tests;
52 
53 /// A type of X509 extension.
54 ///
55 /// # Safety
56 /// The value of NID and Output must match those in OpenSSL so that
57 /// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid.
58 pub unsafe trait ExtensionType {
59     const NID: Nid;
60     type Output: ForeignType;
61 }
62 
63 foreign_type_and_impl_send_sync! {
64     type CType = ffi::X509_STORE_CTX;
65     fn drop = ffi::X509_STORE_CTX_free;
66 
67     /// An `X509` certificate store context.
68     pub struct X509StoreContext;
69 
70     /// A reference to an [`X509StoreContext`].
71     pub struct X509StoreContextRef;
72 }
73 
74 impl X509StoreContext {
75     /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
76     /// context.
77     #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>78     pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
79         unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
80     }
81 
82     /// Creates a new `X509StoreContext` instance.
83     #[corresponds(X509_STORE_CTX_new)]
new() -> Result<X509StoreContext, ErrorStack>84     pub fn new() -> Result<X509StoreContext, ErrorStack> {
85         unsafe {
86             ffi::init();
87             cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
88         }
89     }
90 }
91 
92 impl X509StoreContextRef {
93     /// Returns application data pertaining to an `X509` store context.
94     #[corresponds(X509_STORE_CTX_get_ex_data)]
ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>95     pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
96         unsafe {
97             let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
98             if data.is_null() {
99                 None
100             } else {
101                 Some(&*(data as *const T))
102             }
103         }
104     }
105 
106     /// Returns the error code of the context.
107     #[corresponds(X509_STORE_CTX_get_error)]
error(&self) -> X509VerifyResult108     pub fn error(&self) -> X509VerifyResult {
109         unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
110     }
111 
112     /// Initializes this context with the given certificate, certificates chain and certificate
113     /// store. After initializing the context, the `with_context` closure is called with the prepared
114     /// context. As long as the closure is running, the context stays initialized and can be used
115     /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
116     ///
117     /// * `trust` - The certificate store with the trusted certificates.
118     /// * `cert` - The certificate that should be verified.
119     /// * `cert_chain` - The certificates chain.
120     /// * `with_context` - The closure that is called with the initialized context.
121     ///
122     /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
123     /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
124     ///
125     /// [`X509_STORE_CTX_init`]:  https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html
126     /// [`X509_STORE_CTX_cleanup`]:  https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_cleanup.html
init<F, T>( &mut self, trust: &store::X509StoreRef, cert: &X509Ref, cert_chain: &StackRef<X509>, with_context: F, ) -> Result<T, ErrorStack> where F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,127     pub fn init<F, T>(
128         &mut self,
129         trust: &store::X509StoreRef,
130         cert: &X509Ref,
131         cert_chain: &StackRef<X509>,
132         with_context: F,
133     ) -> Result<T, ErrorStack>
134     where
135         F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
136     {
137         struct Cleanup<'a>(&'a mut X509StoreContextRef);
138 
139         impl<'a> Drop for Cleanup<'a> {
140             fn drop(&mut self) {
141                 unsafe {
142                     ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
143                 }
144             }
145         }
146 
147         unsafe {
148             cvt(ffi::X509_STORE_CTX_init(
149                 self.as_ptr(),
150                 trust.as_ptr(),
151                 cert.as_ptr(),
152                 cert_chain.as_ptr(),
153             ))?;
154 
155             let cleanup = Cleanup(self);
156             with_context(cleanup.0)
157         }
158     }
159 
160     /// Verifies the stored certificate.
161     ///
162     /// Returns `true` if verification succeeds. The `error` method will return the specific
163     /// validation error if the certificate was not valid.
164     ///
165     /// This will only work inside of a call to `init`.
166     #[corresponds(X509_verify_cert)]
verify_cert(&mut self) -> Result<bool, ErrorStack>167     pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
168         unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
169     }
170 
171     /// Set the error code of the context.
172     #[corresponds(X509_STORE_CTX_set_error)]
set_error(&mut self, result: X509VerifyResult)173     pub fn set_error(&mut self, result: X509VerifyResult) {
174         unsafe {
175             ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
176         }
177     }
178 
179     /// Returns a reference to the certificate which caused the error or None if
180     /// no certificate is relevant to the error.
181     #[corresponds(X509_STORE_CTX_get_current_cert)]
current_cert(&self) -> Option<&X509Ref>182     pub fn current_cert(&self) -> Option<&X509Ref> {
183         unsafe {
184             let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
185             X509Ref::from_const_ptr_opt(ptr)
186         }
187     }
188 
189     /// Returns a non-negative integer representing the depth in the certificate
190     /// chain where the error occurred. If it is zero it occurred in the end
191     /// entity certificate, one if it is the certificate which signed the end
192     /// entity certificate and so on.
193     #[corresponds(X509_STORE_CTX_get_error_depth)]
error_depth(&self) -> u32194     pub fn error_depth(&self) -> u32 {
195         unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
196     }
197 
198     /// Returns a reference to a complete valid `X509` certificate chain.
199     #[corresponds(X509_STORE_CTX_get0_chain)]
chain(&self) -> Option<&StackRef<X509>>200     pub fn chain(&self) -> Option<&StackRef<X509>> {
201         unsafe {
202             let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
203 
204             if chain.is_null() {
205                 None
206             } else {
207                 Some(StackRef::from_ptr(chain))
208             }
209         }
210     }
211 }
212 
213 /// A builder used to construct an `X509`.
214 pub struct X509Builder(X509);
215 
216 impl X509Builder {
217     /// Creates a new builder.
218     #[corresponds(X509_new)]
new() -> Result<X509Builder, ErrorStack>219     pub fn new() -> Result<X509Builder, ErrorStack> {
220         unsafe {
221             ffi::init();
222             cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
223         }
224     }
225 
226     /// Sets the notAfter constraint on the certificate.
227     #[corresponds(X509_set1_notAfter)]
set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>228     pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
229         unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
230     }
231 
232     /// Sets the notBefore constraint on the certificate.
233     #[corresponds(X509_set1_notBefore)]
set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>234     pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
235         unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
236     }
237 
238     /// Sets the version of the certificate.
239     ///
240     /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
241     /// the X.509 standard should pass `2` to this method.
242     #[corresponds(X509_set_version)]
243     #[allow(clippy::useless_conversion)]
set_version(&mut self, version: i32) -> Result<(), ErrorStack>244     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
245         unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
246     }
247 
248     /// Sets the serial number of the certificate.
249     #[corresponds(X509_set_serialNumber)]
set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>250     pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
251         unsafe {
252             cvt(ffi::X509_set_serialNumber(
253                 self.0.as_ptr(),
254                 serial_number.as_ptr(),
255             ))
256             .map(|_| ())
257         }
258     }
259 
260     /// Sets the issuer name of the certificate.
261     #[corresponds(X509_set_issuer_name)]
set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack>262     pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
263         unsafe {
264             cvt(ffi::X509_set_issuer_name(
265                 self.0.as_ptr(),
266                 issuer_name.as_ptr(),
267             ))
268             .map(|_| ())
269         }
270     }
271 
272     /// Sets the subject name of the certificate.
273     ///
274     /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools.
275     /// The `CN` field is used for the common name, such as a DNS name.
276     ///
277     /// ```
278     /// use openssl::x509::{X509, X509NameBuilder};
279     ///
280     /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap();
281     /// x509_name.append_entry_by_text("C", "US").unwrap();
282     /// x509_name.append_entry_by_text("ST", "CA").unwrap();
283     /// x509_name.append_entry_by_text("O", "Some organization").unwrap();
284     /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap();
285     /// let x509_name = x509_name.build();
286     ///
287     /// let mut x509 = openssl::x509::X509::builder().unwrap();
288     /// x509.set_subject_name(&x509_name).unwrap();
289     /// ```
290     #[corresponds(X509_set_subject_name)]
set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>291     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
292         unsafe {
293             cvt(ffi::X509_set_subject_name(
294                 self.0.as_ptr(),
295                 subject_name.as_ptr(),
296             ))
297             .map(|_| ())
298         }
299     }
300 
301     /// Sets the public key associated with the certificate.
302     #[corresponds(X509_set_pubkey)]
set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,303     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
304     where
305         T: HasPublic,
306     {
307         unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
308     }
309 
310     /// Returns a context object which is needed to create certain X509 extension values.
311     ///
312     /// Set `issuer` to `None` if the certificate will be self-signed.
313     #[corresponds(X509V3_set_ctx)]
x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>314     pub fn x509v3_context<'a>(
315         &'a self,
316         issuer: Option<&'a X509Ref>,
317         conf: Option<&'a ConfRef>,
318     ) -> X509v3Context<'a> {
319         unsafe {
320             let mut ctx = mem::zeroed();
321 
322             let issuer = match issuer {
323                 Some(issuer) => issuer.as_ptr(),
324                 None => self.0.as_ptr(),
325             };
326             let subject = self.0.as_ptr();
327             ffi::X509V3_set_ctx(
328                 &mut ctx,
329                 issuer,
330                 subject,
331                 ptr::null_mut(),
332                 ptr::null_mut(),
333                 0,
334             );
335 
336             // nodb case taken care of since we zeroed ctx above
337             if let Some(conf) = conf {
338                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
339             }
340 
341             X509v3Context(ctx, PhantomData)
342         }
343     }
344 
345     /// Adds an X509 extension value to the certificate.
346     ///
347     /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>348     pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
349         self.append_extension2(&extension)
350     }
351 
352     /// Adds an X509 extension value to the certificate.
353     #[corresponds(X509_add_ext)]
append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack>354     pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
355         unsafe {
356             cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
357             Ok(())
358         }
359     }
360 
361     /// Signs the certificate with a private key.
362     #[corresponds(X509_sign)]
sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,363     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
364     where
365         T: HasPrivate,
366     {
367         unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
368     }
369 
370     /// Consumes the builder, returning the certificate.
build(self) -> X509371     pub fn build(self) -> X509 {
372         self.0
373     }
374 }
375 
376 foreign_type_and_impl_send_sync! {
377     type CType = ffi::X509;
378     fn drop = ffi::X509_free;
379 
380     /// An `X509` public key certificate.
381     pub struct X509;
382     /// Reference to `X509`.
383     pub struct X509Ref;
384 }
385 
386 #[cfg(boringssl)]
387 type X509LenTy = c_uint;
388 #[cfg(not(boringssl))]
389 type X509LenTy = c_int;
390 
391 impl X509Ref {
392     /// Returns this certificate's subject name.
393     #[corresponds(X509_get_subject_name)]
subject_name(&self) -> &X509NameRef394     pub fn subject_name(&self) -> &X509NameRef {
395         unsafe {
396             let name = ffi::X509_get_subject_name(self.as_ptr());
397             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
398         }
399     }
400 
401     /// Returns the hash of the certificates subject
402     #[corresponds(X509_subject_name_hash)]
subject_name_hash(&self) -> u32403     pub fn subject_name_hash(&self) -> u32 {
404         #[allow(clippy::unnecessary_cast)]
405         unsafe {
406             ffi::X509_subject_name_hash(self.as_ptr()) as u32
407         }
408     }
409 
410     /// Returns this certificate's issuer name.
411     #[corresponds(X509_get_issuer_name)]
issuer_name(&self) -> &X509NameRef412     pub fn issuer_name(&self) -> &X509NameRef {
413         unsafe {
414             let name = ffi::X509_get_issuer_name(self.as_ptr());
415             X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
416         }
417     }
418 
419     /// Returns the hash of the certificates issuer
420     #[corresponds(X509_issuer_name_hash)]
issuer_name_hash(&self) -> u32421     pub fn issuer_name_hash(&self) -> u32 {
422         #[allow(clippy::unnecessary_cast)]
423         unsafe {
424             ffi::X509_issuer_name_hash(self.as_ptr()) as u32
425         }
426     }
427 
428     /// Returns this certificate's subject alternative name entries, if they exist.
429     #[corresponds(X509_get_ext_d2i)]
subject_alt_names(&self) -> Option<Stack<GeneralName>>430     pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
431         unsafe {
432             let stack = ffi::X509_get_ext_d2i(
433                 self.as_ptr(),
434                 ffi::NID_subject_alt_name,
435                 ptr::null_mut(),
436                 ptr::null_mut(),
437             );
438             Stack::from_ptr_opt(stack as *mut _)
439         }
440     }
441 
442     /// Returns this certificate's CRL distribution points, if they exist.
443     #[corresponds(X509_get_ext_d2i)]
crl_distribution_points(&self) -> Option<Stack<DistPoint>>444     pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> {
445         unsafe {
446             let stack = ffi::X509_get_ext_d2i(
447                 self.as_ptr(),
448                 ffi::NID_crl_distribution_points,
449                 ptr::null_mut(),
450                 ptr::null_mut(),
451             );
452             Stack::from_ptr_opt(stack as *mut _)
453         }
454     }
455 
456     /// Returns this certificate's issuer alternative name entries, if they exist.
457     #[corresponds(X509_get_ext_d2i)]
issuer_alt_names(&self) -> Option<Stack<GeneralName>>458     pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
459         unsafe {
460             let stack = ffi::X509_get_ext_d2i(
461                 self.as_ptr(),
462                 ffi::NID_issuer_alt_name,
463                 ptr::null_mut(),
464                 ptr::null_mut(),
465             );
466             Stack::from_ptr_opt(stack as *mut _)
467         }
468     }
469 
470     /// Returns this certificate's [`authority information access`] entries, if they exist.
471     ///
472     /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1
473     #[corresponds(X509_get_ext_d2i)]
authority_info(&self) -> Option<Stack<AccessDescription>>474     pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
475         unsafe {
476             let stack = ffi::X509_get_ext_d2i(
477                 self.as_ptr(),
478                 ffi::NID_info_access,
479                 ptr::null_mut(),
480                 ptr::null_mut(),
481             );
482             Stack::from_ptr_opt(stack as *mut _)
483         }
484     }
485 
486     /// Retrieves the path length extension from a certificate, if it exists.
487     #[corresponds(X509_get_pathlen)]
488     #[cfg(ossl110)]
pathlen(&self) -> Option<u32>489     pub fn pathlen(&self) -> Option<u32> {
490         let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
491         u32::try_from(v).ok()
492     }
493 
494     /// Returns this certificate's subject key id, if it exists.
495     #[corresponds(X509_get0_subject_key_id)]
496     #[cfg(ossl110)]
subject_key_id(&self) -> Option<&Asn1OctetStringRef>497     pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
498         unsafe {
499             let data = ffi::X509_get0_subject_key_id(self.as_ptr());
500             Asn1OctetStringRef::from_const_ptr_opt(data)
501         }
502     }
503 
504     /// Returns this certificate's authority key id, if it exists.
505     #[corresponds(X509_get0_authority_key_id)]
506     #[cfg(ossl110)]
authority_key_id(&self) -> Option<&Asn1OctetStringRef>507     pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
508         unsafe {
509             let data = ffi::X509_get0_authority_key_id(self.as_ptr());
510             Asn1OctetStringRef::from_const_ptr_opt(data)
511         }
512     }
513 
514     /// Returns this certificate's authority issuer name entries, if they exist.
515     #[corresponds(X509_get0_authority_issuer)]
516     #[cfg(ossl111d)]
authority_issuer(&self) -> Option<&StackRef<GeneralName>>517     pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
518         unsafe {
519             let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
520             StackRef::from_const_ptr_opt(stack)
521         }
522     }
523 
524     /// Returns this certificate's authority serial number, if it exists.
525     #[corresponds(X509_get0_authority_serial)]
526     #[cfg(ossl111d)]
authority_serial(&self) -> Option<&Asn1IntegerRef>527     pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
528         unsafe {
529             let r = ffi::X509_get0_authority_serial(self.as_ptr());
530             Asn1IntegerRef::from_const_ptr_opt(r)
531         }
532     }
533 
534     #[corresponds(X509_get_pubkey)]
public_key(&self) -> Result<PKey<Public>, ErrorStack>535     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
536         unsafe {
537             let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
538             Ok(PKey::from_ptr(pkey))
539         }
540     }
541 
542     /// Returns a digest of the DER representation of the certificate.
543     #[corresponds(X509_digest)]
digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>544     pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
545         unsafe {
546             let mut digest = DigestBytes {
547                 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
548                 len: ffi::EVP_MAX_MD_SIZE as usize,
549             };
550             let mut len = ffi::EVP_MAX_MD_SIZE as c_uint;
551             cvt(ffi::X509_digest(
552                 self.as_ptr(),
553                 hash_type.as_ptr(),
554                 digest.buf.as_mut_ptr() as *mut _,
555                 &mut len,
556             ))?;
557             digest.len = len as usize;
558 
559             Ok(digest)
560         }
561     }
562 
563     #[deprecated(since = "0.10.9", note = "renamed to digest")]
fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>564     pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
565         self.digest(hash_type).map(|b| b.to_vec())
566     }
567 
568     /// Returns the certificate's Not After validity period.
569     #[corresponds(X509_getm_notAfter)]
not_after(&self) -> &Asn1TimeRef570     pub fn not_after(&self) -> &Asn1TimeRef {
571         unsafe {
572             let date = X509_getm_notAfter(self.as_ptr());
573             Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
574         }
575     }
576 
577     /// Returns the certificate's Not Before validity period.
578     #[corresponds(X509_getm_notBefore)]
not_before(&self) -> &Asn1TimeRef579     pub fn not_before(&self) -> &Asn1TimeRef {
580         unsafe {
581             let date = X509_getm_notBefore(self.as_ptr());
582             Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
583         }
584     }
585 
586     /// Returns the certificate's signature
587     #[corresponds(X509_get0_signature)]
signature(&self) -> &Asn1BitStringRef588     pub fn signature(&self) -> &Asn1BitStringRef {
589         unsafe {
590             let mut signature = ptr::null();
591             X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
592             Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
593         }
594     }
595 
596     /// Returns the certificate's signature algorithm.
597     #[corresponds(X509_get0_signature)]
signature_algorithm(&self) -> &X509AlgorithmRef598     pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
599         unsafe {
600             let mut algor = ptr::null();
601             X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
602             X509AlgorithmRef::from_const_ptr_opt(algor)
603                 .expect("signature algorithm must not be null")
604         }
605     }
606 
607     /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
608     /// Access field.
609     #[corresponds(X509_get1_ocsp)]
ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>610     pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
611         unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
612     }
613 
614     /// Checks that this certificate issued `subject`.
615     #[corresponds(X509_check_issued)]
issued(&self, subject: &X509Ref) -> X509VerifyResult616     pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
617         unsafe {
618             let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
619             X509VerifyResult::from_raw(r)
620         }
621     }
622 
623     /// Returns certificate version. If this certificate has no explicit version set, it defaults to
624     /// version 1.
625     ///
626     /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
627     #[corresponds(X509_get_version)]
628     #[cfg(ossl110)]
629     #[allow(clippy::unnecessary_cast)]
version(&self) -> i32630     pub fn version(&self) -> i32 {
631         unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
632     }
633 
634     /// Check if the certificate is signed using the given public key.
635     ///
636     /// Only the signature is checked: no other checks (such as certificate chain validity)
637     /// are performed.
638     ///
639     /// Returns `true` if verification succeeds.
640     #[corresponds(X509_verify)]
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,641     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
642     where
643         T: HasPublic,
644     {
645         unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
646     }
647 
648     /// Returns this certificate's serial number.
649     #[corresponds(X509_get_serialNumber)]
serial_number(&self) -> &Asn1IntegerRef650     pub fn serial_number(&self) -> &Asn1IntegerRef {
651         unsafe {
652             let r = ffi::X509_get_serialNumber(self.as_ptr());
653             Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
654         }
655     }
656 
657     to_pem! {
658         /// Serializes the certificate into a PEM-encoded X509 structure.
659         ///
660         /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
661         #[corresponds(PEM_write_bio_X509)]
662         to_pem,
663         ffi::PEM_write_bio_X509
664     }
665 
666     to_der! {
667         /// Serializes the certificate into a DER-encoded X509 structure.
668         #[corresponds(i2d_X509)]
669         to_der,
670         ffi::i2d_X509
671     }
672 
673     to_pem! {
674         /// Converts the certificate to human readable text.
675         #[corresponds(X509_print)]
676         to_text,
677         ffi::X509_print
678     }
679 }
680 
681 impl ToOwned for X509Ref {
682     type Owned = X509;
683 
to_owned(&self) -> X509684     fn to_owned(&self) -> X509 {
685         unsafe {
686             X509_up_ref(self.as_ptr());
687             X509::from_ptr(self.as_ptr())
688         }
689     }
690 }
691 
692 impl Ord for X509Ref {
cmp(&self, other: &Self) -> cmp::Ordering693     fn cmp(&self, other: &Self) -> cmp::Ordering {
694         // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
695         // It can't fail if both pointers are valid, which we know is true.
696         let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
697         cmp.cmp(&0)
698     }
699 }
700 
701 impl PartialOrd for X509Ref {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>702     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
703         Some(self.cmp(other))
704     }
705 }
706 
707 impl PartialOrd<X509> for X509Ref {
partial_cmp(&self, other: &X509) -> Option<cmp::Ordering>708     fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
709         <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
710     }
711 }
712 
713 impl PartialEq for X509Ref {
eq(&self, other: &Self) -> bool714     fn eq(&self, other: &Self) -> bool {
715         self.cmp(other) == cmp::Ordering::Equal
716     }
717 }
718 
719 impl PartialEq<X509> for X509Ref {
eq(&self, other: &X509) -> bool720     fn eq(&self, other: &X509) -> bool {
721         <X509Ref as PartialEq<X509Ref>>::eq(self, other)
722     }
723 }
724 
725 impl Eq for X509Ref {}
726 
727 impl X509 {
728     /// Returns a new builder.
builder() -> Result<X509Builder, ErrorStack>729     pub fn builder() -> Result<X509Builder, ErrorStack> {
730         X509Builder::new()
731     }
732 
733     from_pem! {
734         /// Deserializes a PEM-encoded X509 structure.
735         ///
736         /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
737         #[corresponds(PEM_read_bio_X509)]
738         from_pem,
739         X509,
740         ffi::PEM_read_bio_X509
741     }
742 
743     from_der! {
744         /// Deserializes a DER-encoded X509 structure.
745         #[corresponds(d2i_X509)]
746         from_der,
747         X509,
748         ffi::d2i_X509
749     }
750 
751     /// Deserializes a list of PEM-formatted certificates.
752     #[corresponds(PEM_read_bio_X509)]
stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>753     pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
754         unsafe {
755             ffi::init();
756             let bio = MemBioSlice::new(pem)?;
757 
758             let mut certs = vec![];
759             loop {
760                 let r =
761                     ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
762                 if r.is_null() {
763                     let err = ffi::ERR_peek_last_error();
764                     if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM
765                         && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
766                     {
767                         ffi::ERR_clear_error();
768                         break;
769                     }
770 
771                     return Err(ErrorStack::get());
772                 } else {
773                     certs.push(X509(r));
774                 }
775             }
776 
777             Ok(certs)
778         }
779     }
780 }
781 
782 impl Clone for X509 {
clone(&self) -> X509783     fn clone(&self) -> X509 {
784         X509Ref::to_owned(self)
785     }
786 }
787 
788 impl fmt::Debug for X509 {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result789     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
790         let serial = match &self.serial_number().to_bn() {
791             Ok(bn) => match bn.to_hex_str() {
792                 Ok(hex) => hex.to_string(),
793                 Err(_) => "".to_string(),
794             },
795             Err(_) => "".to_string(),
796         };
797         let mut debug_struct = formatter.debug_struct("X509");
798         debug_struct.field("serial_number", &serial);
799         debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
800         debug_struct.field("issuer", &self.issuer_name());
801         debug_struct.field("subject", &self.subject_name());
802         if let Some(subject_alt_names) = &self.subject_alt_names() {
803             debug_struct.field("subject_alt_names", subject_alt_names);
804         }
805         debug_struct.field("not_before", &self.not_before());
806         debug_struct.field("not_after", &self.not_after());
807 
808         if let Ok(public_key) = &self.public_key() {
809             debug_struct.field("public_key", public_key);
810         };
811         // TODO: Print extensions once they are supported on the X509 struct.
812 
813         debug_struct.finish()
814     }
815 }
816 
817 impl AsRef<X509Ref> for X509Ref {
as_ref(&self) -> &X509Ref818     fn as_ref(&self) -> &X509Ref {
819         self
820     }
821 }
822 
823 impl Stackable for X509 {
824     type StackType = ffi::stack_st_X509;
825 }
826 
827 impl Ord for X509 {
cmp(&self, other: &Self) -> cmp::Ordering828     fn cmp(&self, other: &Self) -> cmp::Ordering {
829         X509Ref::cmp(self, other)
830     }
831 }
832 
833 impl PartialOrd for X509 {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>834     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
835         X509Ref::partial_cmp(self, other)
836     }
837 }
838 
839 impl PartialOrd<X509Ref> for X509 {
partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering>840     fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
841         X509Ref::partial_cmp(self, other)
842     }
843 }
844 
845 impl PartialEq for X509 {
eq(&self, other: &Self) -> bool846     fn eq(&self, other: &Self) -> bool {
847         X509Ref::eq(self, other)
848     }
849 }
850 
851 impl PartialEq<X509Ref> for X509 {
eq(&self, other: &X509Ref) -> bool852     fn eq(&self, other: &X509Ref) -> bool {
853         X509Ref::eq(self, other)
854     }
855 }
856 
857 impl Eq for X509 {}
858 
859 /// A context object required to construct certain `X509` extension values.
860 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
861 
862 impl<'a> X509v3Context<'a> {
as_ptr(&self) -> *mut ffi::X509V3_CTX863     pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
864         &self.0 as *const _ as *mut _
865     }
866 }
867 
868 foreign_type_and_impl_send_sync! {
869     type CType = ffi::X509_EXTENSION;
870     fn drop = ffi::X509_EXTENSION_free;
871 
872     /// Permit additional fields to be added to an `X509` v3 certificate.
873     pub struct X509Extension;
874     /// Reference to `X509Extension`.
875     pub struct X509ExtensionRef;
876 }
877 
878 impl Stackable for X509Extension {
879     type StackType = ffi::stack_st_X509_EXTENSION;
880 }
881 
882 impl X509Extension {
883     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
884     /// names and their value formats.
885     ///
886     /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
887     /// provided.
888     ///
889     /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
890     /// mini-language that can read arbitrary files.
891     ///
892     /// See the extension module for builder types which will construct certain common extensions.
893     ///
894     /// This function is deprecated, `X509Extension::new_from_der` or the
895     /// types in `x509::extension` should be used in its place.
896     #[deprecated(
897         note = "Use x509::extension types or new_from_der instead",
898         since = "0.10.51"
899     )]
new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: &str, value: &str, ) -> Result<X509Extension, ErrorStack>900     pub fn new(
901         conf: Option<&ConfRef>,
902         context: Option<&X509v3Context<'_>>,
903         name: &str,
904         value: &str,
905     ) -> Result<X509Extension, ErrorStack> {
906         let name = CString::new(name).unwrap();
907         let value = CString::new(value).unwrap();
908         let mut ctx;
909         unsafe {
910             ffi::init();
911             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
912             let context_ptr = match context {
913                 Some(c) => c.as_ptr(),
914                 None => {
915                     ctx = mem::zeroed();
916 
917                     ffi::X509V3_set_ctx(
918                         &mut ctx,
919                         ptr::null_mut(),
920                         ptr::null_mut(),
921                         ptr::null_mut(),
922                         ptr::null_mut(),
923                         0,
924                     );
925                     &mut ctx
926                 }
927             };
928             let name = name.as_ptr() as *mut _;
929             let value = value.as_ptr() as *mut _;
930 
931             cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
932         }
933     }
934 
935     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
936     /// extensions and their value formats.
937     ///
938     /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
939     /// be provided.
940     ///
941     /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
942     /// mini-language that can read arbitrary files.
943     ///
944     /// See the extension module for builder types which will construct certain common extensions.
945     ///
946     /// This function is deprecated, `X509Extension::new_from_der` or the
947     /// types in `x509::extension` should be used in its place.
948     #[deprecated(
949         note = "Use x509::extension types or new_from_der instead",
950         since = "0.10.51"
951     )]
new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result<X509Extension, ErrorStack>952     pub fn new_nid(
953         conf: Option<&ConfRef>,
954         context: Option<&X509v3Context<'_>>,
955         name: Nid,
956         value: &str,
957     ) -> Result<X509Extension, ErrorStack> {
958         let value = CString::new(value).unwrap();
959         let mut ctx;
960         unsafe {
961             ffi::init();
962             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
963             let context_ptr = match context {
964                 Some(c) => c.as_ptr(),
965                 None => {
966                     ctx = mem::zeroed();
967 
968                     ffi::X509V3_set_ctx(
969                         &mut ctx,
970                         ptr::null_mut(),
971                         ptr::null_mut(),
972                         ptr::null_mut(),
973                         ptr::null_mut(),
974                         0,
975                     );
976                     &mut ctx
977                 }
978             };
979             let name = name.as_raw();
980             let value = value.as_ptr() as *mut _;
981 
982             cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
983         }
984     }
985 
986     /// Constructs a new X509 extension value from its OID, whether it's
987     /// critical, and its DER contents.
988     ///
989     /// The extent structure of the DER value will vary based on the
990     /// extension type, and can generally be found in the RFC defining the
991     /// extension.
992     ///
993     /// For common extension types, there are Rust APIs provided in
994     /// `openssl::x509::extensions` which are more ergonomic.
new_from_der( oid: &Asn1ObjectRef, critical: bool, der_contents: &Asn1OctetStringRef, ) -> Result<X509Extension, ErrorStack>995     pub fn new_from_der(
996         oid: &Asn1ObjectRef,
997         critical: bool,
998         der_contents: &Asn1OctetStringRef,
999     ) -> Result<X509Extension, ErrorStack> {
1000         unsafe {
1001             cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1002                 ptr::null_mut(),
1003                 oid.as_ptr(),
1004                 critical as _,
1005                 der_contents.as_ptr(),
1006             ))
1007             .map(X509Extension)
1008         }
1009     }
1010 
new_internal( nid: Nid, critical: bool, value: *mut c_void, ) -> Result<X509Extension, ErrorStack>1011     pub(crate) unsafe fn new_internal(
1012         nid: Nid,
1013         critical: bool,
1014         value: *mut c_void,
1015     ) -> Result<X509Extension, ErrorStack> {
1016         ffi::init();
1017         cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1018     }
1019 
1020     /// Adds an alias for an extension
1021     ///
1022     /// # Safety
1023     ///
1024     /// This method modifies global state without locking and therefore is not thread safe
1025     #[corresponds(X509V3_EXT_add_alias)]
1026     #[deprecated(
1027         note = "Use x509::extension types or new_from_der and then this is not necessary",
1028         since = "0.10.51"
1029     )]
add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack>1030     pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1031         ffi::init();
1032         cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1033     }
1034 }
1035 
1036 impl X509ExtensionRef {
1037     to_der! {
1038         /// Serializes the Extension to its standard DER encoding.
1039         #[corresponds(i2d_X509_EXTENSION)]
1040         to_der,
1041         ffi::i2d_X509_EXTENSION
1042     }
1043 }
1044 
1045 /// A builder used to construct an `X509Name`.
1046 pub struct X509NameBuilder(X509Name);
1047 
1048 impl X509NameBuilder {
1049     /// Creates a new builder.
new() -> Result<X509NameBuilder, ErrorStack>1050     pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1051         unsafe {
1052             ffi::init();
1053             cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1054         }
1055     }
1056 
1057     /// Add a name entry
1058     #[corresponds(X509_NAME_add_entry)]
1059     #[cfg(any(ossl101, libressl350))]
append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack>1060     pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1061         unsafe {
1062             cvt(ffi::X509_NAME_add_entry(
1063                 self.0.as_ptr(),
1064                 ne.as_ptr(),
1065                 -1,
1066                 0,
1067             ))
1068             .map(|_| ())
1069         }
1070     }
1071 
1072     /// Add a field entry by str.
1073     ///
1074     /// This corresponds to [`X509_NAME_add_entry_by_txt`].
1075     ///
1076     /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html
append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack>1077     pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1078         unsafe {
1079             let field = CString::new(field).unwrap();
1080             assert!(value.len() <= crate::SLenType::max_value() as usize);
1081             cvt(ffi::X509_NAME_add_entry_by_txt(
1082                 self.0.as_ptr(),
1083                 field.as_ptr() as *mut _,
1084                 ffi::MBSTRING_UTF8,
1085                 value.as_ptr(),
1086                 value.len() as crate::SLenType,
1087                 -1,
1088                 0,
1089             ))
1090             .map(|_| ())
1091         }
1092     }
1093 
1094     /// Add a field entry by str with a specific type.
1095     ///
1096     /// This corresponds to [`X509_NAME_add_entry_by_txt`].
1097     ///
1098     /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html
append_entry_by_text_with_type( &mut self, field: &str, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>1099     pub fn append_entry_by_text_with_type(
1100         &mut self,
1101         field: &str,
1102         value: &str,
1103         ty: Asn1Type,
1104     ) -> Result<(), ErrorStack> {
1105         unsafe {
1106             let field = CString::new(field).unwrap();
1107             assert!(value.len() <= crate::SLenType::max_value() as usize);
1108             cvt(ffi::X509_NAME_add_entry_by_txt(
1109                 self.0.as_ptr(),
1110                 field.as_ptr() as *mut _,
1111                 ty.as_raw(),
1112                 value.as_ptr(),
1113                 value.len() as crate::SLenType,
1114                 -1,
1115                 0,
1116             ))
1117             .map(|_| ())
1118         }
1119     }
1120 
1121     /// Add a field entry by NID.
1122     ///
1123     /// This corresponds to [`X509_NAME_add_entry_by_NID`].
1124     ///
1125     /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack>1126     pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1127         unsafe {
1128             assert!(value.len() <= crate::SLenType::max_value() as usize);
1129             cvt(ffi::X509_NAME_add_entry_by_NID(
1130                 self.0.as_ptr(),
1131                 field.as_raw(),
1132                 ffi::MBSTRING_UTF8,
1133                 value.as_ptr() as *mut _,
1134                 value.len() as crate::SLenType,
1135                 -1,
1136                 0,
1137             ))
1138             .map(|_| ())
1139         }
1140     }
1141 
1142     /// Add a field entry by NID with a specific type.
1143     ///
1144     /// This corresponds to [`X509_NAME_add_entry_by_NID`].
1145     ///
1146     /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
append_entry_by_nid_with_type( &mut self, field: Nid, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>1147     pub fn append_entry_by_nid_with_type(
1148         &mut self,
1149         field: Nid,
1150         value: &str,
1151         ty: Asn1Type,
1152     ) -> Result<(), ErrorStack> {
1153         unsafe {
1154             assert!(value.len() <= crate::SLenType::max_value() as usize);
1155             cvt(ffi::X509_NAME_add_entry_by_NID(
1156                 self.0.as_ptr(),
1157                 field.as_raw(),
1158                 ty.as_raw(),
1159                 value.as_ptr() as *mut _,
1160                 value.len() as crate::SLenType,
1161                 -1,
1162                 0,
1163             ))
1164             .map(|_| ())
1165         }
1166     }
1167 
1168     /// Return an `X509Name`.
build(self) -> X509Name1169     pub fn build(self) -> X509Name {
1170         // Round-trip through bytes because OpenSSL is not const correct and
1171         // names in a "modified" state compute various things lazily. This can
1172         // lead to data-races because OpenSSL doesn't have locks or anything.
1173         X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1174     }
1175 }
1176 
1177 foreign_type_and_impl_send_sync! {
1178     type CType = ffi::X509_NAME;
1179     fn drop = ffi::X509_NAME_free;
1180 
1181     /// The names of an `X509` certificate.
1182     pub struct X509Name;
1183     /// Reference to `X509Name`.
1184     pub struct X509NameRef;
1185 }
1186 
1187 impl X509Name {
1188     /// Returns a new builder.
builder() -> Result<X509NameBuilder, ErrorStack>1189     pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1190         X509NameBuilder::new()
1191     }
1192 
1193     /// Loads subject names from a file containing PEM-formatted certificates.
1194     ///
1195     /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack>1196     pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1197         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1198         unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1199     }
1200 
1201     from_der! {
1202         /// Deserializes a DER-encoded X509 name structure.
1203         ///
1204         /// This corresponds to [`d2i_X509_NAME`].
1205         ///
1206         /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html
1207         from_der,
1208         X509Name,
1209         ffi::d2i_X509_NAME
1210     }
1211 }
1212 
1213 impl Stackable for X509Name {
1214     type StackType = ffi::stack_st_X509_NAME;
1215 }
1216 
1217 impl X509NameRef {
1218     /// Returns the name entries by the nid.
entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>1219     pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1220         X509NameEntries {
1221             name: self,
1222             nid: Some(nid),
1223             loc: -1,
1224         }
1225     }
1226 
1227     /// Returns an iterator over all `X509NameEntry` values
entries(&self) -> X509NameEntries<'_>1228     pub fn entries(&self) -> X509NameEntries<'_> {
1229         X509NameEntries {
1230             name: self,
1231             nid: None,
1232             loc: -1,
1233         }
1234     }
1235 
1236     /// Compare two names, like [`Ord`] but it may fail.
1237     ///
1238     /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
1239     /// call fails.
1240     /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
1241     /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
1242     #[corresponds(X509_NAME_cmp)]
try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack>1243     pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1244         let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1245         if cfg!(ossl300) && cmp == -2 {
1246             return Err(ErrorStack::get());
1247         }
1248         Ok(cmp.cmp(&0))
1249     }
1250 
1251     /// Copies the name to a new `X509Name`.
1252     #[corresponds(X509_NAME_dup)]
1253     #[cfg(any(boringssl, ossl110, libressl270))]
to_owned(&self) -> Result<X509Name, ErrorStack>1254     pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1255         unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1256     }
1257 
1258     to_der! {
1259         /// Serializes the certificate into a DER-encoded X509 name structure.
1260         ///
1261         /// This corresponds to [`i2d_X509_NAME`].
1262         ///
1263         /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html
1264         to_der,
1265         ffi::i2d_X509_NAME
1266     }
1267 }
1268 
1269 impl fmt::Debug for X509NameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1270     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1271         formatter.debug_list().entries(self.entries()).finish()
1272     }
1273 }
1274 
1275 /// A type to destructure and examine an `X509Name`.
1276 pub struct X509NameEntries<'a> {
1277     name: &'a X509NameRef,
1278     nid: Option<Nid>,
1279     loc: c_int,
1280 }
1281 
1282 impl<'a> Iterator for X509NameEntries<'a> {
1283     type Item = &'a X509NameEntryRef;
1284 
next(&mut self) -> Option<&'a X509NameEntryRef>1285     fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1286         unsafe {
1287             match self.nid {
1288                 Some(nid) => {
1289                     // There is a `Nid` specified to search for
1290                     self.loc =
1291                         ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1292                     if self.loc == -1 {
1293                         return None;
1294                     }
1295                 }
1296                 None => {
1297                     // Iterate over all `Nid`s
1298                     self.loc += 1;
1299                     if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1300                         return None;
1301                     }
1302                 }
1303             }
1304 
1305             let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1306 
1307             Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1308         }
1309     }
1310 }
1311 
1312 foreign_type_and_impl_send_sync! {
1313     type CType = ffi::X509_NAME_ENTRY;
1314     fn drop = ffi::X509_NAME_ENTRY_free;
1315 
1316     /// A name entry associated with a `X509Name`.
1317     pub struct X509NameEntry;
1318     /// Reference to `X509NameEntry`.
1319     pub struct X509NameEntryRef;
1320 }
1321 
1322 impl X509NameEntryRef {
1323     /// Returns the field value of an `X509NameEntry`.
1324     ///
1325     /// This corresponds to [`X509_NAME_ENTRY_get_data`].
1326     ///
1327     /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html
data(&self) -> &Asn1StringRef1328     pub fn data(&self) -> &Asn1StringRef {
1329         unsafe {
1330             let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1331             Asn1StringRef::from_ptr(data)
1332         }
1333     }
1334 
1335     /// Returns the `Asn1Object` value of an `X509NameEntry`.
1336     /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1337     ///
1338     /// This corresponds to [`X509_NAME_ENTRY_get_object`].
1339     ///
1340     /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html
object(&self) -> &Asn1ObjectRef1341     pub fn object(&self) -> &Asn1ObjectRef {
1342         unsafe {
1343             let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1344             Asn1ObjectRef::from_ptr(object)
1345         }
1346     }
1347 }
1348 
1349 impl fmt::Debug for X509NameEntryRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1350     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1351         formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1352     }
1353 }
1354 
1355 /// A builder used to construct an `X509Req`.
1356 pub struct X509ReqBuilder(X509Req);
1357 
1358 impl X509ReqBuilder {
1359     /// Returns a builder for a certificate request.
1360     ///
1361     /// This corresponds to [`X509_REQ_new`].
1362     ///
1363     ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html
new() -> Result<X509ReqBuilder, ErrorStack>1364     pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1365         unsafe {
1366             ffi::init();
1367             cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1368         }
1369     }
1370 
1371     /// Set the numerical value of the version field.
1372     ///
1373     /// This corresponds to [`X509_REQ_set_version`].
1374     ///
1375     ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html
1376     #[allow(clippy::useless_conversion)]
set_version(&mut self, version: i32) -> Result<(), ErrorStack>1377     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1378         unsafe {
1379             cvt(ffi::X509_REQ_set_version(
1380                 self.0.as_ptr(),
1381                 version as c_long,
1382             ))
1383             .map(|_| ())
1384         }
1385     }
1386 
1387     /// Set the issuer name.
1388     ///
1389     /// This corresponds to [`X509_REQ_set_subject_name`].
1390     ///
1391     /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_subject_name.html
set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>1392     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1393         unsafe {
1394             cvt(ffi::X509_REQ_set_subject_name(
1395                 self.0.as_ptr(),
1396                 subject_name.as_ptr(),
1397             ))
1398             .map(|_| ())
1399         }
1400     }
1401 
1402     /// Set the public key.
1403     ///
1404     /// This corresponds to [`X509_REQ_set_pubkey`].
1405     ///
1406     /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_pubkey.html
set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,1407     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1408     where
1409         T: HasPublic,
1410     {
1411         unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1412     }
1413 
1414     /// Return an `X509v3Context`. This context object can be used to construct
1415     /// certain `X509` extensions.
x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1416     pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1417         unsafe {
1418             let mut ctx = mem::zeroed();
1419 
1420             ffi::X509V3_set_ctx(
1421                 &mut ctx,
1422                 ptr::null_mut(),
1423                 ptr::null_mut(),
1424                 self.0.as_ptr(),
1425                 ptr::null_mut(),
1426                 0,
1427             );
1428 
1429             // nodb case taken care of since we zeroed ctx above
1430             if let Some(conf) = conf {
1431                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1432             }
1433 
1434             X509v3Context(ctx, PhantomData)
1435         }
1436     }
1437 
1438     /// Permits any number of extension fields to be added to the certificate.
add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1439     pub fn add_extensions(
1440         &mut self,
1441         extensions: &StackRef<X509Extension>,
1442     ) -> Result<(), ErrorStack> {
1443         unsafe {
1444             cvt(ffi::X509_REQ_add_extensions(
1445                 self.0.as_ptr(),
1446                 extensions.as_ptr(),
1447             ))
1448             .map(|_| ())
1449         }
1450     }
1451 
1452     /// Sign the request using a private key.
1453     ///
1454     /// This corresponds to [`X509_REQ_sign`].
1455     ///
1456     /// [`X509_REQ_sign`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_sign.html
sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,1457     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1458     where
1459         T: HasPrivate,
1460     {
1461         unsafe {
1462             cvt(ffi::X509_REQ_sign(
1463                 self.0.as_ptr(),
1464                 key.as_ptr(),
1465                 hash.as_ptr(),
1466             ))
1467             .map(|_| ())
1468         }
1469     }
1470 
1471     /// Returns the `X509Req`.
build(self) -> X509Req1472     pub fn build(self) -> X509Req {
1473         self.0
1474     }
1475 }
1476 
1477 foreign_type_and_impl_send_sync! {
1478     type CType = ffi::X509_REQ;
1479     fn drop = ffi::X509_REQ_free;
1480 
1481     /// An `X509` certificate request.
1482     pub struct X509Req;
1483     /// Reference to `X509Req`.
1484     pub struct X509ReqRef;
1485 }
1486 
1487 impl X509Req {
1488     /// A builder for `X509Req`.
builder() -> Result<X509ReqBuilder, ErrorStack>1489     pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1490         X509ReqBuilder::new()
1491     }
1492 
1493     from_pem! {
1494         /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1495         ///
1496         /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1497         ///
1498         /// This corresponds to [`PEM_read_bio_X509_REQ`].
1499         ///
1500         /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html
1501         from_pem,
1502         X509Req,
1503         ffi::PEM_read_bio_X509_REQ
1504     }
1505 
1506     from_der! {
1507         /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1508         ///
1509         /// This corresponds to [`d2i_X509_REQ`].
1510         ///
1511         /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html
1512         from_der,
1513         X509Req,
1514         ffi::d2i_X509_REQ
1515     }
1516 }
1517 
1518 impl X509ReqRef {
1519     to_pem! {
1520         /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1521         ///
1522         /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1523         ///
1524         /// This corresponds to [`PEM_write_bio_X509_REQ`].
1525         ///
1526         /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html
1527         to_pem,
1528         ffi::PEM_write_bio_X509_REQ
1529     }
1530 
1531     to_der! {
1532         /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1533         ///
1534         /// This corresponds to [`i2d_X509_REQ`].
1535         ///
1536         /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html
1537         to_der,
1538         ffi::i2d_X509_REQ
1539     }
1540 
1541     to_pem! {
1542         /// Converts the request to human readable text.
1543         #[corresponds(X509_Req_print)]
1544         to_text,
1545         ffi::X509_REQ_print
1546     }
1547 
1548     /// Returns the numerical value of the version field of the certificate request.
1549     ///
1550     /// This corresponds to [`X509_REQ_get_version`]
1551     ///
1552     /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html
1553     #[allow(clippy::unnecessary_cast)]
version(&self) -> i321554     pub fn version(&self) -> i32 {
1555         unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1556     }
1557 
1558     /// Returns the subject name of the certificate request.
1559     ///
1560     /// This corresponds to [`X509_REQ_get_subject_name`]
1561     ///
1562     /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html
subject_name(&self) -> &X509NameRef1563     pub fn subject_name(&self) -> &X509NameRef {
1564         unsafe {
1565             let name = X509_REQ_get_subject_name(self.as_ptr());
1566             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1567         }
1568     }
1569 
1570     /// Returns the public key of the certificate request.
1571     ///
1572     /// This corresponds to [`X509_REQ_get_pubkey"]
1573     ///
1574     /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html
public_key(&self) -> Result<PKey<Public>, ErrorStack>1575     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1576         unsafe {
1577             let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1578             Ok(PKey::from_ptr(key))
1579         }
1580     }
1581 
1582     /// Check if the certificate request is signed using the given public key.
1583     ///
1584     /// Returns `true` if verification succeeds.
1585     ///
1586     /// This corresponds to [`X509_REQ_verify"].
1587     ///
1588     /// [`X509_REQ_verify`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_verify.html
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1589     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1590     where
1591         T: HasPublic,
1592     {
1593         unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1594     }
1595 
1596     /// Returns the extensions of the certificate request.
1597     ///
1598     /// This corresponds to [`X509_REQ_get_extensions"]
extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1599     pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1600         unsafe {
1601             let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1602             Ok(Stack::from_ptr(extensions))
1603         }
1604     }
1605 }
1606 
1607 /// The reason that a certificate was revoked.
1608 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1609 pub struct CrlReason(c_int);
1610 
1611 #[allow(missing_docs)] // no need to document the constants
1612 impl CrlReason {
1613     pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1614     pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1615     pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1616     pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1617     pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1618     pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1619     pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1620     pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1621     pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1622     pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1623 
1624     /// Constructs an `CrlReason` from a raw OpenSSL value.
from_raw(value: c_int) -> Self1625     pub const fn from_raw(value: c_int) -> Self {
1626         CrlReason(value)
1627     }
1628 
1629     /// Returns the raw OpenSSL value represented by this type.
as_raw(&self) -> c_int1630     pub const fn as_raw(&self) -> c_int {
1631         self.0
1632     }
1633 }
1634 
1635 foreign_type_and_impl_send_sync! {
1636     type CType = ffi::X509_REVOKED;
1637     fn drop = ffi::X509_REVOKED_free;
1638 
1639     /// An `X509` certificate revocation status.
1640     pub struct X509Revoked;
1641     /// Reference to `X509Revoked`.
1642     pub struct X509RevokedRef;
1643 }
1644 
1645 impl Stackable for X509Revoked {
1646     type StackType = ffi::stack_st_X509_REVOKED;
1647 }
1648 
1649 impl X509Revoked {
1650     from_der! {
1651         /// Deserializes a DER-encoded certificate revocation status
1652         #[corresponds(d2i_X509_REVOKED)]
1653         from_der,
1654         X509Revoked,
1655         ffi::d2i_X509_REVOKED
1656     }
1657 }
1658 
1659 impl X509RevokedRef {
1660     to_der! {
1661         /// Serializes the certificate request to a DER-encoded certificate revocation status
1662         #[corresponds(d2i_X509_REVOKED)]
1663         to_der,
1664         ffi::i2d_X509_REVOKED
1665     }
1666 
1667     /// Copies the entry to a new `X509Revoked`.
1668     #[corresponds(X509_NAME_dup)]
1669     #[cfg(any(boringssl, ossl110, libressl270))]
to_owned(&self) -> Result<X509Revoked, ErrorStack>1670     pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1671         unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1672     }
1673 
1674     /// Get the date that the certificate was revoked
1675     #[corresponds(X509_REVOKED_get0_revocationDate)]
revocation_date(&self) -> &Asn1TimeRef1676     pub fn revocation_date(&self) -> &Asn1TimeRef {
1677         unsafe {
1678             let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1679             assert!(!r.is_null());
1680             Asn1TimeRef::from_ptr(r as *mut _)
1681         }
1682     }
1683 
1684     /// Get the serial number of the revoked certificate
1685     #[corresponds(X509_REVOKED_get0_serialNumber)]
serial_number(&self) -> &Asn1IntegerRef1686     pub fn serial_number(&self) -> &Asn1IntegerRef {
1687         unsafe {
1688             let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1689             assert!(!r.is_null());
1690             Asn1IntegerRef::from_ptr(r as *mut _)
1691         }
1692     }
1693 
1694     /// Get the criticality and value of an extension.
1695     ///
1696     /// This returns None if the extension is not present or occurs multiple times.
1697     #[corresponds(X509_REVOKED_get_ext_d2i)]
extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack>1698     pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1699         let mut critical = -1;
1700         let out = unsafe {
1701             // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
1702             let ext = ffi::X509_REVOKED_get_ext_d2i(
1703                 self.as_ptr(),
1704                 T::NID.as_raw(),
1705                 &mut critical as *mut _,
1706                 ptr::null_mut(),
1707             );
1708             // SAFETY: Extensions's contract promises that the type returned by
1709             // OpenSSL here is T::Output.
1710             T::Output::from_ptr_opt(ext as *mut _)
1711         };
1712         match (critical, out) {
1713             (0, Some(out)) => Ok(Some((false, out))),
1714             (1, Some(out)) => Ok(Some((true, out))),
1715             // -1 means the extension wasn't found, -2 means multiple were found.
1716             (-1 | -2, _) => Ok(None),
1717             // A critical value of 0 or 1 suggests success, but a null pointer
1718             // was returned so something went wrong.
1719             (0 | 1, None) => Err(ErrorStack::get()),
1720             (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1721         }
1722     }
1723 }
1724 
1725 /// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
1726 /// this is as defined in RFC 5280 Section 5.3.1.
1727 pub enum ReasonCode {}
1728 
1729 // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1730 // and in OpenSSL.
1731 unsafe impl ExtensionType for ReasonCode {
1732     const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1733 
1734     type Output = Asn1Enumerated;
1735 }
1736 
1737 /// The CRL entry extension identifying the issuer of a certificate used in
1738 /// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
1739 pub enum CertificateIssuer {}
1740 
1741 // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1742 // and in OpenSSL.
1743 unsafe impl ExtensionType for CertificateIssuer {
1744     const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1745 
1746     type Output = Stack<GeneralName>;
1747 }
1748 
1749 foreign_type_and_impl_send_sync! {
1750     type CType = ffi::X509_CRL;
1751     fn drop = ffi::X509_CRL_free;
1752 
1753     /// An `X509` certificate revocation list.
1754     pub struct X509Crl;
1755     /// Reference to `X509Crl`.
1756     pub struct X509CrlRef;
1757 }
1758 
1759 /// The status of a certificate in a revoction list
1760 ///
1761 /// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1762 ///
1763 /// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html
1764 pub enum CrlStatus<'a> {
1765     /// The certificate is not present in the list
1766     NotRevoked,
1767     /// The certificate is in the list and is revoked
1768     Revoked(&'a X509RevokedRef),
1769     /// The certificate is in the list, but has the "removeFromCrl" status.
1770     ///
1771     /// This can occur if the certificate was revoked with the "CertificateHold"
1772     /// reason, and has since been unrevoked.
1773     RemoveFromCrl(&'a X509RevokedRef),
1774 }
1775 
1776 impl<'a> CrlStatus<'a> {
1777     // Helper used by the X509_CRL_get0_by_* methods to convert their return
1778     // value to the status enum.
1779     // Safety note: the returned CrlStatus must not outlive the owner of the
1780     // revoked_entry pointer.
from_ffi_status( status: c_int, revoked_entry: *mut ffi::X509_REVOKED, ) -> CrlStatus<'a>1781     unsafe fn from_ffi_status(
1782         status: c_int,
1783         revoked_entry: *mut ffi::X509_REVOKED,
1784     ) -> CrlStatus<'a> {
1785         match status {
1786             0 => CrlStatus::NotRevoked,
1787             1 => {
1788                 assert!(!revoked_entry.is_null());
1789                 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1790             }
1791             2 => {
1792                 assert!(!revoked_entry.is_null());
1793                 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1794             }
1795             _ => unreachable!(
1796                 "{}",
1797                 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1798             ),
1799         }
1800     }
1801 }
1802 
1803 impl X509Crl {
1804     from_pem! {
1805         /// Deserializes a PEM-encoded Certificate Revocation List
1806         ///
1807         /// The input should have a header of `-----BEGIN X509 CRL-----`.
1808         #[corresponds(PEM_read_bio_X509_CRL)]
1809         from_pem,
1810         X509Crl,
1811         ffi::PEM_read_bio_X509_CRL
1812     }
1813 
1814     from_der! {
1815         /// Deserializes a DER-encoded Certificate Revocation List
1816         #[corresponds(d2i_X509_CRL)]
1817         from_der,
1818         X509Crl,
1819         ffi::d2i_X509_CRL
1820     }
1821 }
1822 
1823 impl X509CrlRef {
1824     to_pem! {
1825         /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
1826         ///
1827         /// The output will have a header of `-----BEGIN X509 CRL-----`.
1828         #[corresponds(PEM_write_bio_X509_CRL)]
1829         to_pem,
1830         ffi::PEM_write_bio_X509_CRL
1831     }
1832 
1833     to_der! {
1834         /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
1835         #[corresponds(i2d_X509_CRL)]
1836         to_der,
1837         ffi::i2d_X509_CRL
1838     }
1839 
1840     /// Get the stack of revocation entries
get_revoked(&self) -> Option<&StackRef<X509Revoked>>1841     pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
1842         unsafe {
1843             let revoked = X509_CRL_get_REVOKED(self.as_ptr());
1844             if revoked.is_null() {
1845                 None
1846             } else {
1847                 Some(StackRef::from_ptr(revoked))
1848             }
1849         }
1850     }
1851 
1852     /// Returns the CRL's `lastUpdate` time.
1853     #[corresponds(X509_CRL_get0_lastUpdate)]
last_update(&self) -> &Asn1TimeRef1854     pub fn last_update(&self) -> &Asn1TimeRef {
1855         unsafe {
1856             let date = X509_CRL_get0_lastUpdate(self.as_ptr());
1857             assert!(!date.is_null());
1858             Asn1TimeRef::from_ptr(date as *mut _)
1859         }
1860     }
1861 
1862     /// Returns the CRL's `nextUpdate` time.
1863     ///
1864     /// If the `nextUpdate` field is missing, returns `None`.
1865     #[corresponds(X509_CRL_get0_nextUpdate)]
next_update(&self) -> Option<&Asn1TimeRef>1866     pub fn next_update(&self) -> Option<&Asn1TimeRef> {
1867         unsafe {
1868             let date = X509_CRL_get0_nextUpdate(self.as_ptr());
1869             Asn1TimeRef::from_const_ptr_opt(date)
1870         }
1871     }
1872 
1873     /// Get the revocation status of a certificate by its serial number
1874     #[corresponds(X509_CRL_get0_by_serial)]
get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a>1875     pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
1876         unsafe {
1877             let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1878             let status =
1879                 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
1880             CrlStatus::from_ffi_status(status, ret)
1881         }
1882     }
1883 
1884     /// Get the revocation status of a certificate
1885     #[corresponds(X509_CRL_get0_by_cert)]
get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a>1886     pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
1887         unsafe {
1888             let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1889             let status =
1890                 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
1891             CrlStatus::from_ffi_status(status, ret)
1892         }
1893     }
1894 
1895     /// Get the issuer name from the revocation list.
1896     #[corresponds(X509_CRL_get_issuer)]
issuer_name(&self) -> &X509NameRef1897     pub fn issuer_name(&self) -> &X509NameRef {
1898         unsafe {
1899             let name = X509_CRL_get_issuer(self.as_ptr());
1900             assert!(!name.is_null());
1901             X509NameRef::from_ptr(name)
1902         }
1903     }
1904 
1905     /// Check if the CRL is signed using the given public key.
1906     ///
1907     /// Only the signature is checked: no other checks (such as certificate chain validity)
1908     /// are performed.
1909     ///
1910     /// Returns `true` if verification succeeds.
1911     #[corresponds(X509_CRL_verify)]
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1912     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1913     where
1914         T: HasPublic,
1915     {
1916         unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1917     }
1918 }
1919 
1920 /// The result of peer certificate verification.
1921 #[derive(Copy, Clone, PartialEq, Eq)]
1922 pub struct X509VerifyResult(c_int);
1923 
1924 impl fmt::Debug for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1925     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1926         fmt.debug_struct("X509VerifyResult")
1927             .field("code", &self.0)
1928             .field("error", &self.error_string())
1929             .finish()
1930     }
1931 }
1932 
1933 impl fmt::Display for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1934     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1935         fmt.write_str(self.error_string())
1936     }
1937 }
1938 
1939 impl Error for X509VerifyResult {}
1940 
1941 impl X509VerifyResult {
1942     /// Creates an `X509VerifyResult` from a raw error number.
1943     ///
1944     /// # Safety
1945     ///
1946     /// Some methods on `X509VerifyResult` are not thread safe if the error
1947     /// number is invalid.
from_raw(err: c_int) -> X509VerifyResult1948     pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1949         X509VerifyResult(err)
1950     }
1951 
1952     /// Return the integer representation of an `X509VerifyResult`.
1953     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int1954     pub fn as_raw(&self) -> c_int {
1955         self.0
1956     }
1957 
1958     /// Return a human readable error string from the verification error.
1959     ///
1960     /// This corresponds to [`X509_verify_cert_error_string`].
1961     ///
1962     /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html
1963     #[allow(clippy::trivially_copy_pass_by_ref)]
error_string(&self) -> &'static str1964     pub fn error_string(&self) -> &'static str {
1965         ffi::init();
1966 
1967         unsafe {
1968             let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1969             str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1970         }
1971     }
1972 
1973     /// Successful peer certificate verification.
1974     pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1975     /// Application verification failure.
1976     pub const APPLICATION_VERIFICATION: X509VerifyResult =
1977         X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1978 }
1979 
1980 foreign_type_and_impl_send_sync! {
1981     type CType = ffi::GENERAL_NAME;
1982     fn drop = ffi::GENERAL_NAME_free;
1983 
1984     /// An `X509` certificate alternative names.
1985     pub struct GeneralName;
1986     /// Reference to `GeneralName`.
1987     pub struct GeneralNameRef;
1988 }
1989 
1990 impl GeneralName {
new( type_: c_int, asn1_type: Asn1Type, value: &[u8], ) -> Result<GeneralName, ErrorStack>1991     unsafe fn new(
1992         type_: c_int,
1993         asn1_type: Asn1Type,
1994         value: &[u8],
1995     ) -> Result<GeneralName, ErrorStack> {
1996         ffi::init();
1997         let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1998         (*gn.as_ptr()).type_ = type_;
1999         let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2000         ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2001 
2002         #[cfg(boringssl)]
2003         {
2004             (*gn.as_ptr()).d.ptr = s.cast();
2005         }
2006         #[cfg(not(boringssl))]
2007         {
2008             (*gn.as_ptr()).d = s.cast();
2009         }
2010 
2011         Ok(gn)
2012     }
2013 
new_email(email: &[u8]) -> Result<GeneralName, ErrorStack>2014     pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2015         unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2016     }
2017 
new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack>2018     pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2019         unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2020     }
2021 
new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack>2022     pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2023         unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2024     }
2025 
new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack>2026     pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2027         match ip {
2028             IpAddr::V4(addr) => unsafe {
2029                 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2030             },
2031             IpAddr::V6(addr) => unsafe {
2032                 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2033             },
2034         }
2035     }
2036 
new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack>2037     pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2038         unsafe {
2039             ffi::init();
2040             let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2041             (*gn).type_ = ffi::GEN_RID;
2042 
2043             #[cfg(boringssl)]
2044             {
2045                 (*gn).d.registeredID = oid.as_ptr();
2046             }
2047             #[cfg(not(boringssl))]
2048             {
2049                 (*gn).d = oid.as_ptr().cast();
2050             }
2051 
2052             mem::forget(oid);
2053 
2054             Ok(GeneralName::from_ptr(gn))
2055         }
2056     }
2057 
new_other_name( oid: Asn1Object, value: &Vec<u8>, ) -> Result<GeneralName, ErrorStack>2058     pub(crate) fn new_other_name(
2059         oid: Asn1Object,
2060         value: &Vec<u8>,
2061     ) -> Result<GeneralName, ErrorStack> {
2062         unsafe {
2063             ffi::init();
2064 
2065             let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2066                 ptr::null_mut(),
2067                 &mut value.as_ptr().cast(),
2068                 value.len().try_into().unwrap(),
2069             ))?;
2070 
2071             let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2072             (*gn).type_ = ffi::GEN_OTHERNAME;
2073 
2074             if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2075                 gn,
2076                 oid.as_ptr().cast(),
2077                 typ,
2078             )) {
2079                 ffi::GENERAL_NAME_free(gn);
2080                 return Err(e);
2081             }
2082 
2083             mem::forget(oid);
2084 
2085             Ok(GeneralName::from_ptr(gn))
2086         }
2087     }
2088 }
2089 
2090 impl GeneralNameRef {
ia5_string(&self, ffi_type: c_int) -> Option<&str>2091     fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2092         unsafe {
2093             if (*self.as_ptr()).type_ != ffi_type {
2094                 return None;
2095             }
2096 
2097             #[cfg(boringssl)]
2098             let d = (*self.as_ptr()).d.ptr;
2099             #[cfg(not(boringssl))]
2100             let d = (*self.as_ptr()).d;
2101 
2102             let ptr = ASN1_STRING_get0_data(d as *mut _);
2103             let len = ffi::ASN1_STRING_length(d as *mut _);
2104 
2105             let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
2106             // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
2107             // OpenSSL checks that when loading a certificate but if not we'll
2108             // use this instead of from_utf8_unchecked just in case.
2109             str::from_utf8(slice).ok()
2110         }
2111     }
2112 
2113     /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
email(&self) -> Option<&str>2114     pub fn email(&self) -> Option<&str> {
2115         self.ia5_string(ffi::GEN_EMAIL)
2116     }
2117 
2118     /// Returns the contents of this `GeneralName` if it is a `directoryName`.
directory_name(&self) -> Option<&X509NameRef>2119     pub fn directory_name(&self) -> Option<&X509NameRef> {
2120         unsafe {
2121             if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2122                 return None;
2123             }
2124 
2125             #[cfg(boringssl)]
2126             let d = (*self.as_ptr()).d.ptr;
2127             #[cfg(not(boringssl))]
2128             let d = (*self.as_ptr()).d;
2129 
2130             Some(X509NameRef::from_const_ptr(d as *const _))
2131         }
2132     }
2133 
2134     /// Returns the contents of this `GeneralName` if it is a `dNSName`.
dnsname(&self) -> Option<&str>2135     pub fn dnsname(&self) -> Option<&str> {
2136         self.ia5_string(ffi::GEN_DNS)
2137     }
2138 
2139     /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
uri(&self) -> Option<&str>2140     pub fn uri(&self) -> Option<&str> {
2141         self.ia5_string(ffi::GEN_URI)
2142     }
2143 
2144     /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
ipaddress(&self) -> Option<&[u8]>2145     pub fn ipaddress(&self) -> Option<&[u8]> {
2146         unsafe {
2147             if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2148                 return None;
2149             }
2150             #[cfg(boringssl)]
2151             let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2152             #[cfg(not(boringssl))]
2153             let d = (*self.as_ptr()).d;
2154 
2155             let ptr = ASN1_STRING_get0_data(d as *mut _);
2156             let len = ffi::ASN1_STRING_length(d as *mut _);
2157 
2158             Some(slice::from_raw_parts(ptr as *const u8, len as usize))
2159         }
2160     }
2161 }
2162 
2163 impl fmt::Debug for GeneralNameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result2164     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2165         if let Some(email) = self.email() {
2166             formatter.write_str(email)
2167         } else if let Some(dnsname) = self.dnsname() {
2168             formatter.write_str(dnsname)
2169         } else if let Some(uri) = self.uri() {
2170             formatter.write_str(uri)
2171         } else if let Some(ipaddress) = self.ipaddress() {
2172             let address = <[u8; 16]>::try_from(ipaddress)
2173                 .map(IpAddr::from)
2174                 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2175             match address {
2176                 Ok(a) => fmt::Debug::fmt(&a, formatter),
2177                 Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2178             }
2179         } else {
2180             formatter.write_str("(empty)")
2181         }
2182     }
2183 }
2184 
2185 impl Stackable for GeneralName {
2186     type StackType = ffi::stack_st_GENERAL_NAME;
2187 }
2188 
2189 foreign_type_and_impl_send_sync! {
2190     type CType = ffi::DIST_POINT;
2191     fn drop = ffi::DIST_POINT_free;
2192 
2193     /// A `X509` distribution point.
2194     pub struct DistPoint;
2195     /// Reference to `DistPoint`.
2196     pub struct DistPointRef;
2197 }
2198 
2199 impl DistPointRef {
2200     /// Returns the name of this distribution point if it exists
distpoint(&self) -> Option<&DistPointNameRef>2201     pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2202         unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2203     }
2204 }
2205 
2206 foreign_type_and_impl_send_sync! {
2207     type CType = ffi::DIST_POINT_NAME;
2208     fn drop = ffi::DIST_POINT_NAME_free;
2209 
2210     /// A `X509` distribution point.
2211     pub struct DistPointName;
2212     /// Reference to `DistPointName`.
2213     pub struct DistPointNameRef;
2214 }
2215 
2216 impl DistPointNameRef {
2217     /// Returns the contents of this DistPointName if it is a fullname.
fullname(&self) -> Option<&StackRef<GeneralName>>2218     pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2219         unsafe {
2220             if (*self.as_ptr()).type_ != 0 {
2221                 return None;
2222             }
2223             StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2224         }
2225     }
2226 }
2227 
2228 impl Stackable for DistPoint {
2229     type StackType = ffi::stack_st_DIST_POINT;
2230 }
2231 
2232 foreign_type_and_impl_send_sync! {
2233     type CType = ffi::ACCESS_DESCRIPTION;
2234     fn drop = ffi::ACCESS_DESCRIPTION_free;
2235 
2236     /// `AccessDescription` of certificate authority information.
2237     pub struct AccessDescription;
2238     /// Reference to `AccessDescription`.
2239     pub struct AccessDescriptionRef;
2240 }
2241 
2242 impl AccessDescriptionRef {
2243     /// Returns the access method OID.
method(&self) -> &Asn1ObjectRef2244     pub fn method(&self) -> &Asn1ObjectRef {
2245         unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2246     }
2247 
2248     // Returns the access location.
location(&self) -> &GeneralNameRef2249     pub fn location(&self) -> &GeneralNameRef {
2250         unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2251     }
2252 }
2253 
2254 impl Stackable for AccessDescription {
2255     type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2256 }
2257 
2258 foreign_type_and_impl_send_sync! {
2259     type CType = ffi::X509_ALGOR;
2260     fn drop = ffi::X509_ALGOR_free;
2261 
2262     /// An `X509` certificate signature algorithm.
2263     pub struct X509Algorithm;
2264     /// Reference to `X509Algorithm`.
2265     pub struct X509AlgorithmRef;
2266 }
2267 
2268 impl X509AlgorithmRef {
2269     /// Returns the ASN.1 OID of this algorithm.
object(&self) -> &Asn1ObjectRef2270     pub fn object(&self) -> &Asn1ObjectRef {
2271         unsafe {
2272             let mut oid = ptr::null();
2273             X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2274             Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2275         }
2276     }
2277 }
2278 
2279 foreign_type_and_impl_send_sync! {
2280     type CType = ffi::X509_OBJECT;
2281     fn drop = X509_OBJECT_free;
2282 
2283     /// An `X509` or an X509 certificate revocation list.
2284     pub struct X509Object;
2285     /// Reference to `X509Object`
2286     pub struct X509ObjectRef;
2287 }
2288 
2289 impl X509ObjectRef {
x509(&self) -> Option<&X509Ref>2290     pub fn x509(&self) -> Option<&X509Ref> {
2291         unsafe {
2292             let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2293             X509Ref::from_const_ptr_opt(ptr)
2294         }
2295     }
2296 }
2297 
2298 impl Stackable for X509Object {
2299     type StackType = ffi::stack_st_X509_OBJECT;
2300 }
2301 
2302 cfg_if! {
2303     if #[cfg(any(boringssl, ossl110, libressl273))] {
2304         use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2305     } else {
2306         #[allow(bad_style)]
2307         unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2308             (*(*(*x).cert_info).validity).notAfter
2309         }
2310 
2311         #[allow(bad_style)]
2312         unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2313             (*(*(*x).cert_info).validity).notBefore
2314         }
2315 
2316         #[allow(bad_style)]
2317         unsafe fn X509_up_ref(x: *mut ffi::X509) {
2318             ffi::CRYPTO_add_lock(
2319                 &mut (*x).references,
2320                 1,
2321                 ffi::CRYPTO_LOCK_X509,
2322                 "mod.rs\0".as_ptr() as *const _,
2323                 line!() as c_int,
2324             );
2325         }
2326 
2327         #[allow(bad_style)]
2328         unsafe fn X509_get0_signature(
2329             psig: *mut *const ffi::ASN1_BIT_STRING,
2330             palg: *mut *const ffi::X509_ALGOR,
2331             x: *const ffi::X509,
2332         ) {
2333             if !psig.is_null() {
2334                 *psig = (*x).signature;
2335             }
2336             if !palg.is_null() {
2337                 *palg = (*x).sig_alg;
2338             }
2339         }
2340     }
2341 }
2342 
2343 cfg_if! {
2344     if #[cfg(any(boringssl, ossl110, libressl350))] {
2345         use ffi::{
2346             X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2347             X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2348         };
2349     } else {
2350         use ffi::{
2351             ASN1_STRING_data as ASN1_STRING_get0_data,
2352             X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2353             X509_set_notAfter as X509_set1_notAfter,
2354             X509_set_notBefore as X509_set1_notBefore,
2355         };
2356 
2357         #[allow(bad_style)]
2358         unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2359             ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2360         }
2361 
2362         #[allow(bad_style)]
2363         unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2364             (*(*x).req_info).subject
2365         }
2366 
2367         #[allow(bad_style)]
2368         unsafe fn X509_ALGOR_get0(
2369             paobj: *mut *const ffi::ASN1_OBJECT,
2370             pptype: *mut c_int,
2371             pval: *mut *mut ::libc::c_void,
2372             alg: *const ffi::X509_ALGOR,
2373         ) {
2374             if !paobj.is_null() {
2375                 *paobj = (*alg).algorithm;
2376             }
2377             assert!(pptype.is_null());
2378             assert!(pval.is_null());
2379         }
2380     }
2381 }
2382 
2383 cfg_if! {
2384     if #[cfg(any(ossl110, boringssl, libressl270))] {
2385         use ffi::X509_OBJECT_get0_X509;
2386     } else {
2387         #[allow(bad_style)]
2388         unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2389             if (*x).type_ == ffi::X509_LU_X509 {
2390                 (*x).data.x509
2391             } else {
2392                 ptr::null_mut()
2393             }
2394         }
2395     }
2396 }
2397 
2398 cfg_if! {
2399     if #[cfg(any(ossl110, libressl350))] {
2400         use ffi::X509_OBJECT_free;
2401     } else if #[cfg(boringssl)] {
2402         use ffi::X509_OBJECT_free_contents as X509_OBJECT_free;
2403     } else {
2404         #[allow(bad_style)]
2405         unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2406             ffi::X509_OBJECT_free_contents(x);
2407             ffi::CRYPTO_free(x as *mut libc::c_void);
2408         }
2409     }
2410 }
2411 
2412 cfg_if! {
2413     if #[cfg(any(ossl110, libressl350, boringssl))] {
2414         use ffi::{
2415             X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2416             X509_CRL_get_REVOKED,
2417             X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2418         };
2419     } else {
2420         #[allow(bad_style)]
2421         unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2422             (*(*x).crl).lastUpdate
2423         }
2424         #[allow(bad_style)]
2425         unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2426             (*(*x).crl).nextUpdate
2427         }
2428         #[allow(bad_style)]
2429         unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2430             (*(*x).crl).issuer
2431         }
2432         #[allow(bad_style)]
2433         unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2434             (*(*x).crl).revoked
2435         }
2436         #[allow(bad_style)]
2437         unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2438             (*x).serialNumber
2439         }
2440         #[allow(bad_style)]
2441         unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2442             (*x).revocationDate
2443         }
2444     }
2445 }
2446 
2447 #[derive(Copy, Clone, PartialEq, Eq)]
2448 pub struct X509PurposeId(c_int);
2449 
2450 impl X509PurposeId {
2451     pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2452     pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2453     pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2454     pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2455     pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2456     pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2457     pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2458     pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2459     pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2460 
2461     /// Constructs an `X509PurposeId` from a raw OpenSSL value.
from_raw(id: c_int) -> Self2462     pub fn from_raw(id: c_int) -> Self {
2463         X509PurposeId(id)
2464     }
2465 
2466     /// Returns the raw OpenSSL value represented by this type.
as_raw(&self) -> c_int2467     pub fn as_raw(&self) -> c_int {
2468         self.0
2469     }
2470 }
2471 
2472 /// A reference to an [`X509_PURPOSE`].
2473 pub struct X509PurposeRef(Opaque);
2474 
2475 /// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2476 impl ForeignTypeRef for X509PurposeRef {
2477     type CType = ffi::X509_PURPOSE;
2478 }
2479 
2480 impl X509PurposeRef {
2481     /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2482     /// names include
2483     ///  - "sslclient",
2484     ///  - "sslserver",
2485     ///  - "nssslserver",
2486     ///  - "smimesign",
2487     ///  - "smimeencrypt",
2488     ///  - "crlsign",
2489     ///  - "any",
2490     ///  - "ocsphelper",
2491     ///  - "timestampsign"
2492     /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2493     #[allow(clippy::unnecessary_cast)]
get_by_sname(sname: &str) -> Result<c_int, ErrorStack>2494     pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2495         unsafe {
2496             let sname = CString::new(sname).unwrap();
2497             cfg_if! {
2498                 if #[cfg(any(ossl110, libressl280))] {
2499                     let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2500                 } else {
2501                     let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2502                 }
2503             }
2504             Ok(purpose)
2505         }
2506     }
2507     /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2508     /// `X509PurposeRef::get_by_sname()`.
2509     #[corresponds(X509_PURPOSE_get0)]
from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack>2510     pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2511         unsafe {
2512             let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?;
2513             Ok(X509PurposeRef::from_ptr(ptr))
2514         }
2515     }
2516 
2517     /// Get the purpose value from an X509Purpose structure. This value is one of
2518     /// - `X509_PURPOSE_SSL_CLIENT`
2519     /// - `X509_PURPOSE_SSL_SERVER`
2520     /// - `X509_PURPOSE_NS_SSL_SERVER`
2521     /// - `X509_PURPOSE_SMIME_SIGN`
2522     /// - `X509_PURPOSE_SMIME_ENCRYPT`
2523     /// - `X509_PURPOSE_CRL_SIGN`
2524     /// - `X509_PURPOSE_ANY`
2525     /// - `X509_PURPOSE_OCSP_HELPER`
2526     /// - `X509_PURPOSE_TIMESTAMP_SIGN`
purpose(&self) -> X509PurposeId2527     pub fn purpose(&self) -> X509PurposeId {
2528         unsafe {
2529             let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr();
2530             X509PurposeId::from_raw((*x509_purpose).purpose)
2531         }
2532     }
2533 }
2534