Skip to main content

variant_ssl/x509/
mod.rs

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