Skip to main content

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