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, 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::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    /// Signs the certificate with a private key.
488    #[corresponds(X509_sign)]
489    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
490    where
491        T: HasPrivate,
492    {
493        unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())) }
494    }
495
496    /// Consumes the builder, returning the certificate.
497    #[must_use]
498    pub fn build(self) -> X509 {
499        self.0
500    }
501}
502
503foreign_type_and_impl_send_sync! {
504    type CType = ffi::X509;
505    fn drop = ffi::X509_free;
506
507    /// An `X509` public key certificate.
508    pub struct X509;
509}
510
511impl X509Ref {
512    /// Returns this certificate's subject name.
513    #[corresponds(X509_get_subject_name)]
514    #[must_use]
515    pub fn subject_name(&self) -> &X509NameRef {
516        unsafe {
517            let name = ffi::X509_get_subject_name(self.as_ptr());
518            X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
519        }
520    }
521
522    /// Returns the hash of the certificates subject
523    #[corresponds(X509_subject_name_hash)]
524    #[must_use]
525    pub fn subject_name_hash(&self) -> u32 {
526        unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
527    }
528
529    /// Returns this certificate's subject alternative name entries, if they exist.
530    #[corresponds(X509_get_ext_d2i)]
531    #[must_use]
532    pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
533        unsafe {
534            let stack = ffi::X509_get_ext_d2i(
535                self.as_ptr(),
536                ffi::NID_subject_alt_name,
537                ptr::null_mut(),
538                ptr::null_mut(),
539            );
540            if stack.is_null() {
541                None
542            } else {
543                Some(Stack::from_ptr(stack.cast()))
544            }
545        }
546    }
547
548    /// Returns this certificate's issuer name.
549    #[corresponds(X509_get_issuer_name)]
550    #[must_use]
551    pub fn issuer_name(&self) -> &X509NameRef {
552        unsafe {
553            let name = ffi::X509_get_issuer_name(self.as_ptr());
554            X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
555        }
556    }
557
558    /// Returns this certificate's issuer alternative name entries, if they exist.
559    #[corresponds(X509_get_ext_d2i)]
560    #[must_use]
561    pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
562        unsafe {
563            let stack = ffi::X509_get_ext_d2i(
564                self.as_ptr(),
565                ffi::NID_issuer_alt_name,
566                ptr::null_mut(),
567                ptr::null_mut(),
568            );
569            if stack.is_null() {
570                None
571            } else {
572                Some(Stack::from_ptr(stack.cast()))
573            }
574        }
575    }
576
577    /// Returns this certificate's subject key id, if it exists.
578    #[corresponds(X509_get0_subject_key_id)]
579    #[must_use]
580    pub fn subject_key_id(&self) -> Option<&Asn1StringRef> {
581        unsafe {
582            let data = ffi::X509_get0_subject_key_id(self.as_ptr());
583            Asn1StringRef::from_const_ptr_opt(data)
584        }
585    }
586
587    /// Returns this certificate's authority key id, if it exists.
588    #[corresponds(X509_get0_authority_key_id)]
589    #[must_use]
590    pub fn authority_key_id(&self) -> Option<&Asn1StringRef> {
591        unsafe {
592            let data = ffi::X509_get0_authority_key_id(self.as_ptr());
593            Asn1StringRef::from_const_ptr_opt(data)
594        }
595    }
596
597    #[corresponds(X509_get_pubkey)]
598    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
599        unsafe {
600            let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
601            Ok(PKey::from_ptr(pkey))
602        }
603    }
604
605    /// Returns a digest of the DER representation of the certificate.
606    #[corresponds(X509_digest)]
607    pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
608        unsafe {
609            let mut digest = DigestBytes {
610                buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
611                len: ffi::EVP_MAX_MD_SIZE as usize,
612            };
613            let mut len = try_int(ffi::EVP_MAX_MD_SIZE)?;
614            cvt(ffi::X509_digest(
615                self.as_ptr(),
616                hash_type.as_ptr(),
617                digest.buf.as_mut_ptr(),
618                &mut len,
619            ))?;
620            digest.len = try_int(len)?;
621
622            Ok(digest)
623        }
624    }
625
626    #[deprecated(since = "0.10.9", note = "renamed to digest")]
627    pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
628        self.digest(hash_type).map(|b| b.to_vec())
629    }
630
631    /// Returns the certificate's Not After validity period.
632    #[corresponds(X509_getm_notAfter)]
633    #[must_use]
634    pub fn not_after(&self) -> &Asn1TimeRef {
635        unsafe {
636            let date = X509_getm_notAfter(self.as_ptr());
637            assert!(!date.is_null());
638            Asn1TimeRef::from_ptr(date)
639        }
640    }
641
642    /// Returns the certificate's Not Before validity period.
643    #[corresponds(X509_getm_notBefore)]
644    #[must_use]
645    pub fn not_before(&self) -> &Asn1TimeRef {
646        unsafe {
647            let date = X509_getm_notBefore(self.as_ptr());
648            assert!(!date.is_null());
649            Asn1TimeRef::from_ptr(date)
650        }
651    }
652
653    /// Returns the certificate's signature
654    #[corresponds(X509_get0_signature)]
655    #[must_use]
656    pub fn signature(&self) -> &Asn1BitStringRef {
657        unsafe {
658            let mut signature = ptr::null();
659            X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
660            assert!(!signature.is_null());
661            Asn1BitStringRef::from_ptr(signature.cast_mut())
662        }
663    }
664
665    /// Returns the certificate's signature algorithm.
666    #[corresponds(X509_get0_signature)]
667    #[must_use]
668    pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
669        unsafe {
670            let mut algor = ptr::null();
671            X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
672            assert!(!algor.is_null());
673            X509AlgorithmRef::from_ptr(algor.cast_mut())
674        }
675    }
676
677    /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
678    /// Access field.
679    #[corresponds(X509_get1_ocsp)]
680    pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
681        unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
682    }
683
684    /// Checks that this certificate issued `subject`.
685    #[corresponds(X509_check_issued)]
686    pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
687        unsafe {
688            let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
689            X509VerifyError::from_raw(r)
690        }
691    }
692
693    /// Check if the certificate is signed using the given public key.
694    ///
695    /// Only the signature is checked: no other checks (such as certificate chain validity)
696    /// are performed.
697    ///
698    /// Returns `true` if verification succeeds.
699    #[corresponds(X509_verify)]
700    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
701    where
702        T: HasPublic,
703    {
704        unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
705    }
706
707    /// Returns this certificate's serial number.
708    #[corresponds(X509_get_serialNumber)]
709    #[must_use]
710    pub fn serial_number(&self) -> &Asn1IntegerRef {
711        unsafe {
712            let r = ffi::X509_get_serialNumber(self.as_ptr());
713            assert!(!r.is_null());
714            Asn1IntegerRef::from_ptr(r)
715        }
716    }
717
718    pub fn check_host(&self, host: &str) -> Result<bool, ErrorStack> {
719        unsafe {
720            cvt_n(ffi::X509_check_host(
721                self.as_ptr(),
722                host.as_ptr().cast(),
723                host.len(),
724                0,
725                std::ptr::null_mut(),
726            ))
727            .map(|n| n == 1)
728        }
729    }
730
731    #[corresponds(X509_check_ip_asc)]
732    pub fn check_ip_asc(&self, address: &str) -> Result<bool, ErrorStack> {
733        let c_str = CString::new(address).map_err(ErrorStack::internal_error)?;
734
735        unsafe { cvt_n(ffi::X509_check_ip_asc(self.as_ptr(), c_str.as_ptr(), 0)).map(|n| n == 1) }
736    }
737
738    to_pem! {
739        /// Serializes the certificate into a PEM-encoded X509 structure.
740        ///
741        /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
742        #[corresponds(PEM_write_bio_X509)]
743        to_pem,
744        ffi::PEM_write_bio_X509
745    }
746
747    to_der! {
748        /// Serializes the certificate into a DER-encoded X509 structure.
749        #[corresponds(i2d_X509)]
750        to_der,
751        ffi::i2d_X509
752    }
753}
754
755impl ToOwned for X509Ref {
756    type Owned = X509;
757
758    fn to_owned(&self) -> X509 {
759        unsafe {
760            X509_up_ref(self.as_ptr());
761            X509::from_ptr(self.as_ptr())
762        }
763    }
764}
765
766impl X509 {
767    /// Returns a new builder.
768    pub fn builder() -> Result<X509Builder, ErrorStack> {
769        X509Builder::new()
770    }
771
772    from_pem! {
773        /// Deserializes a PEM-encoded X509 structure.
774        ///
775        /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
776        #[corresponds(PEM_read_bio_X509)]
777        from_pem,
778        X509,
779        ffi::PEM_read_bio_X509
780    }
781
782    from_der! {
783        /// Deserializes a DER-encoded X509 structure.
784        #[corresponds(d2i_X509)]
785        from_der,
786        X509,
787        ffi::d2i_X509,
788        crate::libc_types::c_long
789    }
790
791    /// Deserializes a list of PEM-formatted certificates.
792    #[corresponds(PEM_read_bio_X509)]
793    pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
794        unsafe {
795            ffi::init();
796            let bio = MemBioSlice::new(pem)?;
797
798            let mut certs = vec![];
799            loop {
800                let r =
801                    ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
802                if r.is_null() {
803                    let err = ffi::ERR_peek_last_error();
804
805                    if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM.0.try_into().unwrap()
806                        && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
807                    {
808                        ErrorStack::clear();
809                        break;
810                    }
811
812                    return Err(ErrorStack::get());
813                } else {
814                    certs.push(X509::from_ptr(r));
815                }
816            }
817
818            Ok(certs)
819        }
820    }
821}
822
823impl Clone for X509 {
824    fn clone(&self) -> X509 {
825        X509Ref::to_owned(self)
826    }
827}
828
829impl fmt::Debug for X509 {
830    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
831        let serial = match &self.serial_number().to_bn() {
832            Ok(bn) => match bn.to_hex_str() {
833                Ok(hex) => hex.to_string(),
834                Err(_) => "".to_string(),
835            },
836            Err(_) => "".to_string(),
837        };
838        let mut debug_struct = formatter.debug_struct("X509");
839        debug_struct.field("serial_number", &serial);
840        debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
841        debug_struct.field("issuer", &self.issuer_name());
842        debug_struct.field("subject", &self.subject_name());
843        if let Some(subject_alt_names) = &self.subject_alt_names() {
844            debug_struct.field("subject_alt_names", subject_alt_names);
845        }
846        debug_struct.field("not_before", &self.not_before());
847        debug_struct.field("not_after", &self.not_after());
848
849        if let Ok(public_key) = &self.public_key() {
850            debug_struct.field("public_key", public_key);
851        }
852        // TODO: Print extensions once they are supported on the X509 struct.
853
854        debug_struct.finish()
855    }
856}
857
858impl AsRef<X509Ref> for X509Ref {
859    fn as_ref(&self) -> &X509Ref {
860        self
861    }
862}
863
864impl Stackable for X509 {
865    type StackType = ffi::stack_st_X509;
866}
867
868/// A context object required to construct certain `X509` extension values.
869pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
870
871impl X509v3Context<'_> {
872    #[must_use]
873    pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
874        std::ptr::addr_of!(self.0).cast_mut()
875    }
876}
877
878foreign_type_and_impl_send_sync! {
879    type CType = ffi::X509_EXTENSION;
880    fn drop = ffi::X509_EXTENSION_free;
881
882    /// Permit additional fields to be added to an `X509` v3 certificate.
883    pub struct X509Extension;
884}
885
886impl Stackable for X509Extension {
887    type StackType = ffi::stack_st_X509_EXTENSION;
888}
889
890impl X509Extension {
891    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
892    /// names and their value formats.
893    ///
894    /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
895    /// provided.
896    ///
897    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
898    /// mini-language that can read arbitrary files.
899    ///
900    /// See the extension module for builder types which will construct certain common extensions.
901    pub fn new(
902        conf: Option<&ConfRef>,
903        context: Option<&X509v3Context>,
904        name: &str,
905        value: &str,
906    ) -> Result<X509Extension, ErrorStack> {
907        let name = CString::new(name).map_err(ErrorStack::internal_error)?;
908        let value = CString::new(value).map_err(ErrorStack::internal_error)?;
909        let mut ctx;
910        unsafe {
911            ffi::init();
912            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
913            let context_ptr = match context {
914                Some(c) => c.as_ptr(),
915                None => {
916                    ctx = mem::zeroed();
917
918                    ffi::X509V3_set_ctx(
919                        &mut ctx,
920                        ptr::null_mut(),
921                        ptr::null_mut(),
922                        ptr::null_mut(),
923                        ptr::null_mut(),
924                        0,
925                    );
926                    &mut ctx
927                }
928            };
929            let name = name.as_ptr().cast_mut();
930            let value = value.as_ptr().cast_mut();
931
932            cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value))
933                .map(|p| X509Extension::from_ptr(p))
934        }
935    }
936
937    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
938    /// extensions and their value formats.
939    ///
940    /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
941    /// be provided.
942    ///
943    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
944    /// mini-language that can read arbitrary files.
945    ///
946    /// See the extension module for builder types which will construct certain common extensions.
947    pub fn new_nid(
948        conf: Option<&ConfRef>,
949        context: Option<&X509v3Context>,
950        name: Nid,
951        value: &str,
952    ) -> Result<X509Extension, ErrorStack> {
953        let value = CString::new(value).map_err(ErrorStack::internal_error)?;
954        let mut ctx;
955        unsafe {
956            ffi::init();
957            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
958            let context_ptr = match context {
959                Some(c) => c.as_ptr(),
960                None => {
961                    ctx = mem::zeroed();
962
963                    ffi::X509V3_set_ctx(
964                        &mut ctx,
965                        ptr::null_mut(),
966                        ptr::null_mut(),
967                        ptr::null_mut(),
968                        ptr::null_mut(),
969                        0,
970                    );
971                    &mut ctx
972                }
973            };
974            let name = name.as_raw();
975            let value = value.as_ptr().cast_mut();
976
977            cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value))
978                .map(|p| X509Extension::from_ptr(p))
979        }
980    }
981
982    pub(crate) unsafe fn new_internal(
983        nid: Nid,
984        critical: bool,
985        value: *mut c_void,
986    ) -> Result<X509Extension, ErrorStack> {
987        ffi::init();
988        cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value))
989            .map(|p| X509Extension::from_ptr(p))
990    }
991}
992
993impl X509ExtensionRef {
994    to_der! {
995        /// Serializes the Extension to its standard DER encoding.
996        to_der,
997        ffi::i2d_X509_EXTENSION
998    }
999}
1000
1001/// A builder used to construct an `X509Name`.
1002pub struct X509NameBuilder(X509Name);
1003
1004impl X509NameBuilder {
1005    /// Creates a new builder.
1006    pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1007        unsafe {
1008            ffi::init();
1009            cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name::from_ptr(p)))
1010        }
1011    }
1012
1013    /// Add a field entry by str.
1014    #[corresponds(X509_NAME_add_entry_by_txt)]
1015    pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1016        unsafe {
1017            let field = CString::new(field).map_err(ErrorStack::internal_error)?;
1018            cvt(ffi::X509_NAME_add_entry_by_txt(
1019                self.0.as_ptr(),
1020                field.as_ptr().cast_mut(),
1021                ffi::MBSTRING_UTF8,
1022                value.as_ptr(),
1023                try_int(value.len())?,
1024                -1,
1025                0,
1026            ))
1027        }
1028    }
1029
1030    /// Add a field entry by str with a specific type.
1031    #[corresponds(X509_NAME_add_entry_by_txt)]
1032    pub fn append_entry_by_text_with_type(
1033        &mut self,
1034        field: &str,
1035        value: &str,
1036        ty: Asn1Type,
1037    ) -> Result<(), ErrorStack> {
1038        unsafe {
1039            let field = CString::new(field).map_err(ErrorStack::internal_error)?;
1040            cvt(ffi::X509_NAME_add_entry_by_txt(
1041                self.0.as_ptr(),
1042                field.as_ptr().cast_mut(),
1043                ty.as_raw(),
1044                value.as_ptr(),
1045                try_int(value.len())?,
1046                -1,
1047                0,
1048            ))
1049        }
1050    }
1051
1052    /// Add a field entry by NID.
1053    #[corresponds(X509_NAME_add_entry_by_NID)]
1054    pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1055        unsafe {
1056            cvt(ffi::X509_NAME_add_entry_by_NID(
1057                self.0.as_ptr(),
1058                field.as_raw(),
1059                ffi::MBSTRING_UTF8,
1060                value.as_ptr().cast_mut(),
1061                try_int(value.len())?,
1062                -1,
1063                0,
1064            ))
1065        }
1066    }
1067
1068    /// Add a field entry by NID with a specific type.
1069    #[corresponds(X509_NAME_add_entry_by_NID)]
1070    pub fn append_entry_by_nid_with_type(
1071        &mut self,
1072        field: Nid,
1073        value: &str,
1074        ty: Asn1Type,
1075    ) -> Result<(), ErrorStack> {
1076        unsafe {
1077            cvt(ffi::X509_NAME_add_entry_by_NID(
1078                self.0.as_ptr(),
1079                field.as_raw(),
1080                ty.as_raw(),
1081                value.as_ptr().cast_mut(),
1082                try_int(value.len())?,
1083                -1,
1084                0,
1085            ))
1086        }
1087    }
1088
1089    /// Return an `X509Name`.
1090    #[must_use]
1091    pub fn build(self) -> X509Name {
1092        // Round-trip through bytes because OpenSSL is not const correct and
1093        // names in a "modified" state compute various things lazily. This can
1094        // lead to data-races because OpenSSL doesn't have locks or anything.
1095        X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1096    }
1097}
1098
1099foreign_type_and_impl_send_sync! {
1100    type CType = ffi::X509_NAME;
1101    fn drop = ffi::X509_NAME_free;
1102
1103    /// The names of an `X509` certificate.
1104    pub struct X509Name;
1105}
1106
1107impl X509Name {
1108    /// Returns a new builder.
1109    pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1110        X509NameBuilder::new()
1111    }
1112
1113    /// Loads subject names from a file containing PEM-formatted certificates.
1114    ///
1115    /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
1116    pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1117        let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes())
1118            .map_err(ErrorStack::internal_error)?;
1119        unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1120    }
1121
1122    from_der! {
1123        /// Deserializes a DER-encoded X509 name structure.
1124        #[corresponds(d2i_X509_NAME)]
1125        from_der,
1126        X509Name,
1127        ffi::d2i_X509_NAME,
1128        crate::libc_types::c_long
1129    }
1130}
1131
1132impl Stackable for X509Name {
1133    type StackType = ffi::stack_st_X509_NAME;
1134}
1135
1136impl X509NameRef {
1137    /// Returns the name entries by the nid.
1138    #[must_use]
1139    pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1140        X509NameEntries {
1141            name: self,
1142            nid: Some(nid),
1143            loc: -1,
1144        }
1145    }
1146
1147    /// Returns an iterator over all `X509NameEntry` values
1148    #[must_use]
1149    pub fn entries(&self) -> X509NameEntries<'_> {
1150        X509NameEntries {
1151            name: self,
1152            nid: None,
1153            loc: -1,
1154        }
1155    }
1156
1157    /// Returns an owned String representing the X509 name configurable via incoming flags.
1158    ///
1159    /// This function will return `None` if the underlying string contains invalid utf-8.
1160    #[corresponds(X509_NAME_print_ex)]
1161    #[must_use]
1162    pub fn print_ex(&self, flags: i32) -> Option<String> {
1163        unsafe {
1164            let bio = MemBio::new().ok()?;
1165            ffi::X509_NAME_print_ex(bio.as_ptr(), self.as_ptr(), 0, flags as _);
1166            let buf = bio.get_buf().to_vec();
1167            let res = String::from_utf8(buf);
1168            res.ok()
1169        }
1170    }
1171
1172    to_der! {
1173        /// Serializes the certificate into a DER-encoded X509 name structure.
1174        #[corresponds(i2d_X509_NAME)]
1175        to_der,
1176        ffi::i2d_X509_NAME
1177    }
1178}
1179
1180impl fmt::Debug for X509NameRef {
1181    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1182        formatter.debug_list().entries(self.entries()).finish()
1183    }
1184}
1185
1186/// A type to destructure and examine an `X509Name`.
1187pub struct X509NameEntries<'a> {
1188    name: &'a X509NameRef,
1189    nid: Option<Nid>,
1190    loc: c_int,
1191}
1192
1193impl<'a> Iterator for X509NameEntries<'a> {
1194    type Item = &'a X509NameEntryRef;
1195
1196    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1197        unsafe {
1198            match self.nid {
1199                Some(nid) => {
1200                    // There is a `Nid` specified to search for
1201                    self.loc =
1202                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1203                    if self.loc == -1 {
1204                        return None;
1205                    }
1206                }
1207                None => {
1208                    // Iterate over all `Nid`s
1209                    self.loc += 1;
1210                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1211                        return None;
1212                    }
1213                }
1214            }
1215
1216            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1217            assert!(!entry.is_null());
1218
1219            Some(X509NameEntryRef::from_ptr(entry))
1220        }
1221    }
1222}
1223
1224foreign_type_and_impl_send_sync! {
1225    type CType = ffi::X509_NAME_ENTRY;
1226    fn drop = ffi::X509_NAME_ENTRY_free;
1227
1228    /// A name entry associated with a `X509Name`.
1229    pub struct X509NameEntry;
1230}
1231
1232impl X509NameEntryRef {
1233    /// Returns the field value of an `X509NameEntry`.
1234    #[corresponds(X509_NAME_ENTRY_get_data)]
1235    #[must_use]
1236    pub fn data(&self) -> &Asn1StringRef {
1237        unsafe {
1238            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1239            Asn1StringRef::from_ptr(data)
1240        }
1241    }
1242
1243    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1244    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1245    #[corresponds(X509_NAME_ENTRY_get_object)]
1246    #[must_use]
1247    pub fn object(&self) -> &Asn1ObjectRef {
1248        unsafe {
1249            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1250            Asn1ObjectRef::from_ptr(object)
1251        }
1252    }
1253}
1254
1255impl fmt::Debug for X509NameEntryRef {
1256    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1257        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1258    }
1259}
1260
1261/// A builder used to construct an `X509Req`.
1262pub struct X509ReqBuilder(X509Req);
1263
1264impl X509ReqBuilder {
1265    /// Returns a builder for a certificate request.
1266    #[corresponds(X509_REQ_new)]
1267    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1268        unsafe {
1269            ffi::init();
1270            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req::from_ptr(p)))
1271        }
1272    }
1273
1274    /// Set the numerical value of the version field.
1275    #[corresponds(X509_REQ_set_version)]
1276    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1277        unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())) }
1278    }
1279
1280    /// Set the issuer name.
1281    #[corresponds(X509_REQ_set_subject_name)]
1282    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1283        unsafe {
1284            cvt(ffi::X509_REQ_set_subject_name(
1285                self.0.as_ptr(),
1286                subject_name.as_ptr(),
1287            ))
1288        }
1289    }
1290
1291    /// Set the public key.
1292    #[corresponds(X509_REQ_set_pubkey)]
1293    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1294    where
1295        T: HasPublic,
1296    {
1297        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())) }
1298    }
1299
1300    /// Return an `X509v3Context`. This context object can be used to construct
1301    /// certain `X509` extensions.
1302    #[must_use]
1303    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1304        unsafe {
1305            let mut ctx = mem::zeroed();
1306
1307            ffi::X509V3_set_ctx(
1308                &mut ctx,
1309                ptr::null_mut(),
1310                ptr::null_mut(),
1311                self.0.as_ptr(),
1312                ptr::null_mut(),
1313                0,
1314            );
1315
1316            // nodb case taken care of since we zeroed ctx above
1317            if let Some(conf) = conf {
1318                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1319            }
1320
1321            X509v3Context(ctx, PhantomData)
1322        }
1323    }
1324
1325    /// Permits any number of extension fields to be added to the certificate.
1326    pub fn add_extensions(
1327        &mut self,
1328        extensions: &StackRef<X509Extension>,
1329    ) -> Result<(), ErrorStack> {
1330        unsafe {
1331            cvt(ffi::X509_REQ_add_extensions(
1332                self.0.as_ptr(),
1333                extensions.as_ptr(),
1334            ))
1335        }
1336    }
1337
1338    /// Sign the request using a private key.
1339    #[corresponds(X509_REQ_sign)]
1340    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1341    where
1342        T: HasPrivate,
1343    {
1344        unsafe {
1345            cvt(ffi::X509_REQ_sign(
1346                self.0.as_ptr(),
1347                key.as_ptr(),
1348                hash.as_ptr(),
1349            ))
1350        }
1351    }
1352
1353    /// Returns the `X509Req`.
1354    #[must_use]
1355    pub fn build(self) -> X509Req {
1356        self.0
1357    }
1358}
1359
1360foreign_type_and_impl_send_sync! {
1361    type CType = ffi::X509_REQ;
1362    fn drop = ffi::X509_REQ_free;
1363
1364    /// An `X509` certificate request.
1365    pub struct X509Req;
1366}
1367
1368impl X509Req {
1369    /// A builder for `X509Req`.
1370    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1371        X509ReqBuilder::new()
1372    }
1373
1374    from_pem! {
1375        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1376        ///
1377        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1378        #[corresponds(PEM_read_bio_X509_REQ)]
1379        from_pem,
1380        X509Req,
1381        ffi::PEM_read_bio_X509_REQ
1382    }
1383
1384    from_der! {
1385        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1386        #[corresponds(d2i_X509_REQ)]
1387        from_der,
1388        X509Req,
1389        ffi::d2i_X509_REQ,
1390        crate::libc_types::c_long
1391    }
1392}
1393
1394impl X509ReqRef {
1395    to_pem! {
1396        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1397        ///
1398        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1399        #[corresponds(PEM_write_bio_X509_REQ)]
1400        to_pem,
1401        ffi::PEM_write_bio_X509_REQ
1402    }
1403
1404    to_der! {
1405        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1406        #[corresponds(i2d_X509_REQ)]
1407        to_der,
1408        ffi::i2d_X509_REQ
1409    }
1410
1411    /// Returns the numerical value of the version field of the certificate request.
1412    #[corresponds(X509_REQ_get_version)]
1413    #[must_use]
1414    pub fn version(&self) -> i32 {
1415        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1416    }
1417
1418    /// Returns the subject name of the certificate request.
1419    #[corresponds(X509_REQ_get_subject_name)]
1420    #[must_use]
1421    pub fn subject_name(&self) -> &X509NameRef {
1422        unsafe {
1423            let name = X509_REQ_get_subject_name(self.as_ptr());
1424            assert!(!name.is_null());
1425            X509NameRef::from_ptr(name)
1426        }
1427    }
1428
1429    /// Returns the public key of the certificate request.
1430    #[corresponds(X509_REQ_get_pubkey)]
1431    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1432        unsafe {
1433            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1434            Ok(PKey::from_ptr(key))
1435        }
1436    }
1437
1438    /// Check if the certificate request is signed using the given public key.
1439    ///
1440    /// Returns `true` if verification succeeds.
1441    #[corresponds(X509_REQ_verify)]
1442    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1443    where
1444        T: HasPublic,
1445    {
1446        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1447    }
1448
1449    /// Returns the extensions of the certificate request.
1450    #[corresponds(X509_REQ_get_extensions)]
1451    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1452        unsafe {
1453            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1454            Ok(Stack::from_ptr(extensions))
1455        }
1456    }
1457}
1458
1459/// The result of peer certificate verification.
1460pub type X509VerifyResult = Result<(), X509VerifyError>;
1461
1462#[derive(Copy, Clone, PartialEq, Eq)]
1463pub struct X509VerifyError(c_int);
1464
1465impl fmt::Debug for X509VerifyError {
1466    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1467        fmt.debug_struct("X509VerifyError")
1468            .field("code", &self.0)
1469            .field("error", &self.error_string())
1470            .finish()
1471    }
1472}
1473
1474impl fmt::Display for X509VerifyError {
1475    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1476        fmt.write_str(self.error_string())
1477    }
1478}
1479
1480impl Error for X509VerifyError {}
1481
1482impl X509VerifyError {
1483    /// Creates an [`X509VerifyResult`] from a raw error number.
1484    ///
1485    /// # Safety
1486    ///
1487    /// Some methods on [`X509VerifyError`] are not thread safe if the error
1488    /// number is invalid.
1489    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1490        if err == ffi::X509_V_OK {
1491            Ok(())
1492        } else {
1493            Err(X509VerifyError(err))
1494        }
1495    }
1496
1497    /// Return the integer representation of an [`X509VerifyError`].
1498    #[allow(clippy::trivially_copy_pass_by_ref)]
1499    #[must_use]
1500    pub fn as_raw(&self) -> c_int {
1501        self.0
1502    }
1503
1504    /// Return a human readable error string from the verification error.
1505    ///
1506    /// Returns empty string if the message was not UTF-8.
1507    #[corresponds(X509_verify_cert_error_string)]
1508    #[allow(clippy::trivially_copy_pass_by_ref)]
1509    #[must_use]
1510    pub fn error_string(&self) -> &'static str {
1511        ffi::init();
1512
1513        unsafe {
1514            let s = ffi::X509_verify_cert_error_string(c_long::from(self.0));
1515            CStr::from_ptr(s).to_str().unwrap_or_default()
1516        }
1517    }
1518}
1519
1520#[allow(missing_docs)] // no need to document the constants
1521impl X509VerifyError {
1522    pub const UNSPECIFIED: Self = Self(ffi::X509_V_ERR_UNSPECIFIED);
1523    pub const UNABLE_TO_GET_ISSUER_CERT: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
1524    pub const UNABLE_TO_GET_CRL: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL);
1525    pub const UNABLE_TO_DECRYPT_CERT_SIGNATURE: Self =
1526        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
1527    pub const UNABLE_TO_DECRYPT_CRL_SIGNATURE: Self =
1528        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
1529    pub const UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Self =
1530        Self(ffi::X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
1531    pub const CERT_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CERT_SIGNATURE_FAILURE);
1532    pub const CRL_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE);
1533    pub const CERT_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CERT_NOT_YET_VALID);
1534    pub const CERT_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CERT_HAS_EXPIRED);
1535    pub const CRL_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CRL_NOT_YET_VALID);
1536    pub const CRL_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CRL_HAS_EXPIRED);
1537    pub const ERROR_IN_CERT_NOT_BEFORE_FIELD: Self =
1538        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
1539    pub const ERROR_IN_CERT_NOT_AFTER_FIELD: Self =
1540        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
1541    pub const ERROR_IN_CRL_LAST_UPDATE_FIELD: Self =
1542        Self(ffi::X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
1543    pub const ERROR_IN_CRL_NEXT_UPDATE_FIELD: Self =
1544        Self(ffi::X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
1545    pub const OUT_OF_MEM: Self = Self(ffi::X509_V_ERR_OUT_OF_MEM);
1546    pub const DEPTH_ZERO_SELF_SIGNED_CERT: Self = Self(ffi::X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
1547    pub const SELF_SIGNED_CERT_IN_CHAIN: Self = Self(ffi::X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
1548    pub const UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Self =
1549        Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
1550    pub const UNABLE_TO_VERIFY_LEAF_SIGNATURE: Self =
1551        Self(ffi::X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
1552    pub const CERT_CHAIN_TOO_LONG: Self = Self(ffi::X509_V_ERR_CERT_CHAIN_TOO_LONG);
1553    pub const CERT_REVOKED: Self = Self(ffi::X509_V_ERR_CERT_REVOKED);
1554    pub const INVALID_CA: Self = Self(ffi::X509_V_ERR_INVALID_CA);
1555    pub const PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PATH_LENGTH_EXCEEDED);
1556    pub const INVALID_PURPOSE: Self = Self(ffi::X509_V_ERR_INVALID_PURPOSE);
1557    pub const CERT_UNTRUSTED: Self = Self(ffi::X509_V_ERR_CERT_UNTRUSTED);
1558    pub const CERT_REJECTED: Self = Self(ffi::X509_V_ERR_CERT_REJECTED);
1559    pub const SUBJECT_ISSUER_MISMATCH: Self = Self(ffi::X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
1560    pub const AKID_SKID_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_SKID_MISMATCH);
1561    pub const AKID_ISSUER_SERIAL_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
1562    pub const KEYUSAGE_NO_CERTSIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
1563    pub const UNABLE_TO_GET_CRL_ISSUER: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
1564    pub const UNHANDLED_CRITICAL_EXTENSION: Self =
1565        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
1566    pub const KEYUSAGE_NO_CRL_SIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
1567    pub const UNHANDLED_CRITICAL_CRL_EXTENSION: Self =
1568        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
1569    pub const INVALID_NON_CA: Self = Self(ffi::X509_V_ERR_INVALID_NON_CA);
1570    pub const PROXY_PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
1571    pub const KEYUSAGE_NO_DIGITAL_SIGNATURE: Self =
1572        Self(ffi::X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
1573    pub const PROXY_CERTIFICATES_NOT_ALLOWED: Self =
1574        Self(ffi::X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
1575    pub const INVALID_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_EXTENSION);
1576    pub const INVALID_POLICY_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_POLICY_EXTENSION);
1577    pub const NO_EXPLICIT_POLICY: Self = Self(ffi::X509_V_ERR_NO_EXPLICIT_POLICY);
1578    pub const DIFFERENT_CRL_SCOPE: Self = Self(ffi::X509_V_ERR_DIFFERENT_CRL_SCOPE);
1579    pub const UNSUPPORTED_EXTENSION_FEATURE: Self =
1580        Self(ffi::X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
1581    pub const UNNESTED_RESOURCE: Self = Self(ffi::X509_V_ERR_UNNESTED_RESOURCE);
1582    pub const PERMITTED_VIOLATION: Self = Self(ffi::X509_V_ERR_PERMITTED_VIOLATION);
1583    pub const EXCLUDED_VIOLATION: Self = Self(ffi::X509_V_ERR_EXCLUDED_VIOLATION);
1584    pub const SUBTREE_MINMAX: Self = Self(ffi::X509_V_ERR_SUBTREE_MINMAX);
1585    pub const APPLICATION_VERIFICATION: Self = Self(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1586    pub const UNSUPPORTED_CONSTRAINT_TYPE: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
1587    pub const UNSUPPORTED_CONSTRAINT_SYNTAX: Self =
1588        Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
1589    pub const UNSUPPORTED_NAME_SYNTAX: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
1590    pub const CRL_PATH_VALIDATION_ERROR: Self = Self(ffi::X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
1591    pub const HOSTNAME_MISMATCH: Self = Self(ffi::X509_V_ERR_HOSTNAME_MISMATCH);
1592    pub const EMAIL_MISMATCH: Self = Self(ffi::X509_V_ERR_EMAIL_MISMATCH);
1593    pub const IP_ADDRESS_MISMATCH: Self = Self(ffi::X509_V_ERR_IP_ADDRESS_MISMATCH);
1594    pub const INVALID_CALL: Self = Self(ffi::X509_V_ERR_INVALID_CALL);
1595    pub const STORE_LOOKUP: Self = Self(ffi::X509_V_ERR_STORE_LOOKUP);
1596    pub const NAME_CONSTRAINTS_WITHOUT_SANS: Self =
1597        Self(ffi::X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS);
1598}
1599
1600foreign_type_and_impl_send_sync! {
1601    type CType = ffi::GENERAL_NAME;
1602    fn drop = ffi::GENERAL_NAME_free;
1603
1604    /// An `X509` certificate alternative names.
1605    pub struct GeneralName;
1606}
1607
1608impl GeneralName {
1609    unsafe fn new(
1610        type_: c_int,
1611        asn1_type: Asn1Type,
1612        value: &[u8],
1613    ) -> Result<GeneralName, ErrorStack> {
1614        ffi::init();
1615        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1616        (*gn.as_ptr()).type_ = type_;
1617        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
1618        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
1619
1620        (*gn.as_ptr()).d.ptr = s.cast();
1621
1622        Ok(gn)
1623    }
1624
1625    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
1626        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
1627    }
1628
1629    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
1630        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
1631    }
1632
1633    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
1634        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
1635    }
1636
1637    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
1638        match ip {
1639            IpAddr::V4(addr) => unsafe {
1640                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1641            },
1642            IpAddr::V6(addr) => unsafe {
1643                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1644            },
1645        }
1646    }
1647
1648    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
1649        unsafe {
1650            ffi::init();
1651            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
1652            (*gn).type_ = ffi::GEN_RID;
1653            (*gn).d.registeredID = oid.into_ptr();
1654
1655            Ok(GeneralName::from_ptr(gn))
1656        }
1657    }
1658}
1659
1660impl GeneralNameRef {
1661    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1662        unsafe {
1663            if (*self.as_ptr()).type_ != ffi_type {
1664                return None;
1665            }
1666
1667            let asn = Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ia5);
1668
1669            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1670            // OpenSSL checks that when loading a certificate but if not we'll
1671            // use this instead of from_utf8_unchecked just in case.
1672            asn.to_str()
1673        }
1674    }
1675
1676    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
1677    #[must_use]
1678    pub fn email(&self) -> Option<&str> {
1679        self.ia5_string(ffi::GEN_EMAIL)
1680    }
1681
1682    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
1683    #[must_use]
1684    pub fn dnsname(&self) -> Option<&str> {
1685        self.ia5_string(ffi::GEN_DNS)
1686    }
1687
1688    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
1689    #[must_use]
1690    pub fn uri(&self) -> Option<&str> {
1691        self.ia5_string(ffi::GEN_URI)
1692    }
1693
1694    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
1695    #[must_use]
1696    pub fn ipaddress(&self) -> Option<&[u8]> {
1697        unsafe {
1698            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1699                return None;
1700            }
1701
1702            Some(Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ip).as_slice())
1703        }
1704    }
1705}
1706
1707impl fmt::Debug for GeneralNameRef {
1708    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1709        if let Some(email) = self.email() {
1710            formatter.write_str(email)
1711        } else if let Some(dnsname) = self.dnsname() {
1712            formatter.write_str(dnsname)
1713        } else if let Some(uri) = self.uri() {
1714            formatter.write_str(uri)
1715        } else if let Some(ipaddress) = self.ipaddress() {
1716            let result = String::from_utf8_lossy(ipaddress);
1717            formatter.write_str(&result)
1718        } else {
1719            formatter.write_str("(empty)")
1720        }
1721    }
1722}
1723
1724impl Stackable for GeneralName {
1725    type StackType = ffi::stack_st_GENERAL_NAME;
1726}
1727
1728foreign_type_and_impl_send_sync! {
1729    type CType = ffi::X509_ALGOR;
1730    fn drop = ffi::X509_ALGOR_free;
1731
1732    /// An `X509` certificate signature algorithm.
1733    pub struct X509Algorithm;
1734}
1735
1736impl X509AlgorithmRef {
1737    /// Returns the ASN.1 OID of this algorithm.
1738    #[must_use]
1739    pub fn object(&self) -> &Asn1ObjectRef {
1740        unsafe {
1741            let mut oid = ptr::null();
1742            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1743            assert!(!oid.is_null());
1744            Asn1ObjectRef::from_ptr(oid.cast_mut())
1745        }
1746    }
1747}
1748
1749foreign_type_and_impl_send_sync! {
1750    type CType = ffi::X509_OBJECT;
1751    fn drop = X509_OBJECT_free;
1752
1753    /// An `X509` or an X509 certificate revocation list.
1754    pub struct X509Object;
1755}
1756
1757impl X509ObjectRef {
1758    #[must_use]
1759    pub fn x509(&self) -> Option<&X509Ref> {
1760        unsafe {
1761            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1762            if ptr.is_null() {
1763                None
1764            } else {
1765                Some(X509Ref::from_ptr(ptr))
1766            }
1767        }
1768    }
1769}
1770
1771impl Stackable for X509Object {
1772    type StackType = ffi::stack_st_X509_OBJECT;
1773}
1774
1775use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
1776
1777use crate::ffi::{
1778    X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, X509_STORE_CTX_get0_chain,
1779    X509_set1_notAfter, X509_set1_notBefore,
1780};
1781
1782use crate::ffi::X509_OBJECT_get0_X509;
1783
1784#[allow(bad_style)]
1785unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1786    ffi::X509_OBJECT_free_contents(x);
1787    ffi::OPENSSL_free(x.cast());
1788}
1789
1790unsafe fn get_new_x509_store_ctx_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1791    ffi::X509_STORE_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
1792}