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    pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1349        unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1350    }
1351
1352    to_der! {
1353        /// Serializes the certificate into a DER-encoded X509 name structure.
1354        ///
1355        /// This corresponds to [`i2d_X509_NAME`].
1356        ///
1357        /// [`i2d_X509_NAME`]: https://docs.openssl.org/master/man3/i2d_X509_NAME/
1358        to_der,
1359        ffi::i2d_X509_NAME
1360    }
1361
1362    digest! {
1363        /// Returns a digest of the DER representation of this 'X509Name'.
1364        ///
1365        /// This corresponds to [`X509_NAME_digest`].
1366        ///
1367        /// [`X509_NAME_digest`]: https://docs.openssl.org/manmaster/man3/X509_NAME_digest/
1368        digest,
1369        ffi::X509_NAME_digest
1370    }
1371}
1372
1373impl fmt::Debug for X509NameRef {
1374    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1375        formatter.debug_list().entries(self.entries()).finish()
1376    }
1377}
1378
1379/// A type to destructure and examine an `X509Name`.
1380pub struct X509NameEntries<'a> {
1381    name: &'a X509NameRef,
1382    nid: Option<Nid>,
1383    loc: c_int,
1384}
1385
1386impl<'a> Iterator for X509NameEntries<'a> {
1387    type Item = &'a X509NameEntryRef;
1388
1389    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1390        unsafe {
1391            match self.nid {
1392                Some(nid) => {
1393                    // There is a `Nid` specified to search for
1394                    self.loc =
1395                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1396                    if self.loc == -1 {
1397                        return None;
1398                    }
1399                }
1400                None => {
1401                    // Iterate over all `Nid`s
1402                    self.loc += 1;
1403                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1404                        return None;
1405                    }
1406                }
1407            }
1408
1409            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1410
1411            Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1412        }
1413    }
1414}
1415
1416foreign_type_and_impl_send_sync! {
1417    type CType = ffi::X509_NAME_ENTRY;
1418    fn drop = ffi::X509_NAME_ENTRY_free;
1419
1420    /// A name entry associated with a `X509Name`.
1421    pub struct X509NameEntry;
1422    /// Reference to `X509NameEntry`.
1423    pub struct X509NameEntryRef;
1424}
1425
1426impl X509NameEntryRef {
1427    /// Returns the field value of an `X509NameEntry`.
1428    #[corresponds(X509_NAME_ENTRY_get_data)]
1429    pub fn data(&self) -> &Asn1StringRef {
1430        unsafe {
1431            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1432            Asn1StringRef::from_ptr(data)
1433        }
1434    }
1435
1436    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1437    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1438    #[corresponds(X509_NAME_ENTRY_get_object)]
1439    pub fn object(&self) -> &Asn1ObjectRef {
1440        unsafe {
1441            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1442            Asn1ObjectRef::from_ptr(object)
1443        }
1444    }
1445}
1446
1447impl fmt::Debug for X509NameEntryRef {
1448    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1449        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1450    }
1451}
1452
1453foreign_type_and_impl_send_sync! {
1454    type CType = ffi::X509_PUBKEY;
1455    fn drop = ffi::X509_PUBKEY_free;
1456
1457    /// The SubjectPublicKeyInfo of an `X509` certificate.
1458    pub struct X509Pubkey;
1459    /// Reference to `X509Pubkey`.
1460    pub struct X509PubkeyRef;
1461}
1462
1463impl X509Pubkey {
1464    from_der! {
1465        /// Deserializes a DER-encoded X509 SubjectPublicKeyInfo.
1466        ///
1467        /// This corresponds to [`d2i_X509_PUBKEY`].
1468        ///
1469        /// [`d2i_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/d2i_X509_PUBKEY/
1470        from_der,
1471        X509Pubkey,
1472        ffi::d2i_X509_PUBKEY
1473    }
1474
1475    /// Build a X509Pubkey from the public key.
1476    ///
1477    /// This corresponds to [`X509_PUBKEY_set`].
1478    ///
1479    /// [`X509_PUBKEY_set`]: https://docs.openssl.org/manmaster/crypto/X509_PUBKEY_set/
1480    pub fn from_pubkey<T>(key: &PKeyRef<T>) -> Result<Self, ErrorStack>
1481    where
1482        T: HasPublic,
1483    {
1484        let mut p = ptr::null_mut();
1485        unsafe {
1486            cvt(ffi::X509_PUBKEY_set(&mut p as *mut _, key.as_ptr()))?;
1487        }
1488        Ok(X509Pubkey(p))
1489    }
1490}
1491
1492impl X509PubkeyRef {
1493    /// Copies the X509 SubjectPublicKeyInfo to a new `X509Pubkey`.
1494    #[corresponds(X509_PUBKEY_dup)]
1495    #[cfg(ossl300)]
1496    pub fn to_owned(&self) -> Result<X509Pubkey, ErrorStack> {
1497        unsafe { cvt_p(ffi::X509_PUBKEY_dup(self.as_ptr())).map(|n| X509Pubkey::from_ptr(n)) }
1498    }
1499
1500    to_der! {
1501        /// Serializes the X509 SubjectPublicKeyInfo to DER-encoded.
1502        ///
1503        /// This corresponds to [`i2d_X509_PUBKEY`].
1504        ///
1505        /// [`i2d_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/i2d_X509_PUBKEY/
1506        to_der,
1507        ffi::i2d_X509_PUBKEY
1508    }
1509
1510    /// Returns the public key of the X509 SubjectPublicKeyInfo.
1511    ///
1512    /// This corresponds to [`X509_PUBKEY_get"]
1513    ///
1514    /// [`X509_PUBKEY_get`]: https://docs.openssl.org/manmaster/crypto/X509_PUBKEY_get/
1515    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1516        unsafe {
1517            let key = cvt_p(ffi::X509_PUBKEY_get(self.as_ptr()))?;
1518            Ok(PKey::from_ptr(key))
1519        }
1520    }
1521
1522    /// Get the encoded bytes of the X509 SubjectPublicKeyInfo.
1523    ///
1524    /// This corresponds to ['X509_PUBKEY_get0_param']
1525    ///
1526    /// ['X509_PUBKEY_get0_param']: https://docs.openssl.org/man3.0/man3/X509_PUBKEY_get0_param/
1527    pub fn encoded_bytes(&self) -> Result<&[u8], ErrorStack> {
1528        unsafe {
1529            let mut pk = ptr::null_mut() as *const c_uchar;
1530            let mut pkt_len: c_int = 0;
1531            cvt(ffi::X509_PUBKEY_get0_param(
1532                ptr::null_mut(),
1533                &mut pk as *mut _,
1534                &mut pkt_len as *mut _,
1535                ptr::null_mut(),
1536                self.as_ptr(),
1537            ))?;
1538
1539            Ok(util::from_raw_parts(pk, pkt_len as usize))
1540        }
1541    }
1542}
1543
1544/// A builder used to construct an `X509Req`.
1545pub struct X509ReqBuilder(X509Req);
1546
1547impl X509ReqBuilder {
1548    /// Returns a builder for a certificate request.
1549    #[corresponds(X509_REQ_new)]
1550    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1551        unsafe {
1552            ffi::init();
1553            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1554        }
1555    }
1556
1557    /// Set the numerical value of the version field.
1558    #[corresponds(X509_REQ_set_version)]
1559    #[allow(clippy::useless_conversion)]
1560    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1561        unsafe {
1562            cvt(ffi::X509_REQ_set_version(
1563                self.0.as_ptr(),
1564                version as c_long,
1565            ))
1566            .map(|_| ())
1567        }
1568    }
1569
1570    /// Set the issuer name.
1571    #[corresponds(X509_REQ_set_subject_name)]
1572    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1573        unsafe {
1574            cvt(ffi::X509_REQ_set_subject_name(
1575                self.0.as_ptr(),
1576                subject_name.as_ptr(),
1577            ))
1578            .map(|_| ())
1579        }
1580    }
1581
1582    /// Set the public key.
1583    #[corresponds(X509_REQ_set_pubkey)]
1584    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1585    where
1586        T: HasPublic,
1587    {
1588        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1589    }
1590
1591    /// Return an `X509v3Context`. This context object can be used to construct
1592    /// certain `X509` extensions.
1593    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1594        unsafe {
1595            let mut ctx = mem::zeroed();
1596
1597            ffi::X509V3_set_ctx(
1598                &mut ctx,
1599                ptr::null_mut(),
1600                ptr::null_mut(),
1601                self.0.as_ptr(),
1602                ptr::null_mut(),
1603                0,
1604            );
1605
1606            // nodb case taken care of since we zeroed ctx above
1607            if let Some(conf) = conf {
1608                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1609            }
1610
1611            X509v3Context(ctx, PhantomData)
1612        }
1613    }
1614
1615    /// Permits any number of extension fields to be added to the certificate.
1616    pub fn add_extensions(
1617        &mut self,
1618        extensions: &StackRef<X509Extension>,
1619    ) -> Result<(), ErrorStack> {
1620        unsafe {
1621            cvt(ffi::X509_REQ_add_extensions(
1622                self.0.as_ptr(),
1623                extensions.as_ptr(),
1624            ))
1625            .map(|_| ())
1626        }
1627    }
1628
1629    /// Sign the request using a private key.
1630    #[corresponds(X509_REQ_sign)]
1631    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1632    where
1633        T: HasPrivate,
1634    {
1635        unsafe {
1636            cvt(ffi::X509_REQ_sign(
1637                self.0.as_ptr(),
1638                key.as_ptr(),
1639                hash.as_ptr(),
1640            ))
1641            .map(|_| ())
1642        }
1643    }
1644
1645    /// Returns the `X509Req`.
1646    pub fn build(self) -> X509Req {
1647        self.0
1648    }
1649}
1650
1651foreign_type_and_impl_send_sync! {
1652    type CType = ffi::X509_REQ;
1653    fn drop = ffi::X509_REQ_free;
1654
1655    /// An `X509` certificate request.
1656    pub struct X509Req;
1657    /// Reference to `X509Req`.
1658    pub struct X509ReqRef;
1659}
1660
1661impl X509Req {
1662    /// A builder for `X509Req`.
1663    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1664        X509ReqBuilder::new()
1665    }
1666
1667    from_pem! {
1668        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1669        ///
1670        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1671        ///
1672        /// This corresponds to [`PEM_read_bio_X509_REQ`].
1673        ///
1674        /// [`PEM_read_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_read_bio_X509_REQ/
1675        from_pem,
1676        X509Req,
1677        ffi::PEM_read_bio_X509_REQ
1678    }
1679
1680    from_der! {
1681        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1682        ///
1683        /// This corresponds to [`d2i_X509_REQ`].
1684        ///
1685        /// [`d2i_X509_REQ`]: https://docs.openssl.org/master/man3/d2i_X509_REQ/
1686        from_der,
1687        X509Req,
1688        ffi::d2i_X509_REQ
1689    }
1690}
1691
1692impl X509ReqRef {
1693    to_pem! {
1694        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1695        ///
1696        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1697        ///
1698        /// This corresponds to [`PEM_write_bio_X509_REQ`].
1699        ///
1700        /// [`PEM_write_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_write_bio_X509_REQ/
1701        to_pem,
1702        ffi::PEM_write_bio_X509_REQ
1703    }
1704
1705    to_der! {
1706        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1707        ///
1708        /// This corresponds to [`i2d_X509_REQ`].
1709        ///
1710        /// [`i2d_X509_REQ`]: https://docs.openssl.org/master/man3/i2d_X509_REQ/
1711        to_der,
1712        ffi::i2d_X509_REQ
1713    }
1714
1715    to_pem! {
1716        /// Converts the request to human readable text.
1717        #[corresponds(X509_Req_print)]
1718        to_text,
1719        ffi::X509_REQ_print
1720    }
1721
1722    digest! {
1723        /// Returns a digest of the DER representation of this 'X509Req'.
1724        ///
1725        /// This corresponds to [`X509_REQ_digest`].
1726        ///
1727        /// [`X509_REQ_digest`]: https://docs.openssl.org/manmaster/man3/X509_REQ_digest/
1728        digest,
1729        ffi::X509_REQ_digest
1730    }
1731
1732    /// Returns the numerical value of the version field of the certificate request.
1733    #[corresponds(X509_REQ_get_version)]
1734    #[allow(clippy::unnecessary_cast)]
1735    pub fn version(&self) -> i32 {
1736        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1737    }
1738
1739    /// Returns the subject name of the certificate request.
1740    #[corresponds(X509_REQ_get_subject_name)]
1741    pub fn subject_name(&self) -> &X509NameRef {
1742        unsafe {
1743            let name = X509_REQ_get_subject_name(self.as_ptr());
1744            X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1745        }
1746    }
1747
1748    /// Returns the public key of the certificate request.
1749    #[corresponds(X509_REQ_get_pubkey)]
1750    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1751        unsafe {
1752            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1753            Ok(PKey::from_ptr(key))
1754        }
1755    }
1756
1757    /// Returns the X509Pubkey of the certificate request.
1758    ///
1759    /// This corresponds to [`X509_REQ_get_X509_PUBKEY"]
1760    ///
1761    /// [`X509_REQ_get_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/X509_REQ_get_X509_PUBKEY/
1762    #[cfg(ossl110)]
1763    pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
1764        unsafe {
1765            let key = cvt_p(ffi::X509_REQ_get_X509_PUBKEY(self.as_ptr()))?;
1766            Ok(X509PubkeyRef::from_ptr(key))
1767        }
1768    }
1769
1770    /// Check if the certificate request is signed using the given public key.
1771    ///
1772    /// Returns `true` if verification succeeds.
1773    #[corresponds(X509_REQ_verify)]
1774    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1775    where
1776        T: HasPublic,
1777    {
1778        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1779    }
1780
1781    /// Returns the extensions of the certificate request.
1782    #[corresponds(X509_REQ_get_extensions)]
1783    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1784        unsafe {
1785            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1786            Ok(Stack::from_ptr(extensions))
1787        }
1788    }
1789}
1790
1791/// The reason that a certificate was revoked.
1792#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1793pub struct CrlReason(c_int);
1794
1795#[allow(missing_docs)] // no need to document the constants
1796impl CrlReason {
1797    pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1798    pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1799    pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1800    pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1801    pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1802    pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1803    pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1804    pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1805    pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1806    pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1807
1808    /// Constructs an `CrlReason` from a raw OpenSSL value.
1809    pub const fn from_raw(value: c_int) -> Self {
1810        CrlReason(value)
1811    }
1812
1813    /// Returns the raw OpenSSL value represented by this type.
1814    pub const fn as_raw(&self) -> c_int {
1815        self.0
1816    }
1817}
1818
1819foreign_type_and_impl_send_sync! {
1820    type CType = ffi::X509_REVOKED;
1821    fn drop = ffi::X509_REVOKED_free;
1822
1823    /// An `X509` certificate revocation status.
1824    pub struct X509Revoked;
1825    /// Reference to `X509Revoked`.
1826    pub struct X509RevokedRef;
1827}
1828
1829impl Stackable for X509Revoked {
1830    type StackType = ffi::stack_st_X509_REVOKED;
1831}
1832
1833impl X509Revoked {
1834    from_der! {
1835        /// Deserializes a DER-encoded certificate revocation status
1836        #[corresponds(d2i_X509_REVOKED)]
1837        from_der,
1838        X509Revoked,
1839        ffi::d2i_X509_REVOKED
1840    }
1841}
1842
1843impl X509RevokedRef {
1844    to_der! {
1845        /// Serializes the certificate request to a DER-encoded certificate revocation status
1846        #[corresponds(d2i_X509_REVOKED)]
1847        to_der,
1848        ffi::i2d_X509_REVOKED
1849    }
1850
1851    /// Copies the entry to a new `X509Revoked`.
1852    #[corresponds(X509_REVOKED_dup)]
1853    pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1854        unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1855    }
1856
1857    /// Get the date that the certificate was revoked
1858    #[corresponds(X509_REVOKED_get0_revocationDate)]
1859    pub fn revocation_date(&self) -> &Asn1TimeRef {
1860        unsafe {
1861            let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1862            assert!(!r.is_null());
1863            Asn1TimeRef::from_ptr(r as *mut _)
1864        }
1865    }
1866
1867    /// Get the serial number of the revoked certificate
1868    #[corresponds(X509_REVOKED_get0_serialNumber)]
1869    pub fn serial_number(&self) -> &Asn1IntegerRef {
1870        unsafe {
1871            let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1872            assert!(!r.is_null());
1873            Asn1IntegerRef::from_ptr(r as *mut _)
1874        }
1875    }
1876
1877    /// Get the criticality and value of an extension.
1878    ///
1879    /// This returns None if the extension is not present or occurs multiple times.
1880    #[corresponds(X509_REVOKED_get_ext_d2i)]
1881    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1882        let mut critical = -1;
1883        let out = unsafe {
1884            // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
1885            let ext = ffi::X509_REVOKED_get_ext_d2i(
1886                self.as_ptr(),
1887                T::NID.as_raw(),
1888                &mut critical as *mut _,
1889                ptr::null_mut(),
1890            );
1891            // SAFETY: Extensions's contract promises that the type returned by
1892            // OpenSSL here is T::Output.
1893            T::Output::from_ptr_opt(ext as *mut _)
1894        };
1895        match (critical, out) {
1896            (0, Some(out)) => Ok(Some((false, out))),
1897            (1, Some(out)) => Ok(Some((true, out))),
1898            // -1 means the extension wasn't found, -2 means multiple were found.
1899            (-1 | -2, _) => Ok(None),
1900            // A critical value of 0 or 1 suggests success, but a null pointer
1901            // was returned so something went wrong.
1902            (0 | 1, None) => Err(ErrorStack::get()),
1903            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1904        }
1905    }
1906}
1907
1908/// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
1909/// this is as defined in RFC 5280 Section 5.3.1.
1910pub enum ReasonCode {}
1911
1912// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1913// and in OpenSSL.
1914unsafe impl ExtensionType for ReasonCode {
1915    const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1916
1917    type Output = Asn1Enumerated;
1918}
1919
1920/// The CRL entry extension identifying the issuer of a certificate used in
1921/// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
1922pub enum CertificateIssuer {}
1923
1924// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1925// and in OpenSSL.
1926unsafe impl ExtensionType for CertificateIssuer {
1927    const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1928
1929    type Output = Stack<GeneralName>;
1930}
1931
1932/// The CRL extension identifying how to access information and services for the issuer of the CRL
1933pub enum AuthorityInformationAccess {}
1934
1935// SAFETY: AuthorityInformationAccess is defined to be a stack of AccessDescription in the RFC
1936// and in OpenSSL.
1937unsafe impl ExtensionType for AuthorityInformationAccess {
1938    const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1939
1940    type Output = Stack<AccessDescription>;
1941}
1942
1943foreign_type_and_impl_send_sync! {
1944    type CType = ffi::X509_CRL;
1945    fn drop = ffi::X509_CRL_free;
1946
1947    /// An `X509` certificate revocation list.
1948    pub struct X509Crl;
1949    /// Reference to `X509Crl`.
1950    pub struct X509CrlRef;
1951}
1952
1953/// The status of a certificate in a revoction list
1954///
1955/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1956///
1957/// [`X509_CRL_get0_by_*`]: https://docs.openssl.org/master/man3/X509_CRL_get0_by_serial/
1958pub enum CrlStatus<'a> {
1959    /// The certificate is not present in the list
1960    NotRevoked,
1961    /// The certificate is in the list and is revoked
1962    Revoked(&'a X509RevokedRef),
1963    /// The certificate is in the list, but has the "removeFromCrl" status.
1964    ///
1965    /// This can occur if the certificate was revoked with the "CertificateHold"
1966    /// reason, and has since been unrevoked.
1967    RemoveFromCrl(&'a X509RevokedRef),
1968}
1969
1970impl<'a> CrlStatus<'a> {
1971    // Helper used by the X509_CRL_get0_by_* methods to convert their return
1972    // value to the status enum.
1973    // Safety note: the returned CrlStatus must not outlive the owner of the
1974    // revoked_entry pointer.
1975    unsafe fn from_ffi_status(
1976        status: c_int,
1977        revoked_entry: *mut ffi::X509_REVOKED,
1978    ) -> CrlStatus<'a> {
1979        match status {
1980            0 => CrlStatus::NotRevoked,
1981            1 => {
1982                assert!(!revoked_entry.is_null());
1983                CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1984            }
1985            2 => {
1986                assert!(!revoked_entry.is_null());
1987                CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1988            }
1989            _ => unreachable!(
1990                "{}",
1991                "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1992            ),
1993        }
1994    }
1995}
1996
1997impl X509Crl {
1998    from_pem! {
1999        /// Deserializes a PEM-encoded Certificate Revocation List
2000        ///
2001        /// The input should have a header of `-----BEGIN X509 CRL-----`.
2002        #[corresponds(PEM_read_bio_X509_CRL)]
2003        from_pem,
2004        X509Crl,
2005        ffi::PEM_read_bio_X509_CRL
2006    }
2007
2008    from_der! {
2009        /// Deserializes a DER-encoded Certificate Revocation List
2010        #[corresponds(d2i_X509_CRL)]
2011        from_der,
2012        X509Crl,
2013        ffi::d2i_X509_CRL
2014    }
2015}
2016
2017impl X509CrlRef {
2018    to_pem! {
2019        /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
2020        ///
2021        /// The output will have a header of `-----BEGIN X509 CRL-----`.
2022        #[corresponds(PEM_write_bio_X509_CRL)]
2023        to_pem,
2024        ffi::PEM_write_bio_X509_CRL
2025    }
2026
2027    to_der! {
2028        /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
2029        #[corresponds(i2d_X509_CRL)]
2030        to_der,
2031        ffi::i2d_X509_CRL
2032    }
2033
2034    digest! {
2035        /// Returns a digest of the DER representation of this 'X509Crl'.
2036        ///
2037        /// This corresponds to [`X509_CRL_digest`].
2038        ///
2039        /// [`X509_CRL_digest`]: https://docs.openssl.org/manmaster/man3/X509_CRL_digest/
2040        digest,
2041        ffi::X509_CRL_digest
2042    }
2043
2044    /// Get the stack of revocation entries
2045    pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
2046        unsafe {
2047            let revoked = X509_CRL_get_REVOKED(self.as_ptr());
2048            if revoked.is_null() {
2049                None
2050            } else {
2051                Some(StackRef::from_ptr(revoked))
2052            }
2053        }
2054    }
2055
2056    /// Returns the CRL's `lastUpdate` time.
2057    #[corresponds(X509_CRL_get0_lastUpdate)]
2058    pub fn last_update(&self) -> &Asn1TimeRef {
2059        unsafe {
2060            let date = X509_CRL_get0_lastUpdate(self.as_ptr());
2061            assert!(!date.is_null());
2062            Asn1TimeRef::from_ptr(date as *mut _)
2063        }
2064    }
2065
2066    /// Returns the CRL's `nextUpdate` time.
2067    ///
2068    /// If the `nextUpdate` field is missing, returns `None`.
2069    #[corresponds(X509_CRL_get0_nextUpdate)]
2070    pub fn next_update(&self) -> Option<&Asn1TimeRef> {
2071        unsafe {
2072            let date = X509_CRL_get0_nextUpdate(self.as_ptr());
2073            Asn1TimeRef::from_const_ptr_opt(date)
2074        }
2075    }
2076
2077    /// Get the revocation status of a certificate by its serial number
2078    #[corresponds(X509_CRL_get0_by_serial)]
2079    pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
2080        unsafe {
2081            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2082            let status =
2083                ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
2084            CrlStatus::from_ffi_status(status, ret)
2085        }
2086    }
2087
2088    /// Get the revocation status of a certificate
2089    #[corresponds(X509_CRL_get0_by_cert)]
2090    pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
2091        unsafe {
2092            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2093            let status =
2094                ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
2095            CrlStatus::from_ffi_status(status, ret)
2096        }
2097    }
2098
2099    /// Get the issuer name from the revocation list.
2100    #[corresponds(X509_CRL_get_issuer)]
2101    pub fn issuer_name(&self) -> &X509NameRef {
2102        unsafe {
2103            let name = X509_CRL_get_issuer(self.as_ptr());
2104            assert!(!name.is_null());
2105            X509NameRef::from_ptr(name)
2106        }
2107    }
2108
2109    /// Check if the CRL is signed using the given public key.
2110    ///
2111    /// Only the signature is checked: no other checks (such as certificate chain validity)
2112    /// are performed.
2113    ///
2114    /// Returns `true` if verification succeeds.
2115    #[corresponds(X509_CRL_verify)]
2116    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
2117    where
2118        T: HasPublic,
2119    {
2120        unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
2121    }
2122
2123    /// Get the criticality and value of an extension.
2124    ///
2125    /// This returns None if the extension is not present or occurs multiple times.
2126    #[corresponds(X509_CRL_get_ext_d2i)]
2127    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
2128        let mut critical = -1;
2129        let out = unsafe {
2130            // SAFETY: self.as_ptr() is a valid pointer to an X509_CRL.
2131            let ext = ffi::X509_CRL_get_ext_d2i(
2132                self.as_ptr(),
2133                T::NID.as_raw(),
2134                &mut critical as *mut _,
2135                ptr::null_mut(),
2136            );
2137            // SAFETY: Extensions's contract promises that the type returned by
2138            // OpenSSL here is T::Output.
2139            T::Output::from_ptr_opt(ext as *mut _)
2140        };
2141        match (critical, out) {
2142            (0, Some(out)) => Ok(Some((false, out))),
2143            (1, Some(out)) => Ok(Some((true, out))),
2144            // -1 means the extension wasn't found, -2 means multiple were found.
2145            (-1 | -2, _) => Ok(None),
2146            // A critical value of 0 or 1 suggests success, but a null pointer
2147            // was returned so something went wrong.
2148            (0 | 1, None) => Err(ErrorStack::get()),
2149            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
2150        }
2151    }
2152}
2153
2154/// The result of peer certificate verification.
2155#[derive(Copy, Clone, PartialEq, Eq)]
2156pub struct X509VerifyResult(c_int);
2157
2158impl fmt::Debug for X509VerifyResult {
2159    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2160        fmt.debug_struct("X509VerifyResult")
2161            .field("code", &self.0)
2162            .field("error", &self.error_string())
2163            .finish()
2164    }
2165}
2166
2167impl fmt::Display for X509VerifyResult {
2168    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2169        fmt.write_str(self.error_string())
2170    }
2171}
2172
2173impl Error for X509VerifyResult {}
2174
2175impl X509VerifyResult {
2176    /// Creates an `X509VerifyResult` from a raw error number.
2177    ///
2178    /// # Safety
2179    ///
2180    /// Some methods on `X509VerifyResult` are not thread safe if the error
2181    /// number is invalid.
2182    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
2183        X509VerifyResult(err)
2184    }
2185
2186    /// Return the integer representation of an `X509VerifyResult`.
2187    #[allow(clippy::trivially_copy_pass_by_ref)]
2188    pub fn as_raw(&self) -> c_int {
2189        self.0
2190    }
2191
2192    /// Return a human readable error string from the verification error.
2193    #[corresponds(X509_verify_cert_error_string)]
2194    #[allow(clippy::trivially_copy_pass_by_ref)]
2195    pub fn error_string(&self) -> &'static str {
2196        ffi::init();
2197
2198        unsafe {
2199            let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
2200            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
2201        }
2202    }
2203
2204    /// Successful peer certificate verification.
2205    pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
2206    /// Application verification failure.
2207    pub const APPLICATION_VERIFICATION: X509VerifyResult =
2208        X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
2209}
2210
2211foreign_type_and_impl_send_sync! {
2212    type CType = ffi::GENERAL_NAME;
2213    fn drop = ffi::GENERAL_NAME_free;
2214
2215    /// An `X509` certificate alternative names.
2216    pub struct GeneralName;
2217    /// Reference to `GeneralName`.
2218    pub struct GeneralNameRef;
2219}
2220
2221impl GeneralName {
2222    unsafe fn new(
2223        type_: c_int,
2224        asn1_type: Asn1Type,
2225        value: &[u8],
2226    ) -> Result<GeneralName, ErrorStack> {
2227        ffi::init();
2228        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2229        (*gn.as_ptr()).type_ = type_;
2230        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2231        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2232
2233        #[cfg(any(boringssl, awslc))]
2234        {
2235            (*gn.as_ptr()).d.ptr = s.cast();
2236        }
2237        #[cfg(not(any(boringssl, awslc)))]
2238        {
2239            (*gn.as_ptr()).d = s.cast();
2240        }
2241
2242        Ok(gn)
2243    }
2244
2245    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2246        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2247    }
2248
2249    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2250        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2251    }
2252
2253    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2254        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2255    }
2256
2257    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2258        match ip {
2259            IpAddr::V4(addr) => unsafe {
2260                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2261            },
2262            IpAddr::V6(addr) => unsafe {
2263                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2264            },
2265        }
2266    }
2267
2268    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2269        unsafe {
2270            ffi::init();
2271            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2272            (*gn).type_ = ffi::GEN_RID;
2273
2274            #[cfg(any(boringssl, awslc))]
2275            {
2276                (*gn).d.registeredID = oid.as_ptr();
2277            }
2278            #[cfg(not(any(boringssl, awslc)))]
2279            {
2280                (*gn).d = oid.as_ptr().cast();
2281            }
2282
2283            mem::forget(oid);
2284
2285            Ok(GeneralName::from_ptr(gn))
2286        }
2287    }
2288
2289    pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2290        unsafe {
2291            ffi::init();
2292
2293            let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2294                ptr::null_mut(),
2295                &mut value.as_ptr().cast(),
2296                value.len().try_into().unwrap(),
2297            ))?;
2298
2299            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2300            (*gn).type_ = ffi::GEN_OTHERNAME;
2301
2302            if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2303                gn,
2304                oid.as_ptr().cast(),
2305                typ,
2306            )) {
2307                ffi::GENERAL_NAME_free(gn);
2308                return Err(e);
2309            }
2310
2311            mem::forget(oid);
2312
2313            Ok(GeneralName::from_ptr(gn))
2314        }
2315    }
2316
2317    pub(crate) fn new_dir_name(name: &X509NameRef) -> Result<GeneralName, ErrorStack> {
2318        unsafe {
2319            ffi::init();
2320            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2321            (*gn).type_ = ffi::GEN_DIRNAME;
2322
2323            let dup = match name.to_owned() {
2324                Ok(dup) => dup,
2325                Err(e) => {
2326                    ffi::GENERAL_NAME_free(gn);
2327                    return Err(e);
2328                }
2329            };
2330
2331            #[cfg(any(boringssl, awslc))]
2332            {
2333                (*gn).d.directoryName = dup.as_ptr();
2334            }
2335            #[cfg(not(any(boringssl, awslc)))]
2336            {
2337                (*gn).d = dup.as_ptr().cast();
2338            }
2339
2340            std::mem::forget(dup);
2341
2342            Ok(GeneralName::from_ptr(gn))
2343        }
2344    }
2345}
2346
2347impl GeneralNameRef {
2348    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2349        unsafe {
2350            if (*self.as_ptr()).type_ != ffi_type {
2351                return None;
2352            }
2353
2354            #[cfg(any(boringssl, awslc))]
2355            let d = (*self.as_ptr()).d.ptr;
2356            #[cfg(not(any(boringssl, awslc)))]
2357            let d = (*self.as_ptr()).d;
2358
2359            let ptr = ASN1_STRING_get0_data(d as *mut _);
2360            let len = ffi::ASN1_STRING_length(d as *mut _);
2361
2362            #[allow(clippy::unnecessary_cast)]
2363            let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2364            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
2365            // OpenSSL checks that when loading a certificate but if not we'll
2366            // use this instead of from_utf8_unchecked just in case.
2367            str::from_utf8(slice).ok()
2368        }
2369    }
2370
2371    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
2372    pub fn email(&self) -> Option<&str> {
2373        self.ia5_string(ffi::GEN_EMAIL)
2374    }
2375
2376    /// Returns the contents of this `GeneralName` if it is a `directoryName`.
2377    pub fn directory_name(&self) -> Option<&X509NameRef> {
2378        unsafe {
2379            if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2380                return None;
2381            }
2382
2383            #[cfg(any(boringssl, awslc))]
2384            let d = (*self.as_ptr()).d.ptr;
2385            #[cfg(not(any(boringssl, awslc)))]
2386            let d = (*self.as_ptr()).d;
2387
2388            Some(X509NameRef::from_const_ptr(d as *const _))
2389        }
2390    }
2391
2392    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
2393    pub fn dnsname(&self) -> Option<&str> {
2394        self.ia5_string(ffi::GEN_DNS)
2395    }
2396
2397    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
2398    pub fn uri(&self) -> Option<&str> {
2399        self.ia5_string(ffi::GEN_URI)
2400    }
2401
2402    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
2403    pub fn ipaddress(&self) -> Option<&[u8]> {
2404        unsafe {
2405            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2406                return None;
2407            }
2408            #[cfg(any(boringssl, awslc))]
2409            let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2410            #[cfg(not(any(boringssl, awslc)))]
2411            let d = (*self.as_ptr()).d;
2412
2413            let ptr = ASN1_STRING_get0_data(d as *mut _);
2414            let len = ffi::ASN1_STRING_length(d as *mut _);
2415
2416            #[allow(clippy::unnecessary_cast)]
2417            Some(util::from_raw_parts(ptr as *const u8, len as usize))
2418        }
2419    }
2420}
2421
2422impl fmt::Debug for GeneralNameRef {
2423    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2424        if let Some(email) = self.email() {
2425            formatter.write_str(email)
2426        } else if let Some(dnsname) = self.dnsname() {
2427            formatter.write_str(dnsname)
2428        } else if let Some(uri) = self.uri() {
2429            formatter.write_str(uri)
2430        } else if let Some(ipaddress) = self.ipaddress() {
2431            let address = <[u8; 16]>::try_from(ipaddress)
2432                .map(IpAddr::from)
2433                .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2434            match address {
2435                Ok(a) => fmt::Debug::fmt(&a, formatter),
2436                Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2437            }
2438        } else {
2439            formatter.write_str("(empty)")
2440        }
2441    }
2442}
2443
2444impl Stackable for GeneralName {
2445    type StackType = ffi::stack_st_GENERAL_NAME;
2446}
2447
2448foreign_type_and_impl_send_sync! {
2449    type CType = ffi::DIST_POINT;
2450    fn drop = ffi::DIST_POINT_free;
2451
2452    /// A `X509` distribution point.
2453    pub struct DistPoint;
2454    /// Reference to `DistPoint`.
2455    pub struct DistPointRef;
2456}
2457
2458impl DistPointRef {
2459    /// Returns the name of this distribution point if it exists
2460    pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2461        unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2462    }
2463}
2464
2465foreign_type_and_impl_send_sync! {
2466    type CType = ffi::DIST_POINT_NAME;
2467    fn drop = ffi::DIST_POINT_NAME_free;
2468
2469    /// A `X509` distribution point.
2470    pub struct DistPointName;
2471    /// Reference to `DistPointName`.
2472    pub struct DistPointNameRef;
2473}
2474
2475impl DistPointNameRef {
2476    /// Returns the contents of this DistPointName if it is a fullname.
2477    pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2478        unsafe {
2479            if (*self.as_ptr()).type_ != 0 {
2480                return None;
2481            }
2482            StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2483        }
2484    }
2485}
2486
2487impl Stackable for DistPoint {
2488    type StackType = ffi::stack_st_DIST_POINT;
2489}
2490
2491foreign_type_and_impl_send_sync! {
2492    type CType = ffi::BASIC_CONSTRAINTS;
2493    fn drop = ffi::BASIC_CONSTRAINTS_free;
2494
2495    /// A `X509` basic constraints.
2496    pub struct BasicConstraints;
2497    /// Reference to `BasicConstraints`.
2498    pub struct BasicConstraintsRef;
2499}
2500
2501impl BasicConstraintsRef {
2502    pub fn ca(&self) -> bool {
2503        unsafe { (*(self.as_ptr())).ca != 0 }
2504    }
2505
2506    pub fn pathlen(&self) -> Option<&Asn1IntegerRef> {
2507        if !self.ca() {
2508            return None;
2509        }
2510        unsafe {
2511            let data = (*(self.as_ptr())).pathlen;
2512            Asn1IntegerRef::from_const_ptr_opt(data as _)
2513        }
2514    }
2515}
2516
2517foreign_type_and_impl_send_sync! {
2518    type CType = ffi::ACCESS_DESCRIPTION;
2519    fn drop = ffi::ACCESS_DESCRIPTION_free;
2520
2521    /// `AccessDescription` of certificate authority information.
2522    pub struct AccessDescription;
2523    /// Reference to `AccessDescription`.
2524    pub struct AccessDescriptionRef;
2525}
2526
2527impl AccessDescriptionRef {
2528    /// Returns the access method OID.
2529    pub fn method(&self) -> &Asn1ObjectRef {
2530        unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2531    }
2532
2533    // Returns the access location.
2534    pub fn location(&self) -> &GeneralNameRef {
2535        unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2536    }
2537}
2538
2539impl Stackable for AccessDescription {
2540    type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2541}
2542
2543foreign_type_and_impl_send_sync! {
2544    type CType = ffi::X509_ALGOR;
2545    fn drop = ffi::X509_ALGOR_free;
2546
2547    /// An `X509` certificate signature algorithm.
2548    pub struct X509Algorithm;
2549    /// Reference to `X509Algorithm`.
2550    pub struct X509AlgorithmRef;
2551}
2552
2553impl X509AlgorithmRef {
2554    /// Returns the ASN.1 OID of this algorithm.
2555    pub fn object(&self) -> &Asn1ObjectRef {
2556        unsafe {
2557            let mut oid = ptr::null();
2558            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2559            Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2560        }
2561    }
2562}
2563
2564foreign_type_and_impl_send_sync! {
2565    type CType = ffi::X509_OBJECT;
2566    fn drop = X509_OBJECT_free;
2567
2568    /// An `X509` or an X509 certificate revocation list.
2569    pub struct X509Object;
2570    /// Reference to `X509Object`
2571    pub struct X509ObjectRef;
2572}
2573
2574impl X509ObjectRef {
2575    pub fn x509(&self) -> Option<&X509Ref> {
2576        unsafe {
2577            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2578            X509Ref::from_const_ptr_opt(ptr)
2579        }
2580    }
2581}
2582
2583impl Stackable for X509Object {
2584    type StackType = ffi::stack_st_X509_OBJECT;
2585}
2586
2587cfg_if! {
2588    if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2589        use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2590    } else {
2591        #[allow(bad_style)]
2592        unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2593            (*(*(*x).cert_info).validity).notAfter
2594        }
2595
2596        #[allow(bad_style)]
2597        unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2598            (*(*(*x).cert_info).validity).notBefore
2599        }
2600
2601        #[allow(bad_style)]
2602        unsafe fn X509_up_ref(x: *mut ffi::X509) {
2603            ffi::CRYPTO_add_lock(
2604                &mut (*x).references,
2605                1,
2606                ffi::CRYPTO_LOCK_X509,
2607                "mod.rs\0".as_ptr() as *const _,
2608                line!() as c_int,
2609            );
2610        }
2611
2612        #[allow(bad_style)]
2613        unsafe fn X509_get0_signature(
2614            psig: *mut *const ffi::ASN1_BIT_STRING,
2615            palg: *mut *const ffi::X509_ALGOR,
2616            x: *const ffi::X509,
2617        ) {
2618            if !psig.is_null() {
2619                *psig = (*x).signature;
2620            }
2621            if !palg.is_null() {
2622                *palg = (*x).sig_alg;
2623            }
2624        }
2625    }
2626}
2627
2628cfg_if! {
2629    if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2630        use ffi::{
2631            X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2632            X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2633        };
2634    } else {
2635        use ffi::{
2636            ASN1_STRING_data as ASN1_STRING_get0_data,
2637            X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2638            X509_set_notAfter as X509_set1_notAfter,
2639            X509_set_notBefore as X509_set1_notBefore,
2640        };
2641
2642        #[allow(bad_style)]
2643        unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2644            ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2645        }
2646
2647        #[allow(bad_style)]
2648        unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2649            (*(*x).req_info).subject
2650        }
2651
2652        #[allow(bad_style)]
2653        unsafe fn X509_ALGOR_get0(
2654            paobj: *mut *const ffi::ASN1_OBJECT,
2655            pptype: *mut c_int,
2656            pval: *mut *mut ::libc::c_void,
2657            alg: *const ffi::X509_ALGOR,
2658        ) {
2659            if !paobj.is_null() {
2660                *paobj = (*alg).algorithm;
2661            }
2662            assert!(pptype.is_null());
2663            assert!(pval.is_null());
2664        }
2665    }
2666}
2667
2668cfg_if! {
2669    if #[cfg(any(ossl110, boringssl, libressl, awslc))] {
2670        use ffi::X509_OBJECT_get0_X509;
2671    } else {
2672        #[allow(bad_style)]
2673        unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2674            if (*x).type_ == ffi::X509_LU_X509 {
2675                (*x).data.x509
2676            } else {
2677                ptr::null_mut()
2678            }
2679        }
2680    }
2681}
2682
2683cfg_if! {
2684    if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2685        use ffi::X509_OBJECT_free;
2686    } else {
2687        #[allow(bad_style)]
2688        unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2689            ffi::X509_OBJECT_free_contents(x);
2690            ffi::CRYPTO_free(x as *mut libc::c_void);
2691        }
2692    }
2693}
2694
2695cfg_if! {
2696    if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2697        use ffi::{
2698            X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2699            X509_CRL_get_REVOKED,
2700            X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2701        };
2702    } else {
2703        #[allow(bad_style)]
2704        unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2705            (*(*x).crl).lastUpdate
2706        }
2707        #[allow(bad_style)]
2708        unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2709            (*(*x).crl).nextUpdate
2710        }
2711        #[allow(bad_style)]
2712        unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2713            (*(*x).crl).issuer
2714        }
2715        #[allow(bad_style)]
2716        unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2717            (*(*x).crl).revoked
2718        }
2719        #[allow(bad_style)]
2720        unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2721            (*x).serialNumber
2722        }
2723        #[allow(bad_style)]
2724        unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2725            (*x).revocationDate
2726        }
2727    }
2728}
2729
2730#[derive(Copy, Clone, PartialEq, Eq)]
2731pub struct X509PurposeId(c_int);
2732
2733impl X509PurposeId {
2734    pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2735    pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2736    pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2737    pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2738    pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2739    pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2740    pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2741    pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2742    pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2743    #[cfg(ossl320)]
2744    pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2745
2746    /// Constructs an `X509PurposeId` from a raw OpenSSL value.
2747    pub fn from_raw(id: c_int) -> Self {
2748        X509PurposeId(id)
2749    }
2750
2751    /// Returns the raw OpenSSL value represented by this type.
2752    pub fn as_raw(&self) -> c_int {
2753        self.0
2754    }
2755}
2756
2757/// A reference to an [`X509_PURPOSE`].
2758pub struct X509PurposeRef(Opaque);
2759
2760/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2761impl ForeignTypeRef for X509PurposeRef {
2762    type CType = ffi::X509_PURPOSE;
2763}
2764
2765impl X509PurposeRef {
2766    /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2767    /// names include
2768    ///  - "sslclient",
2769    ///  - "sslserver",
2770    ///  - "nssslserver",
2771    ///  - "smimesign",
2772    ///  - "smimeencrypt",
2773    ///  - "crlsign",
2774    ///  - "any",
2775    ///  - "ocsphelper",
2776    ///  - "timestampsign"
2777    ///
2778    /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2779    #[allow(clippy::unnecessary_cast)]
2780    pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2781        unsafe {
2782            let sname = CString::new(sname).unwrap();
2783            cfg_if! {
2784                if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2785                    let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2786                } else {
2787                    let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2788                }
2789            }
2790            Ok(purpose)
2791        }
2792    }
2793    /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2794    /// `X509PurposeRef::get_by_sname()`.
2795    #[corresponds(X509_PURPOSE_get0)]
2796    pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2797        unsafe {
2798            let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2799            Ok(X509PurposeRef::from_const_ptr(ptr))
2800        }
2801    }
2802
2803    /// Get the purpose value from an X509Purpose structure. This value is one of
2804    /// - `X509_PURPOSE_SSL_CLIENT`
2805    /// - `X509_PURPOSE_SSL_SERVER`
2806    /// - `X509_PURPOSE_NS_SSL_SERVER`
2807    /// - `X509_PURPOSE_SMIME_SIGN`
2808    /// - `X509_PURPOSE_SMIME_ENCRYPT`
2809    /// - `X509_PURPOSE_CRL_SIGN`
2810    /// - `X509_PURPOSE_ANY`
2811    /// - `X509_PURPOSE_OCSP_HELPER`
2812    /// - `X509_PURPOSE_TIMESTAMP_SIGN`
2813    pub fn purpose(&self) -> X509PurposeId {
2814        unsafe {
2815            cfg_if! {
2816                if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2817                    let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2818                } else {
2819                    let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2820                }
2821            }
2822            X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2823        }
2824    }
2825}