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    #[corresponds(X509_get1_ocsp)]
602    pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
603        unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
604    }
605
606    /// Checks that this certificate issued `subject`.
607    #[corresponds(X509_check_issued)]
608    pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
609        unsafe {
610            let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
611            X509VerifyResult::from_raw(r)
612        }
613    }
614
615    /// Returns certificate version. If this certificate has no explicit version set, it defaults to
616    /// version 1.
617    ///
618    /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
619    #[corresponds(X509_get_version)]
620    #[cfg(ossl110)]
621    #[allow(clippy::unnecessary_cast)]
622    pub fn version(&self) -> i32 {
623        unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
624    }
625
626    /// Check if the certificate is signed using the given public key.
627    ///
628    /// Only the signature is checked: no other checks (such as certificate chain validity)
629    /// are performed.
630    ///
631    /// Returns `true` if verification succeeds.
632    #[corresponds(X509_verify)]
633    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
634    where
635        T: HasPublic,
636    {
637        unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
638    }
639
640    /// Returns this certificate's serial number.
641    #[corresponds(X509_get_serialNumber)]
642    pub fn serial_number(&self) -> &Asn1IntegerRef {
643        unsafe {
644            let r = ffi::X509_get_serialNumber(self.as_ptr());
645            Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
646        }
647    }
648
649    /// Returns this certificate's "alias". This field is populated by
650    /// OpenSSL in some situations -- specifically OpenSSL will store a
651    /// PKCS#12 `friendlyName` in this field. This is not a part of the X.509
652    /// certificate itself, OpenSSL merely attaches it to this structure in
653    /// memory.
654    #[corresponds(X509_alias_get0)]
655    pub fn alias(&self) -> Option<&[u8]> {
656        unsafe {
657            let mut len = 0;
658            let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len);
659            if ptr.is_null() {
660                None
661            } else {
662                Some(util::from_raw_parts(ptr, len as usize))
663            }
664        }
665    }
666
667    to_pem! {
668        /// Serializes the certificate into a PEM-encoded X509 structure.
669        ///
670        /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
671        #[corresponds(PEM_write_bio_X509)]
672        to_pem,
673        ffi::PEM_write_bio_X509
674    }
675
676    to_der! {
677        /// Serializes the certificate into a DER-encoded X509 structure.
678        #[corresponds(i2d_X509)]
679        to_der,
680        ffi::i2d_X509
681    }
682
683    to_pem! {
684        /// Converts the certificate to human readable text.
685        #[corresponds(X509_print)]
686        to_text,
687        ffi::X509_print
688    }
689}
690
691impl ToOwned for X509Ref {
692    type Owned = X509;
693
694    fn to_owned(&self) -> X509 {
695        unsafe {
696            X509_up_ref(self.as_ptr());
697            X509::from_ptr(self.as_ptr())
698        }
699    }
700}
701
702impl Ord for X509Ref {
703    fn cmp(&self, other: &Self) -> cmp::Ordering {
704        // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
705        // It can't fail if both pointers are valid, which we know is true.
706        let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
707        cmp.cmp(&0)
708    }
709}
710
711impl PartialOrd for X509Ref {
712    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
713        Some(self.cmp(other))
714    }
715}
716
717impl PartialOrd<X509> for X509Ref {
718    fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
719        <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
720    }
721}
722
723impl PartialEq for X509Ref {
724    fn eq(&self, other: &Self) -> bool {
725        self.cmp(other) == cmp::Ordering::Equal
726    }
727}
728
729impl PartialEq<X509> for X509Ref {
730    fn eq(&self, other: &X509) -> bool {
731        <X509Ref as PartialEq<X509Ref>>::eq(self, other)
732    }
733}
734
735impl Eq for X509Ref {}
736
737impl X509 {
738    /// Returns a new builder.
739    pub fn builder() -> Result<X509Builder, ErrorStack> {
740        X509Builder::new()
741    }
742
743    from_pem! {
744        /// Deserializes a PEM-encoded X509 structure.
745        ///
746        /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
747        #[corresponds(PEM_read_bio_X509)]
748        from_pem,
749        X509,
750        ffi::PEM_read_bio_X509
751    }
752
753    from_der! {
754        /// Deserializes a DER-encoded X509 structure.
755        #[corresponds(d2i_X509)]
756        from_der,
757        X509,
758        ffi::d2i_X509
759    }
760
761    /// Deserializes a list of PEM-formatted certificates.
762    #[corresponds(PEM_read_bio_X509)]
763    pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
764        unsafe {
765            ffi::init();
766            let bio = MemBioSlice::new(pem)?;
767
768            let mut certs = vec![];
769            loop {
770                let r =
771                    ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
772                if r.is_null() {
773                    let e = ErrorStack::get();
774
775                    if let Some(err) = e.errors().last() {
776                        if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int
777                            && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int
778                        {
779                            break;
780                        }
781                    }
782
783                    return Err(e);
784                } else {
785                    certs.push(X509(r));
786                }
787            }
788
789            Ok(certs)
790        }
791    }
792}
793
794impl Clone for X509 {
795    fn clone(&self) -> X509 {
796        X509Ref::to_owned(self)
797    }
798}
799
800impl fmt::Debug for X509 {
801    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
802        let serial = match &self.serial_number().to_bn() {
803            Ok(bn) => match bn.to_hex_str() {
804                Ok(hex) => hex.to_string(),
805                Err(_) => "".to_string(),
806            },
807            Err(_) => "".to_string(),
808        };
809        let mut debug_struct = formatter.debug_struct("X509");
810        debug_struct.field("serial_number", &serial);
811        debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
812        debug_struct.field("issuer", &self.issuer_name());
813        debug_struct.field("subject", &self.subject_name());
814        if let Some(subject_alt_names) = &self.subject_alt_names() {
815            debug_struct.field("subject_alt_names", subject_alt_names);
816        }
817        debug_struct.field("not_before", &self.not_before());
818        debug_struct.field("not_after", &self.not_after());
819
820        if let Ok(public_key) = &self.public_key() {
821            debug_struct.field("public_key", public_key);
822        };
823        // TODO: Print extensions once they are supported on the X509 struct.
824
825        debug_struct.finish()
826    }
827}
828
829impl AsRef<X509Ref> for X509Ref {
830    fn as_ref(&self) -> &X509Ref {
831        self
832    }
833}
834
835impl Stackable for X509 {
836    type StackType = ffi::stack_st_X509;
837}
838
839impl Ord for X509 {
840    fn cmp(&self, other: &Self) -> cmp::Ordering {
841        X509Ref::cmp(self, other)
842    }
843}
844
845impl PartialOrd for X509 {
846    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
847        Some(self.cmp(other))
848    }
849}
850
851impl PartialOrd<X509Ref> for X509 {
852    fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
853        X509Ref::partial_cmp(self, other)
854    }
855}
856
857impl PartialEq for X509 {
858    fn eq(&self, other: &Self) -> bool {
859        X509Ref::eq(self, other)
860    }
861}
862
863impl PartialEq<X509Ref> for X509 {
864    fn eq(&self, other: &X509Ref) -> bool {
865        X509Ref::eq(self, other)
866    }
867}
868
869impl Eq for X509 {}
870
871/// A context object required to construct certain `X509` extension values.
872pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
873
874impl X509v3Context<'_> {
875    pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
876        &self.0 as *const _ as *mut _
877    }
878}
879
880foreign_type_and_impl_send_sync! {
881    type CType = ffi::X509_EXTENSION;
882    fn drop = ffi::X509_EXTENSION_free;
883
884    /// Permit additional fields to be added to an `X509` v3 certificate.
885    pub struct X509Extension;
886    /// Reference to `X509Extension`.
887    pub struct X509ExtensionRef;
888}
889
890impl Stackable for X509Extension {
891    type StackType = ffi::stack_st_X509_EXTENSION;
892}
893
894impl X509Extension {
895    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
896    /// names and their value formats.
897    ///
898    /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
899    /// provided.
900    ///
901    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
902    /// mini-language that can read arbitrary files.
903    ///
904    /// See the extension module for builder types which will construct certain common extensions.
905    ///
906    /// This function is deprecated, `X509Extension::new_from_der` or the
907    /// types in `x509::extension` should be used in its place.
908    #[deprecated(
909        note = "Use x509::extension types or new_from_der instead",
910        since = "0.10.51"
911    )]
912    pub fn new(
913        conf: Option<&ConfRef>,
914        context: Option<&X509v3Context<'_>>,
915        name: &str,
916        value: &str,
917    ) -> Result<X509Extension, ErrorStack> {
918        let name = CString::new(name).unwrap();
919        let value = CString::new(value).unwrap();
920        let mut ctx;
921        unsafe {
922            ffi::init();
923            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
924            let context_ptr = match context {
925                Some(c) => c.as_ptr(),
926                None => {
927                    ctx = mem::zeroed();
928
929                    ffi::X509V3_set_ctx(
930                        &mut ctx,
931                        ptr::null_mut(),
932                        ptr::null_mut(),
933                        ptr::null_mut(),
934                        ptr::null_mut(),
935                        0,
936                    );
937                    &mut ctx
938                }
939            };
940            let name = name.as_ptr() as *mut _;
941            let value = value.as_ptr() as *mut _;
942
943            cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
944        }
945    }
946
947    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
948    /// extensions and their value formats.
949    ///
950    /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
951    /// be provided.
952    ///
953    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
954    /// mini-language that can read arbitrary files.
955    ///
956    /// See the extension module for builder types which will construct certain common extensions.
957    ///
958    /// This function is deprecated, `X509Extension::new_from_der` or the
959    /// types in `x509::extension` should be used in its place.
960    #[deprecated(
961        note = "Use x509::extension types or new_from_der instead",
962        since = "0.10.51"
963    )]
964    pub fn new_nid(
965        conf: Option<&ConfRef>,
966        context: Option<&X509v3Context<'_>>,
967        name: Nid,
968        value: &str,
969    ) -> Result<X509Extension, ErrorStack> {
970        let value = CString::new(value).unwrap();
971        let mut ctx;
972        unsafe {
973            ffi::init();
974            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
975            let context_ptr = match context {
976                Some(c) => c.as_ptr(),
977                None => {
978                    ctx = mem::zeroed();
979
980                    ffi::X509V3_set_ctx(
981                        &mut ctx,
982                        ptr::null_mut(),
983                        ptr::null_mut(),
984                        ptr::null_mut(),
985                        ptr::null_mut(),
986                        0,
987                    );
988                    &mut ctx
989                }
990            };
991            let name = name.as_raw();
992            let value = value.as_ptr() as *mut _;
993
994            cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
995        }
996    }
997
998    /// Constructs a new X509 extension value from its OID, whether it's
999    /// critical, and its DER contents.
1000    ///
1001    /// The extent structure of the DER value will vary based on the
1002    /// extension type, and can generally be found in the RFC defining the
1003    /// extension.
1004    ///
1005    /// For common extension types, there are Rust APIs provided in
1006    /// `openssl::x509::extensions` which are more ergonomic.
1007    pub fn new_from_der(
1008        oid: &Asn1ObjectRef,
1009        critical: bool,
1010        der_contents: &Asn1OctetStringRef,
1011    ) -> Result<X509Extension, ErrorStack> {
1012        unsafe {
1013            cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1014                ptr::null_mut(),
1015                oid.as_ptr(),
1016                critical as _,
1017                der_contents.as_ptr(),
1018            ))
1019            .map(X509Extension)
1020        }
1021    }
1022
1023    pub(crate) unsafe fn new_internal(
1024        nid: Nid,
1025        critical: bool,
1026        value: *mut c_void,
1027    ) -> Result<X509Extension, ErrorStack> {
1028        ffi::init();
1029        cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1030    }
1031
1032    /// Adds an alias for an extension
1033    ///
1034    /// # Safety
1035    ///
1036    /// This method modifies global state without locking and therefore is not thread safe
1037    #[cfg(not(libressl390))]
1038    #[corresponds(X509V3_EXT_add_alias)]
1039    #[deprecated(
1040        note = "Use x509::extension types or new_from_der and then this is not necessary",
1041        since = "0.10.51"
1042    )]
1043    pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1044        ffi::init();
1045        cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1046    }
1047}
1048
1049impl X509ExtensionRef {
1050    to_der! {
1051        /// Serializes the Extension to its standard DER encoding.
1052        #[corresponds(i2d_X509_EXTENSION)]
1053        to_der,
1054        ffi::i2d_X509_EXTENSION
1055    }
1056}
1057
1058/// A builder used to construct an `X509Name`.
1059pub struct X509NameBuilder(X509Name);
1060
1061impl X509NameBuilder {
1062    /// Creates a new builder.
1063    pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1064        unsafe {
1065            ffi::init();
1066            cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1067        }
1068    }
1069
1070    /// Add a name entry
1071    #[corresponds(X509_NAME_add_entry)]
1072    pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1073        unsafe {
1074            cvt(ffi::X509_NAME_add_entry(
1075                self.0.as_ptr(),
1076                ne.as_ptr(),
1077                -1,
1078                0,
1079            ))
1080            .map(|_| ())
1081        }
1082    }
1083
1084    /// Add a field entry by str.
1085    #[corresponds(X509_NAME_add_entry_by_txt)]
1086    pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1087        unsafe {
1088            let field = CString::new(field).unwrap();
1089            assert!(value.len() <= crate::SLenType::MAX as usize);
1090            cvt(ffi::X509_NAME_add_entry_by_txt(
1091                self.0.as_ptr(),
1092                field.as_ptr() as *mut _,
1093                ffi::MBSTRING_UTF8,
1094                value.as_ptr(),
1095                value.len() as crate::SLenType,
1096                -1,
1097                0,
1098            ))
1099            .map(|_| ())
1100        }
1101    }
1102
1103    /// Add a field entry by str with a specific type.
1104    #[corresponds(X509_NAME_add_entry_by_txt)]
1105    pub fn append_entry_by_text_with_type(
1106        &mut self,
1107        field: &str,
1108        value: &str,
1109        ty: Asn1Type,
1110    ) -> Result<(), ErrorStack> {
1111        unsafe {
1112            let field = CString::new(field).unwrap();
1113            assert!(value.len() <= crate::SLenType::MAX as usize);
1114            cvt(ffi::X509_NAME_add_entry_by_txt(
1115                self.0.as_ptr(),
1116                field.as_ptr() as *mut _,
1117                ty.as_raw(),
1118                value.as_ptr(),
1119                value.len() as crate::SLenType,
1120                -1,
1121                0,
1122            ))
1123            .map(|_| ())
1124        }
1125    }
1126
1127    /// Add a field entry by NID.
1128    #[corresponds(X509_NAME_add_entry_by_NID)]
1129    pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1130        unsafe {
1131            assert!(value.len() <= crate::SLenType::MAX as usize);
1132            cvt(ffi::X509_NAME_add_entry_by_NID(
1133                self.0.as_ptr(),
1134                field.as_raw(),
1135                ffi::MBSTRING_UTF8,
1136                value.as_ptr() as *mut _,
1137                value.len() as crate::SLenType,
1138                -1,
1139                0,
1140            ))
1141            .map(|_| ())
1142        }
1143    }
1144
1145    /// Add a field entry by NID with a specific type.
1146    #[corresponds(X509_NAME_add_entry_by_NID)]
1147    pub fn append_entry_by_nid_with_type(
1148        &mut self,
1149        field: Nid,
1150        value: &str,
1151        ty: Asn1Type,
1152    ) -> Result<(), ErrorStack> {
1153        unsafe {
1154            assert!(value.len() <= crate::SLenType::MAX as usize);
1155            cvt(ffi::X509_NAME_add_entry_by_NID(
1156                self.0.as_ptr(),
1157                field.as_raw(),
1158                ty.as_raw(),
1159                value.as_ptr() as *mut _,
1160                value.len() as crate::SLenType,
1161                -1,
1162                0,
1163            ))
1164            .map(|_| ())
1165        }
1166    }
1167
1168    /// Return an `X509Name`.
1169    pub fn build(self) -> X509Name {
1170        // Round-trip through bytes because OpenSSL is not const correct and
1171        // names in a "modified" state compute various things lazily. This can
1172        // lead to data-races because OpenSSL doesn't have locks or anything.
1173        X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1174    }
1175}
1176
1177foreign_type_and_impl_send_sync! {
1178    type CType = ffi::X509_NAME;
1179    fn drop = ffi::X509_NAME_free;
1180
1181    /// The names of an `X509` certificate.
1182    pub struct X509Name;
1183    /// Reference to `X509Name`.
1184    pub struct X509NameRef;
1185}
1186
1187impl X509Name {
1188    /// Returns a new builder.
1189    pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1190        X509NameBuilder::new()
1191    }
1192
1193    /// Loads subject names from a file containing PEM-formatted certificates.
1194    ///
1195    /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
1196    pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1197        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1198        unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1199    }
1200
1201    from_der! {
1202        /// Deserializes a DER-encoded X509 name structure.
1203        ///
1204        /// This corresponds to [`d2i_X509_NAME`].
1205        ///
1206        /// [`d2i_X509_NAME`]: https://docs.openssl.org/master/man3/d2i_X509_NAME/
1207        from_der,
1208        X509Name,
1209        ffi::d2i_X509_NAME
1210    }
1211}
1212
1213impl Stackable for X509Name {
1214    type StackType = ffi::stack_st_X509_NAME;
1215}
1216
1217impl X509NameRef {
1218    /// Returns the name entries by the nid.
1219    pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1220        X509NameEntries {
1221            name: self,
1222            nid: Some(nid),
1223            loc: -1,
1224        }
1225    }
1226
1227    /// Returns an iterator over all `X509NameEntry` values
1228    pub fn entries(&self) -> X509NameEntries<'_> {
1229        X509NameEntries {
1230            name: self,
1231            nid: None,
1232            loc: -1,
1233        }
1234    }
1235
1236    /// Compare two names, like [`Ord`] but it may fail.
1237    ///
1238    /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
1239    /// call fails.
1240    /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
1241    /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
1242    #[corresponds(X509_NAME_cmp)]
1243    pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1244        let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1245        if cfg!(ossl300) && cmp == -2 {
1246            return Err(ErrorStack::get());
1247        }
1248        Ok(cmp.cmp(&0))
1249    }
1250
1251    /// Copies the name to a new `X509Name`.
1252    #[corresponds(X509_NAME_dup)]
1253    pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1254        unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1255    }
1256
1257    to_der! {
1258        /// Serializes the certificate into a DER-encoded X509 name structure.
1259        ///
1260        /// This corresponds to [`i2d_X509_NAME`].
1261        ///
1262        /// [`i2d_X509_NAME`]: https://docs.openssl.org/master/man3/i2d_X509_NAME/
1263        to_der,
1264        ffi::i2d_X509_NAME
1265    }
1266}
1267
1268impl fmt::Debug for X509NameRef {
1269    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1270        formatter.debug_list().entries(self.entries()).finish()
1271    }
1272}
1273
1274/// A type to destructure and examine an `X509Name`.
1275pub struct X509NameEntries<'a> {
1276    name: &'a X509NameRef,
1277    nid: Option<Nid>,
1278    loc: c_int,
1279}
1280
1281impl<'a> Iterator for X509NameEntries<'a> {
1282    type Item = &'a X509NameEntryRef;
1283
1284    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1285        unsafe {
1286            match self.nid {
1287                Some(nid) => {
1288                    // There is a `Nid` specified to search for
1289                    self.loc =
1290                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1291                    if self.loc == -1 {
1292                        return None;
1293                    }
1294                }
1295                None => {
1296                    // Iterate over all `Nid`s
1297                    self.loc += 1;
1298                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1299                        return None;
1300                    }
1301                }
1302            }
1303
1304            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1305
1306            Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1307        }
1308    }
1309}
1310
1311foreign_type_and_impl_send_sync! {
1312    type CType = ffi::X509_NAME_ENTRY;
1313    fn drop = ffi::X509_NAME_ENTRY_free;
1314
1315    /// A name entry associated with a `X509Name`.
1316    pub struct X509NameEntry;
1317    /// Reference to `X509NameEntry`.
1318    pub struct X509NameEntryRef;
1319}
1320
1321impl X509NameEntryRef {
1322    /// Returns the field value of an `X509NameEntry`.
1323    #[corresponds(X509_NAME_ENTRY_get_data)]
1324    pub fn data(&self) -> &Asn1StringRef {
1325        unsafe {
1326            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1327            Asn1StringRef::from_ptr(data)
1328        }
1329    }
1330
1331    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1332    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1333    #[corresponds(X509_NAME_ENTRY_get_object)]
1334    pub fn object(&self) -> &Asn1ObjectRef {
1335        unsafe {
1336            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1337            Asn1ObjectRef::from_ptr(object)
1338        }
1339    }
1340}
1341
1342impl fmt::Debug for X509NameEntryRef {
1343    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1344        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1345    }
1346}
1347
1348/// A builder used to construct an `X509Req`.
1349pub struct X509ReqBuilder(X509Req);
1350
1351impl X509ReqBuilder {
1352    /// Returns a builder for a certificate request.
1353    #[corresponds(X509_REQ_new)]
1354    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1355        unsafe {
1356            ffi::init();
1357            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1358        }
1359    }
1360
1361    /// Set the numerical value of the version field.
1362    #[corresponds(X509_REQ_set_version)]
1363    #[allow(clippy::useless_conversion)]
1364    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1365        unsafe {
1366            cvt(ffi::X509_REQ_set_version(
1367                self.0.as_ptr(),
1368                version as c_long,
1369            ))
1370            .map(|_| ())
1371        }
1372    }
1373
1374    /// Set the issuer name.
1375    #[corresponds(X509_REQ_set_subject_name)]
1376    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1377        unsafe {
1378            cvt(ffi::X509_REQ_set_subject_name(
1379                self.0.as_ptr(),
1380                subject_name.as_ptr(),
1381            ))
1382            .map(|_| ())
1383        }
1384    }
1385
1386    /// Set the public key.
1387    #[corresponds(X509_REQ_set_pubkey)]
1388    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1389    where
1390        T: HasPublic,
1391    {
1392        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1393    }
1394
1395    /// Return an `X509v3Context`. This context object can be used to construct
1396    /// certain `X509` extensions.
1397    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1398        unsafe {
1399            let mut ctx = mem::zeroed();
1400
1401            ffi::X509V3_set_ctx(
1402                &mut ctx,
1403                ptr::null_mut(),
1404                ptr::null_mut(),
1405                self.0.as_ptr(),
1406                ptr::null_mut(),
1407                0,
1408            );
1409
1410            // nodb case taken care of since we zeroed ctx above
1411            if let Some(conf) = conf {
1412                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1413            }
1414
1415            X509v3Context(ctx, PhantomData)
1416        }
1417    }
1418
1419    /// Permits any number of extension fields to be added to the certificate.
1420    pub fn add_extensions(
1421        &mut self,
1422        extensions: &StackRef<X509Extension>,
1423    ) -> Result<(), ErrorStack> {
1424        unsafe {
1425            cvt(ffi::X509_REQ_add_extensions(
1426                self.0.as_ptr(),
1427                extensions.as_ptr(),
1428            ))
1429            .map(|_| ())
1430        }
1431    }
1432
1433    /// Sign the request using a private key.
1434    #[corresponds(X509_REQ_sign)]
1435    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1436    where
1437        T: HasPrivate,
1438    {
1439        unsafe {
1440            cvt(ffi::X509_REQ_sign(
1441                self.0.as_ptr(),
1442                key.as_ptr(),
1443                hash.as_ptr(),
1444            ))
1445            .map(|_| ())
1446        }
1447    }
1448
1449    /// Returns the `X509Req`.
1450    pub fn build(self) -> X509Req {
1451        self.0
1452    }
1453}
1454
1455foreign_type_and_impl_send_sync! {
1456    type CType = ffi::X509_REQ;
1457    fn drop = ffi::X509_REQ_free;
1458
1459    /// An `X509` certificate request.
1460    pub struct X509Req;
1461    /// Reference to `X509Req`.
1462    pub struct X509ReqRef;
1463}
1464
1465impl X509Req {
1466    /// A builder for `X509Req`.
1467    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1468        X509ReqBuilder::new()
1469    }
1470
1471    from_pem! {
1472        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1473        ///
1474        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1475        ///
1476        /// This corresponds to [`PEM_read_bio_X509_REQ`].
1477        ///
1478        /// [`PEM_read_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_read_bio_X509_REQ/
1479        from_pem,
1480        X509Req,
1481        ffi::PEM_read_bio_X509_REQ
1482    }
1483
1484    from_der! {
1485        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1486        ///
1487        /// This corresponds to [`d2i_X509_REQ`].
1488        ///
1489        /// [`d2i_X509_REQ`]: https://docs.openssl.org/master/man3/d2i_X509_REQ/
1490        from_der,
1491        X509Req,
1492        ffi::d2i_X509_REQ
1493    }
1494}
1495
1496impl X509ReqRef {
1497    to_pem! {
1498        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1499        ///
1500        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1501        ///
1502        /// This corresponds to [`PEM_write_bio_X509_REQ`].
1503        ///
1504        /// [`PEM_write_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_write_bio_X509_REQ/
1505        to_pem,
1506        ffi::PEM_write_bio_X509_REQ
1507    }
1508
1509    to_der! {
1510        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1511        ///
1512        /// This corresponds to [`i2d_X509_REQ`].
1513        ///
1514        /// [`i2d_X509_REQ`]: https://docs.openssl.org/master/man3/i2d_X509_REQ/
1515        to_der,
1516        ffi::i2d_X509_REQ
1517    }
1518
1519    to_pem! {
1520        /// Converts the request to human readable text.
1521        #[corresponds(X509_Req_print)]
1522        to_text,
1523        ffi::X509_REQ_print
1524    }
1525
1526    /// Returns the numerical value of the version field of the certificate request.
1527    #[corresponds(X509_REQ_get_version)]
1528    #[allow(clippy::unnecessary_cast)]
1529    pub fn version(&self) -> i32 {
1530        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1531    }
1532
1533    /// Returns the subject name of the certificate request.
1534    #[corresponds(X509_REQ_get_subject_name)]
1535    pub fn subject_name(&self) -> &X509NameRef {
1536        unsafe {
1537            let name = X509_REQ_get_subject_name(self.as_ptr());
1538            X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1539        }
1540    }
1541
1542    /// Returns the public key of the certificate request.
1543    #[corresponds(X509_REQ_get_pubkey)]
1544    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1545        unsafe {
1546            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1547            Ok(PKey::from_ptr(key))
1548        }
1549    }
1550
1551    /// Check if the certificate request is signed using the given public key.
1552    ///
1553    /// Returns `true` if verification succeeds.
1554    #[corresponds(X509_REQ_verify)]
1555    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1556    where
1557        T: HasPublic,
1558    {
1559        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1560    }
1561
1562    /// Returns the extensions of the certificate request.
1563    #[corresponds(X509_REQ_get_extensions)]
1564    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1565        unsafe {
1566            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1567            Ok(Stack::from_ptr(extensions))
1568        }
1569    }
1570}
1571
1572/// The reason that a certificate was revoked.
1573#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1574pub struct CrlReason(c_int);
1575
1576#[allow(missing_docs)] // no need to document the constants
1577impl CrlReason {
1578    pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1579    pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1580    pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1581    pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1582    pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1583    pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1584    pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1585    pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1586    pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1587    pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1588
1589    /// Constructs an `CrlReason` from a raw OpenSSL value.
1590    pub const fn from_raw(value: c_int) -> Self {
1591        CrlReason(value)
1592    }
1593
1594    /// Returns the raw OpenSSL value represented by this type.
1595    pub const fn as_raw(&self) -> c_int {
1596        self.0
1597    }
1598}
1599
1600foreign_type_and_impl_send_sync! {
1601    type CType = ffi::X509_REVOKED;
1602    fn drop = ffi::X509_REVOKED_free;
1603
1604    /// An `X509` certificate revocation status.
1605    pub struct X509Revoked;
1606    /// Reference to `X509Revoked`.
1607    pub struct X509RevokedRef;
1608}
1609
1610impl Stackable for X509Revoked {
1611    type StackType = ffi::stack_st_X509_REVOKED;
1612}
1613
1614impl X509Revoked {
1615    from_der! {
1616        /// Deserializes a DER-encoded certificate revocation status
1617        #[corresponds(d2i_X509_REVOKED)]
1618        from_der,
1619        X509Revoked,
1620        ffi::d2i_X509_REVOKED
1621    }
1622}
1623
1624impl X509RevokedRef {
1625    to_der! {
1626        /// Serializes the certificate request to a DER-encoded certificate revocation status
1627        #[corresponds(d2i_X509_REVOKED)]
1628        to_der,
1629        ffi::i2d_X509_REVOKED
1630    }
1631
1632    /// Copies the entry to a new `X509Revoked`.
1633    #[corresponds(X509_REVOKED_dup)]
1634    pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1635        unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1636    }
1637
1638    /// Get the date that the certificate was revoked
1639    #[corresponds(X509_REVOKED_get0_revocationDate)]
1640    pub fn revocation_date(&self) -> &Asn1TimeRef {
1641        unsafe {
1642            let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1643            assert!(!r.is_null());
1644            Asn1TimeRef::from_ptr(r as *mut _)
1645        }
1646    }
1647
1648    /// Get the serial number of the revoked certificate
1649    #[corresponds(X509_REVOKED_get0_serialNumber)]
1650    pub fn serial_number(&self) -> &Asn1IntegerRef {
1651        unsafe {
1652            let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1653            assert!(!r.is_null());
1654            Asn1IntegerRef::from_ptr(r as *mut _)
1655        }
1656    }
1657
1658    /// Get the criticality and value of an extension.
1659    ///
1660    /// This returns None if the extension is not present or occurs multiple times.
1661    #[corresponds(X509_REVOKED_get_ext_d2i)]
1662    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1663        let mut critical = -1;
1664        let out = unsafe {
1665            // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
1666            let ext = ffi::X509_REVOKED_get_ext_d2i(
1667                self.as_ptr(),
1668                T::NID.as_raw(),
1669                &mut critical as *mut _,
1670                ptr::null_mut(),
1671            );
1672            // SAFETY: Extensions's contract promises that the type returned by
1673            // OpenSSL here is T::Output.
1674            T::Output::from_ptr_opt(ext as *mut _)
1675        };
1676        match (critical, out) {
1677            (0, Some(out)) => Ok(Some((false, out))),
1678            (1, Some(out)) => Ok(Some((true, out))),
1679            // -1 means the extension wasn't found, -2 means multiple were found.
1680            (-1 | -2, _) => Ok(None),
1681            // A critical value of 0 or 1 suggests success, but a null pointer
1682            // was returned so something went wrong.
1683            (0 | 1, None) => Err(ErrorStack::get()),
1684            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1685        }
1686    }
1687}
1688
1689/// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
1690/// this is as defined in RFC 5280 Section 5.3.1.
1691pub enum ReasonCode {}
1692
1693// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1694// and in OpenSSL.
1695unsafe impl ExtensionType for ReasonCode {
1696    const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1697
1698    type Output = Asn1Enumerated;
1699}
1700
1701/// The CRL entry extension identifying the issuer of a certificate used in
1702/// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
1703pub enum CertificateIssuer {}
1704
1705// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1706// and in OpenSSL.
1707unsafe impl ExtensionType for CertificateIssuer {
1708    const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1709
1710    type Output = Stack<GeneralName>;
1711}
1712
1713/// The CRL extension identifying how to access information and services for the issuer of the CRL
1714pub enum AuthorityInformationAccess {}
1715
1716// SAFETY: AuthorityInformationAccess is defined to be a stack of AccessDescription in the RFC
1717// and in OpenSSL.
1718unsafe impl ExtensionType for AuthorityInformationAccess {
1719    const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1720
1721    type Output = Stack<AccessDescription>;
1722}
1723
1724foreign_type_and_impl_send_sync! {
1725    type CType = ffi::X509_CRL;
1726    fn drop = ffi::X509_CRL_free;
1727
1728    /// An `X509` certificate revocation list.
1729    pub struct X509Crl;
1730    /// Reference to `X509Crl`.
1731    pub struct X509CrlRef;
1732}
1733
1734/// The status of a certificate in a revoction list
1735///
1736/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1737///
1738/// [`X509_CRL_get0_by_*`]: https://docs.openssl.org/master/man3/X509_CRL_get0_by_serial/
1739pub enum CrlStatus<'a> {
1740    /// The certificate is not present in the list
1741    NotRevoked,
1742    /// The certificate is in the list and is revoked
1743    Revoked(&'a X509RevokedRef),
1744    /// The certificate is in the list, but has the "removeFromCrl" status.
1745    ///
1746    /// This can occur if the certificate was revoked with the "CertificateHold"
1747    /// reason, and has since been unrevoked.
1748    RemoveFromCrl(&'a X509RevokedRef),
1749}
1750
1751impl<'a> CrlStatus<'a> {
1752    // Helper used by the X509_CRL_get0_by_* methods to convert their return
1753    // value to the status enum.
1754    // Safety note: the returned CrlStatus must not outlive the owner of the
1755    // revoked_entry pointer.
1756    unsafe fn from_ffi_status(
1757        status: c_int,
1758        revoked_entry: *mut ffi::X509_REVOKED,
1759    ) -> CrlStatus<'a> {
1760        match status {
1761            0 => CrlStatus::NotRevoked,
1762            1 => {
1763                assert!(!revoked_entry.is_null());
1764                CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1765            }
1766            2 => {
1767                assert!(!revoked_entry.is_null());
1768                CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1769            }
1770            _ => unreachable!(
1771                "{}",
1772                "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1773            ),
1774        }
1775    }
1776}
1777
1778impl X509Crl {
1779    from_pem! {
1780        /// Deserializes a PEM-encoded Certificate Revocation List
1781        ///
1782        /// The input should have a header of `-----BEGIN X509 CRL-----`.
1783        #[corresponds(PEM_read_bio_X509_CRL)]
1784        from_pem,
1785        X509Crl,
1786        ffi::PEM_read_bio_X509_CRL
1787    }
1788
1789    from_der! {
1790        /// Deserializes a DER-encoded Certificate Revocation List
1791        #[corresponds(d2i_X509_CRL)]
1792        from_der,
1793        X509Crl,
1794        ffi::d2i_X509_CRL
1795    }
1796}
1797
1798impl X509CrlRef {
1799    to_pem! {
1800        /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
1801        ///
1802        /// The output will have a header of `-----BEGIN X509 CRL-----`.
1803        #[corresponds(PEM_write_bio_X509_CRL)]
1804        to_pem,
1805        ffi::PEM_write_bio_X509_CRL
1806    }
1807
1808    to_der! {
1809        /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
1810        #[corresponds(i2d_X509_CRL)]
1811        to_der,
1812        ffi::i2d_X509_CRL
1813    }
1814
1815    /// Get the stack of revocation entries
1816    pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
1817        unsafe {
1818            let revoked = X509_CRL_get_REVOKED(self.as_ptr());
1819            if revoked.is_null() {
1820                None
1821            } else {
1822                Some(StackRef::from_ptr(revoked))
1823            }
1824        }
1825    }
1826
1827    /// Returns the CRL's `lastUpdate` time.
1828    #[corresponds(X509_CRL_get0_lastUpdate)]
1829    pub fn last_update(&self) -> &Asn1TimeRef {
1830        unsafe {
1831            let date = X509_CRL_get0_lastUpdate(self.as_ptr());
1832            assert!(!date.is_null());
1833            Asn1TimeRef::from_ptr(date as *mut _)
1834        }
1835    }
1836
1837    /// Returns the CRL's `nextUpdate` time.
1838    ///
1839    /// If the `nextUpdate` field is missing, returns `None`.
1840    #[corresponds(X509_CRL_get0_nextUpdate)]
1841    pub fn next_update(&self) -> Option<&Asn1TimeRef> {
1842        unsafe {
1843            let date = X509_CRL_get0_nextUpdate(self.as_ptr());
1844            Asn1TimeRef::from_const_ptr_opt(date)
1845        }
1846    }
1847
1848    /// Get the revocation status of a certificate by its serial number
1849    #[corresponds(X509_CRL_get0_by_serial)]
1850    pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
1851        unsafe {
1852            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1853            let status =
1854                ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
1855            CrlStatus::from_ffi_status(status, ret)
1856        }
1857    }
1858
1859    /// Get the revocation status of a certificate
1860    #[corresponds(X509_CRL_get0_by_cert)]
1861    pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
1862        unsafe {
1863            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1864            let status =
1865                ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
1866            CrlStatus::from_ffi_status(status, ret)
1867        }
1868    }
1869
1870    /// Get the issuer name from the revocation list.
1871    #[corresponds(X509_CRL_get_issuer)]
1872    pub fn issuer_name(&self) -> &X509NameRef {
1873        unsafe {
1874            let name = X509_CRL_get_issuer(self.as_ptr());
1875            assert!(!name.is_null());
1876            X509NameRef::from_ptr(name)
1877        }
1878    }
1879
1880    /// Check if the CRL is signed using the given public key.
1881    ///
1882    /// Only the signature is checked: no other checks (such as certificate chain validity)
1883    /// are performed.
1884    ///
1885    /// Returns `true` if verification succeeds.
1886    #[corresponds(X509_CRL_verify)]
1887    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1888    where
1889        T: HasPublic,
1890    {
1891        unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1892    }
1893
1894    /// Get the criticality and value of an extension.
1895    ///
1896    /// This returns None if the extension is not present or occurs multiple times.
1897    #[corresponds(X509_CRL_get_ext_d2i)]
1898    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1899        let mut critical = -1;
1900        let out = unsafe {
1901            // SAFETY: self.as_ptr() is a valid pointer to an X509_CRL.
1902            let ext = ffi::X509_CRL_get_ext_d2i(
1903                self.as_ptr(),
1904                T::NID.as_raw(),
1905                &mut critical as *mut _,
1906                ptr::null_mut(),
1907            );
1908            // SAFETY: Extensions's contract promises that the type returned by
1909            // OpenSSL here is T::Output.
1910            T::Output::from_ptr_opt(ext as *mut _)
1911        };
1912        match (critical, out) {
1913            (0, Some(out)) => Ok(Some((false, out))),
1914            (1, Some(out)) => Ok(Some((true, out))),
1915            // -1 means the extension wasn't found, -2 means multiple were found.
1916            (-1 | -2, _) => Ok(None),
1917            // A critical value of 0 or 1 suggests success, but a null pointer
1918            // was returned so something went wrong.
1919            (0 | 1, None) => Err(ErrorStack::get()),
1920            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1921        }
1922    }
1923}
1924
1925/// The result of peer certificate verification.
1926#[derive(Copy, Clone, PartialEq, Eq)]
1927pub struct X509VerifyResult(c_int);
1928
1929impl fmt::Debug for X509VerifyResult {
1930    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1931        fmt.debug_struct("X509VerifyResult")
1932            .field("code", &self.0)
1933            .field("error", &self.error_string())
1934            .finish()
1935    }
1936}
1937
1938impl fmt::Display for X509VerifyResult {
1939    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1940        fmt.write_str(self.error_string())
1941    }
1942}
1943
1944impl Error for X509VerifyResult {}
1945
1946impl X509VerifyResult {
1947    /// Creates an `X509VerifyResult` from a raw error number.
1948    ///
1949    /// # Safety
1950    ///
1951    /// Some methods on `X509VerifyResult` are not thread safe if the error
1952    /// number is invalid.
1953    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1954        X509VerifyResult(err)
1955    }
1956
1957    /// Return the integer representation of an `X509VerifyResult`.
1958    #[allow(clippy::trivially_copy_pass_by_ref)]
1959    pub fn as_raw(&self) -> c_int {
1960        self.0
1961    }
1962
1963    /// Return a human readable error string from the verification error.
1964    #[corresponds(X509_verify_cert_error_string)]
1965    #[allow(clippy::trivially_copy_pass_by_ref)]
1966    pub fn error_string(&self) -> &'static str {
1967        ffi::init();
1968
1969        unsafe {
1970            let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1971            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1972        }
1973    }
1974
1975    /// Successful peer certificate verification.
1976    pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1977    /// Application verification failure.
1978    pub const APPLICATION_VERIFICATION: X509VerifyResult =
1979        X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1980}
1981
1982foreign_type_and_impl_send_sync! {
1983    type CType = ffi::GENERAL_NAME;
1984    fn drop = ffi::GENERAL_NAME_free;
1985
1986    /// An `X509` certificate alternative names.
1987    pub struct GeneralName;
1988    /// Reference to `GeneralName`.
1989    pub struct GeneralNameRef;
1990}
1991
1992impl GeneralName {
1993    unsafe fn new(
1994        type_: c_int,
1995        asn1_type: Asn1Type,
1996        value: &[u8],
1997    ) -> Result<GeneralName, ErrorStack> {
1998        ffi::init();
1999        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2000        (*gn.as_ptr()).type_ = type_;
2001        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2002        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2003
2004        #[cfg(any(boringssl, awslc))]
2005        {
2006            (*gn.as_ptr()).d.ptr = s.cast();
2007        }
2008        #[cfg(not(any(boringssl, awslc)))]
2009        {
2010            (*gn.as_ptr()).d = s.cast();
2011        }
2012
2013        Ok(gn)
2014    }
2015
2016    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2017        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2018    }
2019
2020    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2021        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2022    }
2023
2024    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2025        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2026    }
2027
2028    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2029        match ip {
2030            IpAddr::V4(addr) => unsafe {
2031                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2032            },
2033            IpAddr::V6(addr) => unsafe {
2034                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2035            },
2036        }
2037    }
2038
2039    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2040        unsafe {
2041            ffi::init();
2042            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2043            (*gn).type_ = ffi::GEN_RID;
2044
2045            #[cfg(any(boringssl, awslc))]
2046            {
2047                (*gn).d.registeredID = oid.as_ptr();
2048            }
2049            #[cfg(not(any(boringssl, awslc)))]
2050            {
2051                (*gn).d = oid.as_ptr().cast();
2052            }
2053
2054            mem::forget(oid);
2055
2056            Ok(GeneralName::from_ptr(gn))
2057        }
2058    }
2059
2060    pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2061        unsafe {
2062            ffi::init();
2063
2064            let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2065                ptr::null_mut(),
2066                &mut value.as_ptr().cast(),
2067                value.len().try_into().unwrap(),
2068            ))?;
2069
2070            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2071            (*gn).type_ = ffi::GEN_OTHERNAME;
2072
2073            if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2074                gn,
2075                oid.as_ptr().cast(),
2076                typ,
2077            )) {
2078                ffi::GENERAL_NAME_free(gn);
2079                return Err(e);
2080            }
2081
2082            mem::forget(oid);
2083
2084            Ok(GeneralName::from_ptr(gn))
2085        }
2086    }
2087
2088    pub(crate) fn new_dir_name(name: &X509NameRef) -> Result<GeneralName, ErrorStack> {
2089        unsafe {
2090            ffi::init();
2091            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2092            (*gn).type_ = ffi::GEN_DIRNAME;
2093
2094            let dup = match name.to_owned() {
2095                Ok(dup) => dup,
2096                Err(e) => {
2097                    ffi::GENERAL_NAME_free(gn);
2098                    return Err(e);
2099                }
2100            };
2101
2102            #[cfg(any(boringssl, awslc))]
2103            {
2104                (*gn).d.directoryName = dup.as_ptr();
2105            }
2106            #[cfg(not(any(boringssl, awslc)))]
2107            {
2108                (*gn).d = dup.as_ptr().cast();
2109            }
2110
2111            std::mem::forget(dup);
2112
2113            Ok(GeneralName::from_ptr(gn))
2114        }
2115    }
2116}
2117
2118impl GeneralNameRef {
2119    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2120        unsafe {
2121            if (*self.as_ptr()).type_ != ffi_type {
2122                return None;
2123            }
2124
2125            #[cfg(any(boringssl, awslc))]
2126            let d = (*self.as_ptr()).d.ptr;
2127            #[cfg(not(any(boringssl, awslc)))]
2128            let d = (*self.as_ptr()).d;
2129
2130            let ptr = ASN1_STRING_get0_data(d as *mut _);
2131            let len = ffi::ASN1_STRING_length(d as *mut _);
2132
2133            #[allow(clippy::unnecessary_cast)]
2134            let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2135            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
2136            // OpenSSL checks that when loading a certificate but if not we'll
2137            // use this instead of from_utf8_unchecked just in case.
2138            str::from_utf8(slice).ok()
2139        }
2140    }
2141
2142    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
2143    pub fn email(&self) -> Option<&str> {
2144        self.ia5_string(ffi::GEN_EMAIL)
2145    }
2146
2147    /// Returns the contents of this `GeneralName` if it is a `directoryName`.
2148    pub fn directory_name(&self) -> Option<&X509NameRef> {
2149        unsafe {
2150            if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2151                return None;
2152            }
2153
2154            #[cfg(any(boringssl, awslc))]
2155            let d = (*self.as_ptr()).d.ptr;
2156            #[cfg(not(any(boringssl, awslc)))]
2157            let d = (*self.as_ptr()).d;
2158
2159            Some(X509NameRef::from_const_ptr(d as *const _))
2160        }
2161    }
2162
2163    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
2164    pub fn dnsname(&self) -> Option<&str> {
2165        self.ia5_string(ffi::GEN_DNS)
2166    }
2167
2168    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
2169    pub fn uri(&self) -> Option<&str> {
2170        self.ia5_string(ffi::GEN_URI)
2171    }
2172
2173    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
2174    pub fn ipaddress(&self) -> Option<&[u8]> {
2175        unsafe {
2176            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2177                return None;
2178            }
2179            #[cfg(any(boringssl, awslc))]
2180            let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2181            #[cfg(not(any(boringssl, awslc)))]
2182            let d = (*self.as_ptr()).d;
2183
2184            let ptr = ASN1_STRING_get0_data(d as *mut _);
2185            let len = ffi::ASN1_STRING_length(d as *mut _);
2186
2187            #[allow(clippy::unnecessary_cast)]
2188            Some(util::from_raw_parts(ptr as *const u8, len as usize))
2189        }
2190    }
2191}
2192
2193impl fmt::Debug for GeneralNameRef {
2194    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2195        if let Some(email) = self.email() {
2196            formatter.write_str(email)
2197        } else if let Some(dnsname) = self.dnsname() {
2198            formatter.write_str(dnsname)
2199        } else if let Some(uri) = self.uri() {
2200            formatter.write_str(uri)
2201        } else if let Some(ipaddress) = self.ipaddress() {
2202            let address = <[u8; 16]>::try_from(ipaddress)
2203                .map(IpAddr::from)
2204                .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2205            match address {
2206                Ok(a) => fmt::Debug::fmt(&a, formatter),
2207                Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2208            }
2209        } else {
2210            formatter.write_str("(empty)")
2211        }
2212    }
2213}
2214
2215impl Stackable for GeneralName {
2216    type StackType = ffi::stack_st_GENERAL_NAME;
2217}
2218
2219foreign_type_and_impl_send_sync! {
2220    type CType = ffi::DIST_POINT;
2221    fn drop = ffi::DIST_POINT_free;
2222
2223    /// A `X509` distribution point.
2224    pub struct DistPoint;
2225    /// Reference to `DistPoint`.
2226    pub struct DistPointRef;
2227}
2228
2229impl DistPointRef {
2230    /// Returns the name of this distribution point if it exists
2231    pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2232        unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2233    }
2234}
2235
2236foreign_type_and_impl_send_sync! {
2237    type CType = ffi::DIST_POINT_NAME;
2238    fn drop = ffi::DIST_POINT_NAME_free;
2239
2240    /// A `X509` distribution point.
2241    pub struct DistPointName;
2242    /// Reference to `DistPointName`.
2243    pub struct DistPointNameRef;
2244}
2245
2246impl DistPointNameRef {
2247    /// Returns the contents of this DistPointName if it is a fullname.
2248    pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2249        unsafe {
2250            if (*self.as_ptr()).type_ != 0 {
2251                return None;
2252            }
2253            StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2254        }
2255    }
2256}
2257
2258impl Stackable for DistPoint {
2259    type StackType = ffi::stack_st_DIST_POINT;
2260}
2261
2262foreign_type_and_impl_send_sync! {
2263    type CType = ffi::ACCESS_DESCRIPTION;
2264    fn drop = ffi::ACCESS_DESCRIPTION_free;
2265
2266    /// `AccessDescription` of certificate authority information.
2267    pub struct AccessDescription;
2268    /// Reference to `AccessDescription`.
2269    pub struct AccessDescriptionRef;
2270}
2271
2272impl AccessDescriptionRef {
2273    /// Returns the access method OID.
2274    pub fn method(&self) -> &Asn1ObjectRef {
2275        unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2276    }
2277
2278    // Returns the access location.
2279    pub fn location(&self) -> &GeneralNameRef {
2280        unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2281    }
2282}
2283
2284impl Stackable for AccessDescription {
2285    type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2286}
2287
2288foreign_type_and_impl_send_sync! {
2289    type CType = ffi::X509_ALGOR;
2290    fn drop = ffi::X509_ALGOR_free;
2291
2292    /// An `X509` certificate signature algorithm.
2293    pub struct X509Algorithm;
2294    /// Reference to `X509Algorithm`.
2295    pub struct X509AlgorithmRef;
2296}
2297
2298impl X509AlgorithmRef {
2299    /// Returns the ASN.1 OID of this algorithm.
2300    pub fn object(&self) -> &Asn1ObjectRef {
2301        unsafe {
2302            let mut oid = ptr::null();
2303            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2304            Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2305        }
2306    }
2307}
2308
2309foreign_type_and_impl_send_sync! {
2310    type CType = ffi::X509_OBJECT;
2311    fn drop = X509_OBJECT_free;
2312
2313    /// An `X509` or an X509 certificate revocation list.
2314    pub struct X509Object;
2315    /// Reference to `X509Object`
2316    pub struct X509ObjectRef;
2317}
2318
2319impl X509ObjectRef {
2320    pub fn x509(&self) -> Option<&X509Ref> {
2321        unsafe {
2322            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2323            X509Ref::from_const_ptr_opt(ptr)
2324        }
2325    }
2326}
2327
2328impl Stackable for X509Object {
2329    type StackType = ffi::stack_st_X509_OBJECT;
2330}
2331
2332use ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
2333
2334use ffi::{
2335    ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
2336    X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
2337};
2338
2339use ffi::X509_OBJECT_free;
2340use ffi::X509_OBJECT_get0_X509;
2341
2342use ffi::{
2343    X509_CRL_get0_lastUpdate, X509_CRL_get0_nextUpdate, X509_CRL_get_REVOKED, X509_CRL_get_issuer,
2344    X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2345};
2346
2347#[derive(Copy, Clone, PartialEq, Eq)]
2348pub struct X509PurposeId(c_int);
2349
2350impl X509PurposeId {
2351    pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2352    pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2353    pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2354    pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2355    pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2356    pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2357    pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2358    pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2359    pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2360    #[cfg(ossl320)]
2361    pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2362
2363    /// Constructs an `X509PurposeId` from a raw OpenSSL value.
2364    pub fn from_raw(id: c_int) -> Self {
2365        X509PurposeId(id)
2366    }
2367
2368    /// Returns the raw OpenSSL value represented by this type.
2369    pub fn as_raw(&self) -> c_int {
2370        self.0
2371    }
2372}
2373
2374/// A reference to an [`X509_PURPOSE`].
2375pub struct X509PurposeRef(Opaque);
2376
2377/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2378impl ForeignTypeRef for X509PurposeRef {
2379    type CType = ffi::X509_PURPOSE;
2380}
2381
2382impl X509PurposeRef {
2383    /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2384    /// names include
2385    ///  - "sslclient",
2386    ///  - "sslserver",
2387    ///  - "nssslserver",
2388    ///  - "smimesign",
2389    ///  - "smimeencrypt",
2390    ///  - "crlsign",
2391    ///  - "any",
2392    ///  - "ocsphelper",
2393    ///  - "timestampsign"
2394    ///
2395    /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2396    #[allow(clippy::unnecessary_cast)]
2397    pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2398        unsafe {
2399            let sname = CString::new(sname).unwrap();
2400            let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2401            Ok(purpose)
2402        }
2403    }
2404    /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2405    /// `X509PurposeRef::get_by_sname()`.
2406    #[corresponds(X509_PURPOSE_get0)]
2407    pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2408        unsafe {
2409            let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2410            Ok(X509PurposeRef::from_const_ptr(ptr))
2411        }
2412    }
2413
2414    /// Get the purpose value from an X509Purpose structure. This value is one of
2415    /// - `X509_PURPOSE_SSL_CLIENT`
2416    /// - `X509_PURPOSE_SSL_SERVER`
2417    /// - `X509_PURPOSE_NS_SSL_SERVER`
2418    /// - `X509_PURPOSE_SMIME_SIGN`
2419    /// - `X509_PURPOSE_SMIME_ENCRYPT`
2420    /// - `X509_PURPOSE_CRL_SIGN`
2421    /// - `X509_PURPOSE_ANY`
2422    /// - `X509_PURPOSE_OCSP_HELPER`
2423    /// - `X509_PURPOSE_TIMESTAMP_SIGN`
2424    pub fn purpose(&self) -> X509PurposeId {
2425        unsafe {
2426            let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2427            X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2428        }
2429    }
2430}