Skip to main content

variant_ssl/x509/
mod.rs

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