Skip to main content

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