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