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