Skip to main content

boring/x509/
mod.rs

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