rama_boring/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};
11use libc::{c_int, c_long, c_void};
12use openssl_macros::corresponds;
13use std::convert::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::slice;
23use std::str;
24
25use crate::asn1::{
26    Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef,
27    Asn1Type,
28};
29use crate::bio::{MemBio, MemBioSlice};
30use crate::conf::ConfRef;
31use crate::error::ErrorStack;
32use crate::ex_data::Index;
33use crate::ffi;
34use crate::hash::{DigestBytes, MessageDigest};
35use crate::nid::Nid;
36use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
37use crate::ssl::SslRef;
38use crate::stack::{Stack, StackRef, Stackable};
39use crate::string::OpensslString;
40use crate::util::ForeignTypeRefExt;
41use crate::x509::verify::X509VerifyParamRef;
42use crate::{cvt, cvt_n, cvt_p};
43
44pub mod extension;
45pub mod store;
46pub mod verify;
47
48#[cfg(test)]
49mod tests;
50
51foreign_type_and_impl_send_sync! {
52    type CType = ffi::X509_STORE_CTX;
53    fn drop = ffi::X509_STORE_CTX_free;
54
55    /// An `X509` certificate store context.
56    pub struct X509StoreContext;
57}
58
59impl X509StoreContext {
60    /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
61    /// context.
62    #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
63    pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
64        unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
65    }
66
67    /// Creates a new `X509StoreContext` instance.
68    #[corresponds(X509_STORE_CTX_new)]
69    pub fn new() -> Result<X509StoreContext, ErrorStack> {
70        unsafe {
71            ffi::init();
72            cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext::from_ptr(p))
73        }
74    }
75}
76
77impl X509StoreContextRef {
78    /// Returns application data pertaining to an `X509` store context.
79    #[corresponds(X509_STORE_CTX_get_ex_data)]
80    pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
81        unsafe {
82            let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
83            if data.is_null() {
84                None
85            } else {
86                Some(&*(data as *const T))
87            }
88        }
89    }
90
91    /// Returns the verify result of the context.
92    #[corresponds(X509_STORE_CTX_get_error)]
93    pub fn verify_result(&self) -> X509VerifyResult {
94        unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
95    }
96
97    /// Initializes this context with the given certificate, certificates chain and certificate
98    /// store. After initializing the context, the `with_context` closure is called with the prepared
99    /// context. As long as the closure is running, the context stays initialized and can be used
100    /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
101    ///
102    /// * `trust` - The certificate store with the trusted certificates.
103    /// * `cert` - The certificate that should be verified.
104    /// * `cert_chain` - The certificates chain.
105    /// * `with_context` - The closure that is called with the initialized context.
106    ///
107    /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
108    /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
109    ///
110    /// [`X509_STORE_CTX_init`]:  https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html
111    /// [`X509_STORE_CTX_cleanup`]:  https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
112    pub fn init<F, T>(
113        &mut self,
114        trust: &store::X509StoreRef,
115        cert: &X509Ref,
116        cert_chain: &StackRef<X509>,
117        with_context: F,
118    ) -> Result<T, ErrorStack>
119    where
120        F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
121    {
122        struct Cleanup<'a>(&'a mut X509StoreContextRef);
123
124        impl Drop for Cleanup<'_> {
125            fn drop(&mut self) {
126                unsafe {
127                    ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
128                }
129            }
130        }
131
132        unsafe {
133            cvt(ffi::X509_STORE_CTX_init(
134                self.as_ptr(),
135                trust.as_ptr(),
136                cert.as_ptr(),
137                cert_chain.as_ptr(),
138            ))?;
139
140            let cleanup = Cleanup(self);
141            with_context(cleanup.0)
142        }
143    }
144
145    /// Returns a mutable reference to the X509 verification configuration.
146    #[corresponds(X509_STORE_CTX_get0_param)]
147    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
148        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) }
149    }
150
151    /// Verifies the stored certificate.
152    ///
153    /// Returns `true` if verification succeeds. The `error` method will return the specific
154    /// validation error if the certificate was not valid.
155    ///
156    /// This will only work inside of a call to `init`.
157    #[corresponds(X509_verify_cert)]
158    pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
159        unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
160    }
161
162    /// Set the verify result of the context.
163    #[corresponds(X509_STORE_CTX_set_error)]
164    pub fn set_error(&mut self, result: X509VerifyResult) {
165        unsafe {
166            ffi::X509_STORE_CTX_set_error(
167                self.as_ptr(),
168                result
169                    .err()
170                    .as_ref()
171                    .map_or(ffi::X509_V_OK, X509VerifyError::as_raw),
172            );
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            if ptr.is_null() {
183                None
184            } else {
185                Some(X509Ref::from_ptr(ptr))
186            }
187        }
188    }
189
190    /// Returns a non-negative integer representing the depth in the certificate
191    /// chain where the error occurred. If it is zero it occurred in the end
192    /// entity certificate, one if it is the certificate which signed the end
193    /// entity certificate and so on.
194    #[corresponds(X509_STORE_CTX_get_error_depth)]
195    pub fn error_depth(&self) -> u32 {
196        unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
197    }
198
199    /// Returns a reference to a complete valid `X509` certificate chain.
200    #[corresponds(X509_STORE_CTX_get0_chain)]
201    pub fn chain(&self) -> Option<&StackRef<X509>> {
202        unsafe {
203            let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
204
205            if chain.is_null() {
206                None
207            } else {
208                Some(StackRef::from_ptr(chain))
209            }
210        }
211    }
212}
213
214/// A builder used to construct an `X509`.
215pub struct X509Builder(X509);
216
217impl X509Builder {
218    /// Creates a new builder.
219    #[corresponds(X509_new)]
220    pub fn new() -> Result<X509Builder, ErrorStack> {
221        unsafe {
222            ffi::init();
223            cvt_p(ffi::X509_new()).map(|p| X509Builder(X509::from_ptr(p)))
224        }
225    }
226
227    /// Sets the notAfter constraint on the certificate.
228    #[corresponds(X509_set1_notAfter)]
229    pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
230        unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
231    }
232
233    /// Sets the notBefore constraint on the certificate.
234    #[corresponds(X509_set1_notBefore)]
235    pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
236        unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
237    }
238
239    /// Sets the version of the certificate.
240    ///
241    /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
242    /// the X.509 standard should pass `2` to this method.
243    #[corresponds(X509_set_version)]
244    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
245        unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
246    }
247
248    /// Sets the serial number of the certificate.
249    #[corresponds(X509_set_serialNumber)]
250    pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
251        unsafe {
252            cvt(ffi::X509_set_serialNumber(
253                self.0.as_ptr(),
254                serial_number.as_ptr(),
255            ))
256            .map(|_| ())
257        }
258    }
259
260    /// Sets the issuer name of the certificate.
261    #[corresponds(X509_set_issuer_name)]
262    pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
263        unsafe {
264            cvt(ffi::X509_set_issuer_name(
265                self.0.as_ptr(),
266                issuer_name.as_ptr(),
267            ))
268            .map(|_| ())
269        }
270    }
271
272    /// Sets the subject name of the certificate.
273    ///
274    /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools.
275    /// The `CN` field is used for the common name, such as a DNS name.
276    ///
277    /// ```
278    /// use rama_boring::x509::{X509, X509NameBuilder};
279    ///
280    /// let mut x509_name = rama_boring::x509::X509NameBuilder::new().unwrap();
281    /// x509_name.append_entry_by_text("C", "US").unwrap();
282    /// x509_name.append_entry_by_text("ST", "CA").unwrap();
283    /// x509_name.append_entry_by_text("O", "Some organization").unwrap();
284    /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap();
285    /// let x509_name = x509_name.build();
286    ///
287    /// let mut x509 = rama_boring::x509::X509::builder().unwrap();
288    /// x509.set_subject_name(&x509_name).unwrap();
289    /// ```
290    #[corresponds(X509_set_subject_name)]
291    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
292        unsafe {
293            cvt(ffi::X509_set_subject_name(
294                self.0.as_ptr(),
295                subject_name.as_ptr(),
296            ))
297            .map(|_| ())
298        }
299    }
300
301    /// Sets the public key associated with the certificate.
302    #[corresponds(X509_set_pubkey)]
303    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
304    where
305        T: HasPublic,
306    {
307        unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
308    }
309
310    /// Returns a context object which is needed to create certain X509 extension values.
311    ///
312    /// Set `issuer` to `None` if the certificate will be self-signed.
313    #[corresponds(X509V3_set_ctx)]
314    pub fn x509v3_context<'a>(
315        &'a self,
316        issuer: Option<&'a X509Ref>,
317        conf: Option<&'a ConfRef>,
318    ) -> X509v3Context<'a> {
319        unsafe {
320            let mut ctx = mem::zeroed();
321
322            let issuer = match issuer {
323                Some(issuer) => issuer.as_ptr(),
324                None => self.0.as_ptr(),
325            };
326            let subject = self.0.as_ptr();
327            ffi::X509V3_set_ctx(
328                &mut ctx,
329                issuer,
330                subject,
331                ptr::null_mut(),
332                ptr::null_mut(),
333                0,
334            );
335
336            // nodb case taken care of since we zeroed ctx above
337            if let Some(conf) = conf {
338                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
339            }
340
341            X509v3Context(ctx, PhantomData)
342        }
343    }
344
345    /// Adds an X509 extension value to the certificate.
346    ///
347    /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
348    pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
349        self.append_extension2(&extension)
350    }
351
352    /// Adds an X509 extension value to the certificate.
353    #[corresponds(X509_add_ext)]
354    pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
355        unsafe {
356            cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
357            Ok(())
358        }
359    }
360
361    /// Signs the certificate with a private key.
362    #[corresponds(X509_sign)]
363    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
364    where
365        T: HasPrivate,
366    {
367        unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
368    }
369
370    /// Consumes the builder, returning the certificate.
371    pub fn build(self) -> X509 {
372        self.0
373    }
374}
375
376foreign_type_and_impl_send_sync! {
377    type CType = ffi::X509;
378    fn drop = ffi::X509_free;
379
380    /// An `X509` public key certificate.
381    pub struct X509;
382}
383
384impl X509Ref {
385    /// Returns this certificate's subject name.
386    #[corresponds(X509_get_subject_name)]
387    pub fn subject_name(&self) -> &X509NameRef {
388        unsafe {
389            let name = ffi::X509_get_subject_name(self.as_ptr());
390            X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
391        }
392    }
393
394    /// Returns the hash of the certificates subject
395    #[corresponds(X509_subject_name_hash)]
396    pub fn subject_name_hash(&self) -> u32 {
397        unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
398    }
399
400    /// Returns this certificate's subject alternative name entries, if they exist.
401    #[corresponds(X509_get_ext_d2i)]
402    pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
403        unsafe {
404            let stack = ffi::X509_get_ext_d2i(
405                self.as_ptr(),
406                ffi::NID_subject_alt_name,
407                ptr::null_mut(),
408                ptr::null_mut(),
409            );
410            if stack.is_null() {
411                None
412            } else {
413                Some(Stack::from_ptr(stack as *mut _))
414            }
415        }
416    }
417
418    /// Returns this certificate's issuer name.
419    #[corresponds(X509_get_issuer_name)]
420    pub fn issuer_name(&self) -> &X509NameRef {
421        unsafe {
422            let name = ffi::X509_get_issuer_name(self.as_ptr());
423            X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
424        }
425    }
426
427    /// Returns this certificate's issuer alternative name entries, if they exist.
428    #[corresponds(X509_get_ext_d2i)]
429    pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
430        unsafe {
431            let stack = ffi::X509_get_ext_d2i(
432                self.as_ptr(),
433                ffi::NID_issuer_alt_name,
434                ptr::null_mut(),
435                ptr::null_mut(),
436            );
437            if stack.is_null() {
438                None
439            } else {
440                Some(Stack::from_ptr(stack as *mut _))
441            }
442        }
443    }
444
445    /// Returns this certificate's subject key id, if it exists.
446    #[corresponds(X509_get0_subject_key_id)]
447    pub fn subject_key_id(&self) -> Option<&Asn1StringRef> {
448        unsafe {
449            let data = ffi::X509_get0_subject_key_id(self.as_ptr());
450            Asn1StringRef::from_const_ptr_opt(data)
451        }
452    }
453
454    /// Returns this certificate's authority key id, if it exists.
455    #[corresponds(X509_get0_authority_key_id)]
456    pub fn authority_key_id(&self) -> Option<&Asn1StringRef> {
457        unsafe {
458            let data = ffi::X509_get0_authority_key_id(self.as_ptr());
459            Asn1StringRef::from_const_ptr_opt(data)
460        }
461    }
462
463    #[corresponds(X509_get_pubkey)]
464    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
465        unsafe {
466            let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
467            Ok(PKey::from_ptr(pkey))
468        }
469    }
470
471    /// Returns a digest of the DER representation of the certificate.
472    #[corresponds(X509_digest)]
473    pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
474        unsafe {
475            let mut digest = DigestBytes {
476                buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
477                len: ffi::EVP_MAX_MD_SIZE as usize,
478            };
479            let mut len = ffi::EVP_MAX_MD_SIZE.try_into().unwrap();
480            cvt(ffi::X509_digest(
481                self.as_ptr(),
482                hash_type.as_ptr(),
483                digest.buf.as_mut_ptr() as *mut _,
484                &mut len,
485            ))?;
486            digest.len = len as usize;
487
488            Ok(digest)
489        }
490    }
491
492    #[deprecated(since = "0.10.9", note = "renamed to digest")]
493    pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
494        self.digest(hash_type).map(|b| b.to_vec())
495    }
496
497    /// Returns the certificate's Not After validity period.
498    #[corresponds(X509_getm_notAfter)]
499    pub fn not_after(&self) -> &Asn1TimeRef {
500        unsafe {
501            let date = X509_getm_notAfter(self.as_ptr());
502            assert!(!date.is_null());
503            Asn1TimeRef::from_ptr(date)
504        }
505    }
506
507    /// Returns the certificate's Not Before validity period.
508    #[corresponds(X509_getm_notBefore)]
509    pub fn not_before(&self) -> &Asn1TimeRef {
510        unsafe {
511            let date = X509_getm_notBefore(self.as_ptr());
512            assert!(!date.is_null());
513            Asn1TimeRef::from_ptr(date)
514        }
515    }
516
517    /// Returns the certificate's signature
518    #[corresponds(X509_get0_signature)]
519    pub fn signature(&self) -> &Asn1BitStringRef {
520        unsafe {
521            let mut signature = ptr::null();
522            X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
523            assert!(!signature.is_null());
524            Asn1BitStringRef::from_ptr(signature as *mut _)
525        }
526    }
527
528    /// Returns the certificate's signature algorithm.
529    #[corresponds(X509_get0_signature)]
530    pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
531        unsafe {
532            let mut algor = ptr::null();
533            X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
534            assert!(!algor.is_null());
535            X509AlgorithmRef::from_ptr(algor as *mut _)
536        }
537    }
538
539    /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
540    /// Access field.
541    #[corresponds(X509_get1_ocsp)]
542    pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
543        unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
544    }
545
546    /// Checks that this certificate issued `subject`.
547    #[corresponds(X509_check_issued)]
548    pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
549        unsafe {
550            let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
551            X509VerifyError::from_raw(r)
552        }
553    }
554
555    /// Check if the certificate is signed using the given public key.
556    ///
557    /// Only the signature is checked: no other checks (such as certificate chain validity)
558    /// are performed.
559    ///
560    /// Returns `true` if verification succeeds.
561    #[corresponds(X509_verify)]
562    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
563    where
564        T: HasPublic,
565    {
566        unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
567    }
568
569    /// Returns this certificate's serial number.
570    #[corresponds(X509_get_serialNumber)]
571    pub fn serial_number(&self) -> &Asn1IntegerRef {
572        unsafe {
573            let r = ffi::X509_get_serialNumber(self.as_ptr());
574            assert!(!r.is_null());
575            Asn1IntegerRef::from_ptr(r)
576        }
577    }
578
579    pub fn check_host(&self, host: &str) -> Result<bool, ErrorStack> {
580        unsafe {
581            cvt_n(ffi::X509_check_host(
582                self.as_ptr(),
583                host.as_ptr() as _,
584                host.len(),
585                0,
586                std::ptr::null_mut(),
587            ))
588            .map(|n| n == 1)
589        }
590    }
591
592    to_pem! {
593        /// Serializes the certificate into a PEM-encoded X509 structure.
594        ///
595        /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
596        #[corresponds(PEM_write_bio_X509)]
597        to_pem,
598        ffi::PEM_write_bio_X509
599    }
600
601    to_der! {
602        /// Serializes the certificate into a DER-encoded X509 structure.
603        #[corresponds(i2d_X509)]
604        to_der,
605        ffi::i2d_X509
606    }
607}
608
609impl ToOwned for X509Ref {
610    type Owned = X509;
611
612    fn to_owned(&self) -> X509 {
613        unsafe {
614            X509_up_ref(self.as_ptr());
615            X509::from_ptr(self.as_ptr())
616        }
617    }
618}
619
620impl X509 {
621    /// Returns a new builder.
622    pub fn builder() -> Result<X509Builder, ErrorStack> {
623        X509Builder::new()
624    }
625
626    from_pem! {
627        /// Deserializes a PEM-encoded X509 structure.
628        ///
629        /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
630        #[corresponds(PEM_read_bio_X509)]
631        from_pem,
632        X509,
633        ffi::PEM_read_bio_X509
634    }
635
636    from_der! {
637        /// Deserializes a DER-encoded X509 structure.
638        #[corresponds(d2i_X509)]
639        from_der,
640        X509,
641        ffi::d2i_X509,
642        ::libc::c_long
643    }
644
645    /// Deserializes a list of PEM-formatted certificates.
646    #[corresponds(PEM_read_bio_X509)]
647    pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
648        unsafe {
649            ffi::init();
650            let bio = MemBioSlice::new(pem)?;
651
652            let mut certs = vec![];
653            loop {
654                let r =
655                    ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
656                if r.is_null() {
657                    let err = ffi::ERR_peek_last_error();
658
659                    if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM.0.try_into().unwrap()
660                        && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
661                    {
662                        ffi::ERR_clear_error();
663                        break;
664                    }
665
666                    return Err(ErrorStack::get());
667                } else {
668                    certs.push(X509::from_ptr(r));
669                }
670            }
671
672            Ok(certs)
673        }
674    }
675}
676
677impl Clone for X509 {
678    fn clone(&self) -> X509 {
679        X509Ref::to_owned(self)
680    }
681}
682
683impl fmt::Debug for X509 {
684    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
685        let serial = match &self.serial_number().to_bn() {
686            Ok(bn) => match bn.to_hex_str() {
687                Ok(hex) => hex.to_string(),
688                Err(_) => "".to_string(),
689            },
690            Err(_) => "".to_string(),
691        };
692        let mut debug_struct = formatter.debug_struct("X509");
693        debug_struct.field("serial_number", &serial);
694        debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
695        debug_struct.field("issuer", &self.issuer_name());
696        debug_struct.field("subject", &self.subject_name());
697        if let Some(subject_alt_names) = &self.subject_alt_names() {
698            debug_struct.field("subject_alt_names", subject_alt_names);
699        }
700        debug_struct.field("not_before", &self.not_before());
701        debug_struct.field("not_after", &self.not_after());
702
703        if let Ok(public_key) = &self.public_key() {
704            debug_struct.field("public_key", public_key);
705        };
706        // TODO: Print extensions once they are supported on the X509 struct.
707
708        debug_struct.finish()
709    }
710}
711
712impl AsRef<X509Ref> for X509Ref {
713    fn as_ref(&self) -> &X509Ref {
714        self
715    }
716}
717
718impl Stackable for X509 {
719    type StackType = ffi::stack_st_X509;
720}
721
722/// A context object required to construct certain `X509` extension values.
723pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
724
725impl X509v3Context<'_> {
726    pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
727        &self.0 as *const _ as *mut _
728    }
729}
730
731foreign_type_and_impl_send_sync! {
732    type CType = ffi::X509_EXTENSION;
733    fn drop = ffi::X509_EXTENSION_free;
734
735    /// Permit additional fields to be added to an `X509` v3 certificate.
736    pub struct X509Extension;
737}
738
739impl Stackable for X509Extension {
740    type StackType = ffi::stack_st_X509_EXTENSION;
741}
742
743impl X509Extension {
744    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
745    /// names and their value formats.
746    ///
747    /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
748    /// provided.
749    ///
750    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
751    /// mini-language that can read arbitrary files.
752    ///
753    /// See the extension module for builder types which will construct certain common extensions.
754    pub fn new(
755        conf: Option<&ConfRef>,
756        context: Option<&X509v3Context>,
757        name: &str,
758        value: &str,
759    ) -> Result<X509Extension, ErrorStack> {
760        let name = CString::new(name).unwrap();
761        let value = CString::new(value).unwrap();
762        let mut ctx;
763        unsafe {
764            ffi::init();
765            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
766            let context_ptr = match context {
767                Some(c) => c.as_ptr(),
768                None => {
769                    ctx = mem::zeroed();
770
771                    ffi::X509V3_set_ctx(
772                        &mut ctx,
773                        ptr::null_mut(),
774                        ptr::null_mut(),
775                        ptr::null_mut(),
776                        ptr::null_mut(),
777                        0,
778                    );
779                    &mut ctx
780                }
781            };
782            let name = name.as_ptr() as *mut _;
783            let value = value.as_ptr() as *mut _;
784
785            cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value))
786                .map(|p| X509Extension::from_ptr(p))
787        }
788    }
789
790    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
791    /// extensions and their value formats.
792    ///
793    /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
794    /// be provided.
795    ///
796    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
797    /// mini-language that can read arbitrary files.
798    ///
799    /// See the extension module for builder types which will construct certain common extensions.
800    pub fn new_nid(
801        conf: Option<&ConfRef>,
802        context: Option<&X509v3Context>,
803        name: Nid,
804        value: &str,
805    ) -> Result<X509Extension, ErrorStack> {
806        let value = CString::new(value).unwrap();
807        let mut ctx;
808        unsafe {
809            ffi::init();
810            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
811            let context_ptr = match context {
812                Some(c) => c.as_ptr(),
813                None => {
814                    ctx = mem::zeroed();
815
816                    ffi::X509V3_set_ctx(
817                        &mut ctx,
818                        ptr::null_mut(),
819                        ptr::null_mut(),
820                        ptr::null_mut(),
821                        ptr::null_mut(),
822                        0,
823                    );
824                    &mut ctx
825                }
826            };
827            let name = name.as_raw();
828            let value = value.as_ptr() as *mut _;
829
830            cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value))
831                .map(|p| X509Extension::from_ptr(p))
832        }
833    }
834
835    pub(crate) unsafe fn new_internal(
836        nid: Nid,
837        critical: bool,
838        value: *mut c_void,
839    ) -> Result<X509Extension, ErrorStack> {
840        ffi::init();
841        cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value))
842            .map(|p| X509Extension::from_ptr(p))
843    }
844}
845
846impl X509ExtensionRef {
847    to_der! {
848        /// Serializes the Extension to its standard DER encoding.
849        to_der,
850        ffi::i2d_X509_EXTENSION
851    }
852}
853
854/// A builder used to construct an `X509Name`.
855pub struct X509NameBuilder(X509Name);
856
857impl X509NameBuilder {
858    /// Creates a new builder.
859    pub fn new() -> Result<X509NameBuilder, ErrorStack> {
860        unsafe {
861            ffi::init();
862            cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name::from_ptr(p)))
863        }
864    }
865
866    /// Add a field entry by str.
867    #[corresponds(X509_NAME_add_entry_by_txt)]
868    pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
869        unsafe {
870            let field = CString::new(field).unwrap();
871            assert!(value.len() <= ValueLen::MAX as usize);
872            cvt(ffi::X509_NAME_add_entry_by_txt(
873                self.0.as_ptr(),
874                field.as_ptr() as *mut _,
875                ffi::MBSTRING_UTF8,
876                value.as_ptr(),
877                value.len() as ValueLen,
878                -1,
879                0,
880            ))
881            .map(|_| ())
882        }
883    }
884
885    /// Add a field entry by str with a specific type.
886    #[corresponds(X509_NAME_add_entry_by_txt)]
887    pub fn append_entry_by_text_with_type(
888        &mut self,
889        field: &str,
890        value: &str,
891        ty: Asn1Type,
892    ) -> Result<(), ErrorStack> {
893        unsafe {
894            let field = CString::new(field).unwrap();
895            assert!(value.len() <= ValueLen::MAX as usize);
896            cvt(ffi::X509_NAME_add_entry_by_txt(
897                self.0.as_ptr(),
898                field.as_ptr() as *mut _,
899                ty.as_raw(),
900                value.as_ptr(),
901                value.len() as ValueLen,
902                -1,
903                0,
904            ))
905            .map(|_| ())
906        }
907    }
908
909    /// Add a field entry by NID.
910    #[corresponds(X509_NAME_add_entry_by_NID)]
911    pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
912        unsafe {
913            assert!(value.len() <= ValueLen::MAX as usize);
914            cvt(ffi::X509_NAME_add_entry_by_NID(
915                self.0.as_ptr(),
916                field.as_raw(),
917                ffi::MBSTRING_UTF8,
918                value.as_ptr() as *mut _,
919                value.len() as ValueLen,
920                -1,
921                0,
922            ))
923            .map(|_| ())
924        }
925    }
926
927    /// Add a field entry by NID with a specific type.
928    #[corresponds(X509_NAME_add_entry_by_NID)]
929    pub fn append_entry_by_nid_with_type(
930        &mut self,
931        field: Nid,
932        value: &str,
933        ty: Asn1Type,
934    ) -> Result<(), ErrorStack> {
935        unsafe {
936            assert!(value.len() <= ValueLen::MAX as usize);
937            cvt(ffi::X509_NAME_add_entry_by_NID(
938                self.0.as_ptr(),
939                field.as_raw(),
940                ty.as_raw(),
941                value.as_ptr() as *mut _,
942                value.len() as ValueLen,
943                -1,
944                0,
945            ))
946            .map(|_| ())
947        }
948    }
949
950    /// Return an `X509Name`.
951    pub fn build(self) -> X509Name {
952        // Round-trip through bytes because OpenSSL is not const correct and
953        // names in a "modified" state compute various things lazily. This can
954        // lead to data-races because OpenSSL doesn't have locks or anything.
955        X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
956    }
957}
958
959type ValueLen = isize;
960
961foreign_type_and_impl_send_sync! {
962    type CType = ffi::X509_NAME;
963    fn drop = ffi::X509_NAME_free;
964
965    /// The names of an `X509` certificate.
966    pub struct X509Name;
967}
968
969impl X509Name {
970    /// Returns a new builder.
971    pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
972        X509NameBuilder::new()
973    }
974
975    /// Loads subject names from a file containing PEM-formatted certificates.
976    ///
977    /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
978    pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
979        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
980        unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
981    }
982
983    from_der! {
984        /// Deserializes a DER-encoded X509 name structure.
985        #[corresponds(d2i_X509_NAME)]
986        from_der,
987        X509Name,
988        ffi::d2i_X509_NAME,
989        ::libc::c_long
990    }
991}
992
993impl Stackable for X509Name {
994    type StackType = ffi::stack_st_X509_NAME;
995}
996
997impl X509NameRef {
998    /// Returns the name entries by the nid.
999    pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1000        X509NameEntries {
1001            name: self,
1002            nid: Some(nid),
1003            loc: -1,
1004        }
1005    }
1006
1007    /// Returns an iterator over all `X509NameEntry` values
1008    pub fn entries(&self) -> X509NameEntries<'_> {
1009        X509NameEntries {
1010            name: self,
1011            nid: None,
1012            loc: -1,
1013        }
1014    }
1015
1016    /// Returns an owned String representing the X509 name configurable via incoming flags.
1017    ///
1018    /// This function will return `None` if the underlying string contains invalid utf-8.
1019    #[corresponds(X509_NAME_print_ex)]
1020    pub fn print_ex(&self, flags: i32) -> Option<String> {
1021        unsafe {
1022            let bio = MemBio::new().ok()?;
1023            ffi::X509_NAME_print_ex(bio.as_ptr(), self.as_ptr(), 0, flags as _);
1024            let buf = bio.get_buf().to_vec();
1025            let res = String::from_utf8(buf);
1026            res.ok()
1027        }
1028    }
1029
1030    to_der! {
1031        /// Serializes the certificate into a DER-encoded X509 name structure.
1032        #[corresponds(i2d_X509_NAME)]
1033        to_der,
1034        ffi::i2d_X509_NAME
1035    }
1036}
1037
1038impl fmt::Debug for X509NameRef {
1039    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1040        formatter.debug_list().entries(self.entries()).finish()
1041    }
1042}
1043
1044/// A type to destructure and examine an `X509Name`.
1045pub struct X509NameEntries<'a> {
1046    name: &'a X509NameRef,
1047    nid: Option<Nid>,
1048    loc: c_int,
1049}
1050
1051impl<'a> Iterator for X509NameEntries<'a> {
1052    type Item = &'a X509NameEntryRef;
1053
1054    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1055        unsafe {
1056            match self.nid {
1057                Some(nid) => {
1058                    // There is a `Nid` specified to search for
1059                    self.loc =
1060                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1061                    if self.loc == -1 {
1062                        return None;
1063                    }
1064                }
1065                None => {
1066                    // Iterate over all `Nid`s
1067                    self.loc += 1;
1068                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1069                        return None;
1070                    }
1071                }
1072            }
1073
1074            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1075            assert!(!entry.is_null());
1076
1077            Some(X509NameEntryRef::from_ptr(entry))
1078        }
1079    }
1080}
1081
1082foreign_type_and_impl_send_sync! {
1083    type CType = ffi::X509_NAME_ENTRY;
1084    fn drop = ffi::X509_NAME_ENTRY_free;
1085
1086    /// A name entry associated with a `X509Name`.
1087    pub struct X509NameEntry;
1088}
1089
1090impl X509NameEntryRef {
1091    /// Returns the field value of an `X509NameEntry`.
1092    #[corresponds(X509_NAME_ENTRY_get_data)]
1093    pub fn data(&self) -> &Asn1StringRef {
1094        unsafe {
1095            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1096            Asn1StringRef::from_ptr(data)
1097        }
1098    }
1099
1100    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1101    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1102    #[corresponds(X509_NAME_ENTRY_get_object)]
1103    pub fn object(&self) -> &Asn1ObjectRef {
1104        unsafe {
1105            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1106            Asn1ObjectRef::from_ptr(object)
1107        }
1108    }
1109}
1110
1111impl fmt::Debug for X509NameEntryRef {
1112    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1113        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1114    }
1115}
1116
1117/// A builder used to construct an `X509Req`.
1118pub struct X509ReqBuilder(X509Req);
1119
1120impl X509ReqBuilder {
1121    /// Returns a builder for a certificate request.
1122    ///
1123    /// This corresponds to [`X509_REQ_new`].
1124    ///
1125    ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html
1126    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1127        unsafe {
1128            ffi::init();
1129            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req::from_ptr(p)))
1130        }
1131    }
1132
1133    /// Set the numerical value of the version field.
1134    ///
1135    /// This corresponds to [`X509_REQ_set_version`].
1136    ///
1137    ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html
1138    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1139        unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
1140    }
1141
1142    /// Set the issuer name.
1143    #[corresponds(X509_REQ_set_subject_name)]
1144    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1145        unsafe {
1146            cvt(ffi::X509_REQ_set_subject_name(
1147                self.0.as_ptr(),
1148                subject_name.as_ptr(),
1149            ))
1150            .map(|_| ())
1151        }
1152    }
1153
1154    /// Set the public key.
1155    #[corresponds(X509_REQ_set_pubkey)]
1156    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1157    where
1158        T: HasPublic,
1159    {
1160        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1161    }
1162
1163    /// Return an `X509v3Context`. This context object can be used to construct
1164    /// certain `X509` extensions.
1165    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1166        unsafe {
1167            let mut ctx = mem::zeroed();
1168
1169            ffi::X509V3_set_ctx(
1170                &mut ctx,
1171                ptr::null_mut(),
1172                ptr::null_mut(),
1173                self.0.as_ptr(),
1174                ptr::null_mut(),
1175                0,
1176            );
1177
1178            // nodb case taken care of since we zeroed ctx above
1179            if let Some(conf) = conf {
1180                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1181            }
1182
1183            X509v3Context(ctx, PhantomData)
1184        }
1185    }
1186
1187    /// Permits any number of extension fields to be added to the certificate.
1188    pub fn add_extensions(
1189        &mut self,
1190        extensions: &StackRef<X509Extension>,
1191    ) -> Result<(), ErrorStack> {
1192        unsafe {
1193            cvt(ffi::X509_REQ_add_extensions(
1194                self.0.as_ptr(),
1195                extensions.as_ptr(),
1196            ))
1197            .map(|_| ())
1198        }
1199    }
1200
1201    /// Sign the request using a private key.
1202    #[corresponds(X509_REQ_sign)]
1203    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1204    where
1205        T: HasPrivate,
1206    {
1207        unsafe {
1208            cvt(ffi::X509_REQ_sign(
1209                self.0.as_ptr(),
1210                key.as_ptr(),
1211                hash.as_ptr(),
1212            ))
1213            .map(|_| ())
1214        }
1215    }
1216
1217    /// Returns the `X509Req`.
1218    pub fn build(self) -> X509Req {
1219        self.0
1220    }
1221}
1222
1223foreign_type_and_impl_send_sync! {
1224    type CType = ffi::X509_REQ;
1225    fn drop = ffi::X509_REQ_free;
1226
1227    /// An `X509` certificate request.
1228    pub struct X509Req;
1229}
1230
1231impl X509Req {
1232    /// A builder for `X509Req`.
1233    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1234        X509ReqBuilder::new()
1235    }
1236
1237    from_pem! {
1238        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1239        ///
1240        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1241        #[corresponds(PEM_read_bio_X509_REQ)]
1242        from_pem,
1243        X509Req,
1244        ffi::PEM_read_bio_X509_REQ
1245    }
1246
1247    from_der! {
1248        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1249        #[corresponds(d2i_X509_REQ)]
1250        from_der,
1251        X509Req,
1252        ffi::d2i_X509_REQ,
1253        ::libc::c_long
1254    }
1255}
1256
1257impl X509ReqRef {
1258    to_pem! {
1259        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1260        ///
1261        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1262        #[corresponds(PEM_write_bio_X509_REQ)]
1263        to_pem,
1264        ffi::PEM_write_bio_X509_REQ
1265    }
1266
1267    to_der! {
1268        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1269        #[corresponds(i2d_X509_REQ)]
1270        to_der,
1271        ffi::i2d_X509_REQ
1272    }
1273
1274    /// Returns the numerical value of the version field of the certificate request.
1275    #[corresponds(X509_REQ_get_version)]
1276    pub fn version(&self) -> i32 {
1277        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1278    }
1279
1280    /// Returns the subject name of the certificate request.
1281    #[corresponds(X509_REQ_get_subject_name)]
1282    pub fn subject_name(&self) -> &X509NameRef {
1283        unsafe {
1284            let name = X509_REQ_get_subject_name(self.as_ptr());
1285            assert!(!name.is_null());
1286            X509NameRef::from_ptr(name)
1287        }
1288    }
1289
1290    /// Returns the public key of the certificate request.
1291    ///
1292    /// This corresponds to [`X509_REQ_get_pubkey"]
1293    ///
1294    /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html
1295    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1296        unsafe {
1297            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1298            Ok(PKey::from_ptr(key))
1299        }
1300    }
1301
1302    /// Check if the certificate request is signed using the given public key.
1303    ///
1304    /// Returns `true` if verification succeeds.
1305    ///
1306    /// This corresponds to [`X509_REQ_verify"].
1307    ///
1308    /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html
1309    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1310    where
1311        T: HasPublic,
1312    {
1313        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1314    }
1315
1316    /// Returns the extensions of the certificate request.
1317    ///
1318    /// This corresponds to [`X509_REQ_get_extensions"]
1319    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1320        unsafe {
1321            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1322            Ok(Stack::from_ptr(extensions))
1323        }
1324    }
1325}
1326
1327/// The result of peer certificate verification.
1328pub type X509VerifyResult = Result<(), X509VerifyError>;
1329
1330#[derive(Copy, Clone, PartialEq, Eq)]
1331pub struct X509VerifyError(c_int);
1332
1333impl fmt::Debug for X509VerifyError {
1334    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1335        fmt.debug_struct("X509VerifyError")
1336            .field("code", &self.0)
1337            .field("error", &self.error_string())
1338            .finish()
1339    }
1340}
1341
1342impl fmt::Display for X509VerifyError {
1343    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1344        fmt.write_str(self.error_string())
1345    }
1346}
1347
1348impl Error for X509VerifyError {}
1349
1350impl X509VerifyError {
1351    /// Creates an [`X509VerifyResult`] from a raw error number.
1352    ///
1353    /// # Safety
1354    ///
1355    /// Some methods on [`X509VerifyError`] are not thread safe if the error
1356    /// number is invalid.
1357    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1358        if err == ffi::X509_V_OK {
1359            Ok(())
1360        } else {
1361            Err(X509VerifyError(err))
1362        }
1363    }
1364
1365    /// Return the integer representation of an [`X509VerifyError`].
1366    #[allow(clippy::trivially_copy_pass_by_ref)]
1367    pub fn as_raw(&self) -> c_int {
1368        self.0
1369    }
1370
1371    /// Return a human readable error string from the verification error.
1372    #[corresponds(X509_verify_cert_error_string)]
1373    #[allow(clippy::trivially_copy_pass_by_ref)]
1374    pub fn error_string(&self) -> &'static str {
1375        ffi::init();
1376
1377        unsafe {
1378            let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1379            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1380        }
1381    }
1382}
1383
1384#[allow(missing_docs)] // no need to document the constants
1385impl X509VerifyError {
1386    pub const UNSPECIFIED: Self = Self(ffi::X509_V_ERR_UNSPECIFIED);
1387    pub const UNABLE_TO_GET_ISSUER_CERT: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
1388    pub const UNABLE_TO_GET_CRL: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL);
1389    pub const UNABLE_TO_DECRYPT_CERT_SIGNATURE: Self =
1390        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
1391    pub const UNABLE_TO_DECRYPT_CRL_SIGNATURE: Self =
1392        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
1393    pub const UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Self =
1394        Self(ffi::X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
1395    pub const CERT_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CERT_SIGNATURE_FAILURE);
1396    pub const CRL_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE);
1397    pub const CERT_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CERT_NOT_YET_VALID);
1398    pub const CERT_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CERT_HAS_EXPIRED);
1399    pub const CRL_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CRL_NOT_YET_VALID);
1400    pub const CRL_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CRL_HAS_EXPIRED);
1401    pub const ERROR_IN_CERT_NOT_BEFORE_FIELD: Self =
1402        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
1403    pub const ERROR_IN_CERT_NOT_AFTER_FIELD: Self =
1404        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
1405    pub const ERROR_IN_CRL_LAST_UPDATE_FIELD: Self =
1406        Self(ffi::X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
1407    pub const ERROR_IN_CRL_NEXT_UPDATE_FIELD: Self =
1408        Self(ffi::X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
1409    pub const OUT_OF_MEM: Self = Self(ffi::X509_V_ERR_OUT_OF_MEM);
1410    pub const DEPTH_ZERO_SELF_SIGNED_CERT: Self = Self(ffi::X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
1411    pub const SELF_SIGNED_CERT_IN_CHAIN: Self = Self(ffi::X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
1412    pub const UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Self =
1413        Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
1414    pub const UNABLE_TO_VERIFY_LEAF_SIGNATURE: Self =
1415        Self(ffi::X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
1416    pub const CERT_CHAIN_TOO_LONG: Self = Self(ffi::X509_V_ERR_CERT_CHAIN_TOO_LONG);
1417    pub const CERT_REVOKED: Self = Self(ffi::X509_V_ERR_CERT_REVOKED);
1418    pub const INVALID_CA: Self = Self(ffi::X509_V_ERR_INVALID_CA);
1419    pub const PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PATH_LENGTH_EXCEEDED);
1420    pub const INVALID_PURPOSE: Self = Self(ffi::X509_V_ERR_INVALID_PURPOSE);
1421    pub const CERT_UNTRUSTED: Self = Self(ffi::X509_V_ERR_CERT_UNTRUSTED);
1422    pub const CERT_REJECTED: Self = Self(ffi::X509_V_ERR_CERT_REJECTED);
1423    pub const SUBJECT_ISSUER_MISMATCH: Self = Self(ffi::X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
1424    pub const AKID_SKID_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_SKID_MISMATCH);
1425    pub const AKID_ISSUER_SERIAL_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
1426    pub const KEYUSAGE_NO_CERTSIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
1427    pub const UNABLE_TO_GET_CRL_ISSUER: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
1428    pub const UNHANDLED_CRITICAL_EXTENSION: Self =
1429        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
1430    pub const KEYUSAGE_NO_CRL_SIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
1431    pub const UNHANDLED_CRITICAL_CRL_EXTENSION: Self =
1432        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
1433    pub const INVALID_NON_CA: Self = Self(ffi::X509_V_ERR_INVALID_NON_CA);
1434    pub const PROXY_PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
1435    pub const KEYUSAGE_NO_DIGITAL_SIGNATURE: Self =
1436        Self(ffi::X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
1437    pub const PROXY_CERTIFICATES_NOT_ALLOWED: Self =
1438        Self(ffi::X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
1439    pub const INVALID_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_EXTENSION);
1440    pub const INVALID_POLICY_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_POLICY_EXTENSION);
1441    pub const NO_EXPLICIT_POLICY: Self = Self(ffi::X509_V_ERR_NO_EXPLICIT_POLICY);
1442    pub const DIFFERENT_CRL_SCOPE: Self = Self(ffi::X509_V_ERR_DIFFERENT_CRL_SCOPE);
1443    pub const UNSUPPORTED_EXTENSION_FEATURE: Self =
1444        Self(ffi::X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
1445    pub const UNNESTED_RESOURCE: Self = Self(ffi::X509_V_ERR_UNNESTED_RESOURCE);
1446    pub const PERMITTED_VIOLATION: Self = Self(ffi::X509_V_ERR_PERMITTED_VIOLATION);
1447    pub const EXCLUDED_VIOLATION: Self = Self(ffi::X509_V_ERR_EXCLUDED_VIOLATION);
1448    pub const SUBTREE_MINMAX: Self = Self(ffi::X509_V_ERR_SUBTREE_MINMAX);
1449    pub const APPLICATION_VERIFICATION: Self = Self(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1450    pub const UNSUPPORTED_CONSTRAINT_TYPE: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
1451    pub const UNSUPPORTED_CONSTRAINT_SYNTAX: Self =
1452        Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
1453    pub const UNSUPPORTED_NAME_SYNTAX: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
1454    pub const CRL_PATH_VALIDATION_ERROR: Self = Self(ffi::X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
1455    pub const HOSTNAME_MISMATCH: Self = Self(ffi::X509_V_ERR_HOSTNAME_MISMATCH);
1456    pub const EMAIL_MISMATCH: Self = Self(ffi::X509_V_ERR_EMAIL_MISMATCH);
1457    pub const IP_ADDRESS_MISMATCH: Self = Self(ffi::X509_V_ERR_IP_ADDRESS_MISMATCH);
1458    pub const INVALID_CALL: Self = Self(ffi::X509_V_ERR_INVALID_CALL);
1459    pub const STORE_LOOKUP: Self = Self(ffi::X509_V_ERR_STORE_LOOKUP);
1460    pub const NAME_CONSTRAINTS_WITHOUT_SANS: Self =
1461        Self(ffi::X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS);
1462}
1463
1464foreign_type_and_impl_send_sync! {
1465    type CType = ffi::GENERAL_NAME;
1466    fn drop = ffi::GENERAL_NAME_free;
1467
1468    /// An `X509` certificate alternative names.
1469    pub struct GeneralName;
1470}
1471
1472impl GeneralName {
1473    unsafe fn new(
1474        type_: c_int,
1475        asn1_type: Asn1Type,
1476        value: &[u8],
1477    ) -> Result<GeneralName, ErrorStack> {
1478        ffi::init();
1479        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1480        (*gn.as_ptr()).type_ = type_;
1481        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
1482        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
1483
1484        (*gn.as_ptr()).d.ptr = s.cast();
1485
1486        Ok(gn)
1487    }
1488
1489    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
1490        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
1491    }
1492
1493    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
1494        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
1495    }
1496
1497    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
1498        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
1499    }
1500
1501    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
1502        match ip {
1503            IpAddr::V4(addr) => unsafe {
1504                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1505            },
1506            IpAddr::V6(addr) => unsafe {
1507                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1508            },
1509        }
1510    }
1511
1512    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
1513        unsafe {
1514            ffi::init();
1515            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
1516            (*gn).type_ = ffi::GEN_RID;
1517            (*gn).d.registeredID = oid.into_ptr();
1518
1519            Ok(GeneralName::from_ptr(gn))
1520        }
1521    }
1522}
1523
1524impl GeneralNameRef {
1525    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1526        unsafe {
1527            if (*self.as_ptr()).type_ != ffi_type {
1528                return None;
1529            }
1530
1531            let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
1532            let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
1533
1534            let slice = slice::from_raw_parts(ptr, len as usize);
1535            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1536            // OpenSSL checks that when loading a certificate but if not we'll
1537            // use this instead of from_utf8_unchecked just in case.
1538            str::from_utf8(slice).ok()
1539        }
1540    }
1541
1542    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
1543    pub fn email(&self) -> Option<&str> {
1544        self.ia5_string(ffi::GEN_EMAIL)
1545    }
1546
1547    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
1548    pub fn dnsname(&self) -> Option<&str> {
1549        self.ia5_string(ffi::GEN_DNS)
1550    }
1551
1552    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
1553    pub fn uri(&self) -> Option<&str> {
1554        self.ia5_string(ffi::GEN_URI)
1555    }
1556
1557    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
1558    pub fn ipaddress(&self) -> Option<&[u8]> {
1559        unsafe {
1560            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1561                return None;
1562            }
1563
1564            let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
1565            let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
1566
1567            Some(slice::from_raw_parts(ptr, len as usize))
1568        }
1569    }
1570}
1571
1572impl fmt::Debug for GeneralNameRef {
1573    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1574        if let Some(email) = self.email() {
1575            formatter.write_str(email)
1576        } else if let Some(dnsname) = self.dnsname() {
1577            formatter.write_str(dnsname)
1578        } else if let Some(uri) = self.uri() {
1579            formatter.write_str(uri)
1580        } else if let Some(ipaddress) = self.ipaddress() {
1581            let result = String::from_utf8_lossy(ipaddress);
1582            formatter.write_str(&result)
1583        } else {
1584            formatter.write_str("(empty)")
1585        }
1586    }
1587}
1588
1589impl Stackable for GeneralName {
1590    type StackType = ffi::stack_st_GENERAL_NAME;
1591}
1592
1593foreign_type_and_impl_send_sync! {
1594    type CType = ffi::X509_ALGOR;
1595    fn drop = ffi::X509_ALGOR_free;
1596
1597    /// An `X509` certificate signature algorithm.
1598    pub struct X509Algorithm;
1599}
1600
1601impl X509AlgorithmRef {
1602    /// Returns the ASN.1 OID of this algorithm.
1603    pub fn object(&self) -> &Asn1ObjectRef {
1604        unsafe {
1605            let mut oid = ptr::null();
1606            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1607            assert!(!oid.is_null());
1608            Asn1ObjectRef::from_ptr(oid as *mut _)
1609        }
1610    }
1611}
1612
1613foreign_type_and_impl_send_sync! {
1614    type CType = ffi::X509_OBJECT;
1615    fn drop = X509_OBJECT_free;
1616
1617    /// An `X509` or an X509 certificate revocation list.
1618    pub struct X509Object;
1619}
1620
1621impl X509ObjectRef {
1622    pub fn x509(&self) -> Option<&X509Ref> {
1623        unsafe {
1624            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1625            if ptr.is_null() {
1626                None
1627            } else {
1628                Some(X509Ref::from_ptr(ptr))
1629            }
1630        }
1631    }
1632}
1633
1634impl Stackable for X509Object {
1635    type StackType = ffi::stack_st_X509_OBJECT;
1636}
1637
1638use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
1639
1640use crate::ffi::{
1641    ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
1642    X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
1643};
1644
1645use crate::ffi::X509_OBJECT_get0_X509;
1646
1647#[allow(bad_style)]
1648unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1649    ffi::X509_OBJECT_free_contents(x);
1650    ffi::OPENSSL_free(x as *mut libc::c_void);
1651}