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