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.as_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        cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value))
990            .map(|p| X509Extension::from_ptr(p))
991    }
992}
993
994impl X509ExtensionRef {
995    to_der! {
996        /// Serializes the Extension to its standard DER encoding.
997        to_der,
998        ffi::i2d_X509_EXTENSION
999    }
1000}
1001
1002/// A builder used to construct an `X509Name`.
1003pub struct X509NameBuilder(X509Name);
1004
1005impl X509NameBuilder {
1006    /// Creates a new builder.
1007    pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1008        unsafe {
1009            ffi::init();
1010            cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name::from_ptr(p)))
1011        }
1012    }
1013
1014    /// Add a field entry by str.
1015    #[corresponds(X509_NAME_add_entry_by_txt)]
1016    pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1017        unsafe {
1018            let field = CString::new(field).map_err(ErrorStack::internal_error)?;
1019            cvt(ffi::X509_NAME_add_entry_by_txt(
1020                self.0.as_ptr(),
1021                field.as_ptr().cast_mut(),
1022                ffi::MBSTRING_UTF8,
1023                value.as_ptr(),
1024                try_int(value.len())?,
1025                -1,
1026                0,
1027            ))
1028        }
1029    }
1030
1031    /// Add a field entry by str with a specific type.
1032    #[corresponds(X509_NAME_add_entry_by_txt)]
1033    pub fn append_entry_by_text_with_type(
1034        &mut self,
1035        field: &str,
1036        value: &str,
1037        ty: Asn1Type,
1038    ) -> Result<(), ErrorStack> {
1039        unsafe {
1040            let field = CString::new(field).map_err(ErrorStack::internal_error)?;
1041            cvt(ffi::X509_NAME_add_entry_by_txt(
1042                self.0.as_ptr(),
1043                field.as_ptr().cast_mut(),
1044                ty.as_raw(),
1045                value.as_ptr(),
1046                try_int(value.len())?,
1047                -1,
1048                0,
1049            ))
1050        }
1051    }
1052
1053    /// Add a field entry by NID.
1054    #[corresponds(X509_NAME_add_entry_by_NID)]
1055    pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1056        unsafe {
1057            cvt(ffi::X509_NAME_add_entry_by_NID(
1058                self.0.as_ptr(),
1059                field.as_raw(),
1060                ffi::MBSTRING_UTF8,
1061                value.as_ptr().cast_mut(),
1062                try_int(value.len())?,
1063                -1,
1064                0,
1065            ))
1066        }
1067    }
1068
1069    /// Add a field entry by NID with a specific type.
1070    #[corresponds(X509_NAME_add_entry_by_NID)]
1071    pub fn append_entry_by_nid_with_type(
1072        &mut self,
1073        field: Nid,
1074        value: &str,
1075        ty: Asn1Type,
1076    ) -> Result<(), ErrorStack> {
1077        unsafe {
1078            cvt(ffi::X509_NAME_add_entry_by_NID(
1079                self.0.as_ptr(),
1080                field.as_raw(),
1081                ty.as_raw(),
1082                value.as_ptr().cast_mut(),
1083                try_int(value.len())?,
1084                -1,
1085                0,
1086            ))
1087        }
1088    }
1089
1090    /// Return an `X509Name`.
1091    #[must_use]
1092    pub fn build(self) -> X509Name {
1093        // Round-trip through bytes because OpenSSL is not const correct and
1094        // names in a "modified" state compute various things lazily. This can
1095        // lead to data-races because OpenSSL doesn't have locks or anything.
1096        X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1097    }
1098}
1099
1100foreign_type_and_impl_send_sync! {
1101    type CType = ffi::X509_NAME;
1102    fn drop = ffi::X509_NAME_free;
1103
1104    /// The names of an `X509` certificate.
1105    pub struct X509Name;
1106}
1107
1108impl X509Name {
1109    /// Returns a new builder.
1110    pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1111        X509NameBuilder::new()
1112    }
1113
1114    /// Loads subject names from a file containing PEM-formatted certificates.
1115    ///
1116    /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
1117    pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1118        let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes())
1119            .map_err(ErrorStack::internal_error)?;
1120        unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1121    }
1122
1123    from_der! {
1124        /// Deserializes a DER-encoded X509 name structure.
1125        #[corresponds(d2i_X509_NAME)]
1126        from_der,
1127        X509Name,
1128        ffi::d2i_X509_NAME,
1129        ::libc::c_long
1130    }
1131}
1132
1133impl Stackable for X509Name {
1134    type StackType = ffi::stack_st_X509_NAME;
1135}
1136
1137impl X509NameRef {
1138    /// Returns the name entries by the nid.
1139    #[must_use]
1140    pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1141        X509NameEntries {
1142            name: self,
1143            nid: Some(nid),
1144            loc: -1,
1145        }
1146    }
1147
1148    /// Returns an iterator over all `X509NameEntry` values
1149    #[must_use]
1150    pub fn entries(&self) -> X509NameEntries<'_> {
1151        X509NameEntries {
1152            name: self,
1153            nid: None,
1154            loc: -1,
1155        }
1156    }
1157
1158    /// Returns an owned String representing the X509 name configurable via incoming flags.
1159    ///
1160    /// This function will return `None` if the underlying string contains invalid utf-8.
1161    #[corresponds(X509_NAME_print_ex)]
1162    #[must_use]
1163    pub fn print_ex(&self, flags: i32) -> Option<String> {
1164        unsafe {
1165            let bio = MemBio::new().ok()?;
1166            ffi::X509_NAME_print_ex(bio.as_ptr(), self.as_ptr(), 0, flags as _);
1167            let buf = bio.get_buf().to_vec();
1168            let res = String::from_utf8(buf);
1169            res.ok()
1170        }
1171    }
1172
1173    to_der! {
1174        /// Serializes the certificate into a DER-encoded X509 name structure.
1175        #[corresponds(i2d_X509_NAME)]
1176        to_der,
1177        ffi::i2d_X509_NAME
1178    }
1179}
1180
1181impl fmt::Debug for X509NameRef {
1182    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1183        formatter.debug_list().entries(self.entries()).finish()
1184    }
1185}
1186
1187/// A type to destructure and examine an `X509Name`.
1188pub struct X509NameEntries<'a> {
1189    name: &'a X509NameRef,
1190    nid: Option<Nid>,
1191    loc: c_int,
1192}
1193
1194impl<'a> Iterator for X509NameEntries<'a> {
1195    type Item = &'a X509NameEntryRef;
1196
1197    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1198        unsafe {
1199            match self.nid {
1200                Some(nid) => {
1201                    // There is a `Nid` specified to search for
1202                    self.loc =
1203                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1204                    if self.loc == -1 {
1205                        return None;
1206                    }
1207                }
1208                None => {
1209                    // Iterate over all `Nid`s
1210                    self.loc += 1;
1211                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1212                        return None;
1213                    }
1214                }
1215            }
1216
1217            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1218            assert!(!entry.is_null());
1219
1220            Some(X509NameEntryRef::from_ptr(entry))
1221        }
1222    }
1223}
1224
1225foreign_type_and_impl_send_sync! {
1226    type CType = ffi::X509_NAME_ENTRY;
1227    fn drop = ffi::X509_NAME_ENTRY_free;
1228
1229    /// A name entry associated with a `X509Name`.
1230    pub struct X509NameEntry;
1231}
1232
1233impl X509NameEntryRef {
1234    /// Returns the field value of an `X509NameEntry`.
1235    #[corresponds(X509_NAME_ENTRY_get_data)]
1236    #[must_use]
1237    pub fn data(&self) -> &Asn1StringRef {
1238        unsafe {
1239            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1240            Asn1StringRef::from_ptr(data)
1241        }
1242    }
1243
1244    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1245    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1246    #[corresponds(X509_NAME_ENTRY_get_object)]
1247    #[must_use]
1248    pub fn object(&self) -> &Asn1ObjectRef {
1249        unsafe {
1250            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1251            Asn1ObjectRef::from_ptr(object)
1252        }
1253    }
1254}
1255
1256impl fmt::Debug for X509NameEntryRef {
1257    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1258        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1259    }
1260}
1261
1262/// A builder used to construct an `X509Req`.
1263pub struct X509ReqBuilder(X509Req);
1264
1265impl X509ReqBuilder {
1266    /// Returns a builder for a certificate request.
1267    #[corresponds(X509_REQ_new)]
1268    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1269        unsafe {
1270            ffi::init();
1271            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req::from_ptr(p)))
1272        }
1273    }
1274
1275    /// Set the numerical value of the version field.
1276    #[corresponds(X509_REQ_set_version)]
1277    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1278        unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())) }
1279    }
1280
1281    /// Set the issuer name.
1282    #[corresponds(X509_REQ_set_subject_name)]
1283    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1284        unsafe {
1285            cvt(ffi::X509_REQ_set_subject_name(
1286                self.0.as_ptr(),
1287                subject_name.as_ptr(),
1288            ))
1289        }
1290    }
1291
1292    /// Set the public key.
1293    #[corresponds(X509_REQ_set_pubkey)]
1294    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1295    where
1296        T: HasPublic,
1297    {
1298        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())) }
1299    }
1300
1301    /// Return an `X509v3Context`. This context object can be used to construct
1302    /// certain `X509` extensions.
1303    #[must_use]
1304    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1305        unsafe {
1306            let mut ctx = mem::zeroed();
1307
1308            ffi::X509V3_set_ctx(
1309                &mut ctx,
1310                ptr::null_mut(),
1311                ptr::null_mut(),
1312                self.0.as_ptr(),
1313                ptr::null_mut(),
1314                0,
1315            );
1316
1317            // nodb case taken care of since we zeroed ctx above
1318            if let Some(conf) = conf {
1319                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1320            }
1321
1322            X509v3Context(ctx, PhantomData)
1323        }
1324    }
1325
1326    /// Permits any number of extension fields to be added to the certificate.
1327    pub fn add_extensions(
1328        &mut self,
1329        extensions: &StackRef<X509Extension>,
1330    ) -> Result<(), ErrorStack> {
1331        unsafe {
1332            cvt(ffi::X509_REQ_add_extensions(
1333                self.0.as_ptr(),
1334                extensions.as_ptr(),
1335            ))
1336        }
1337    }
1338
1339    /// Sign the request using a private key.
1340    #[corresponds(X509_REQ_sign)]
1341    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1342    where
1343        T: HasPrivate,
1344    {
1345        unsafe {
1346            cvt(ffi::X509_REQ_sign(
1347                self.0.as_ptr(),
1348                key.as_ptr(),
1349                hash.as_ptr(),
1350            ))
1351        }
1352    }
1353
1354    /// Returns the `X509Req`.
1355    #[must_use]
1356    pub fn build(self) -> X509Req {
1357        self.0
1358    }
1359}
1360
1361foreign_type_and_impl_send_sync! {
1362    type CType = ffi::X509_REQ;
1363    fn drop = ffi::X509_REQ_free;
1364
1365    /// An `X509` certificate request.
1366    pub struct X509Req;
1367}
1368
1369impl X509Req {
1370    /// A builder for `X509Req`.
1371    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1372        X509ReqBuilder::new()
1373    }
1374
1375    from_pem! {
1376        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1377        ///
1378        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1379        #[corresponds(PEM_read_bio_X509_REQ)]
1380        from_pem,
1381        X509Req,
1382        ffi::PEM_read_bio_X509_REQ
1383    }
1384
1385    from_der! {
1386        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1387        #[corresponds(d2i_X509_REQ)]
1388        from_der,
1389        X509Req,
1390        ffi::d2i_X509_REQ,
1391        ::libc::c_long
1392    }
1393}
1394
1395impl X509ReqRef {
1396    to_pem! {
1397        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1398        ///
1399        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1400        #[corresponds(PEM_write_bio_X509_REQ)]
1401        to_pem,
1402        ffi::PEM_write_bio_X509_REQ
1403    }
1404
1405    to_der! {
1406        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1407        #[corresponds(i2d_X509_REQ)]
1408        to_der,
1409        ffi::i2d_X509_REQ
1410    }
1411
1412    /// Returns the numerical value of the version field of the certificate request.
1413    #[corresponds(X509_REQ_get_version)]
1414    #[must_use]
1415    pub fn version(&self) -> i32 {
1416        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1417    }
1418
1419    /// Returns the subject name of the certificate request.
1420    #[corresponds(X509_REQ_get_subject_name)]
1421    #[must_use]
1422    pub fn subject_name(&self) -> &X509NameRef {
1423        unsafe {
1424            let name = X509_REQ_get_subject_name(self.as_ptr());
1425            assert!(!name.is_null());
1426            X509NameRef::from_ptr(name)
1427        }
1428    }
1429
1430    /// Returns the public key of the certificate request.
1431    #[corresponds(X509_REQ_get_pubkey)]
1432    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1433        unsafe {
1434            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1435            Ok(PKey::from_ptr(key))
1436        }
1437    }
1438
1439    /// Check if the certificate request is signed using the given public key.
1440    ///
1441    /// Returns `true` if verification succeeds.
1442    #[corresponds(X509_REQ_verify)]
1443    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1444    where
1445        T: HasPublic,
1446    {
1447        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1448    }
1449
1450    /// Returns the extensions of the certificate request.
1451    #[corresponds(X509_REQ_get_extensions)]
1452    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1453        unsafe {
1454            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1455            Ok(Stack::from_ptr(extensions))
1456        }
1457    }
1458}
1459
1460/// The result of peer certificate verification.
1461pub type X509VerifyResult = Result<(), X509VerifyError>;
1462
1463#[derive(Copy, Clone, PartialEq, Eq)]
1464pub struct X509VerifyError(c_int);
1465
1466impl fmt::Debug for X509VerifyError {
1467    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1468        fmt.debug_struct("X509VerifyError")
1469            .field("code", &self.0)
1470            .field("error", &self.error_string())
1471            .finish()
1472    }
1473}
1474
1475impl fmt::Display for X509VerifyError {
1476    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1477        fmt.write_str(self.error_string())
1478    }
1479}
1480
1481impl Error for X509VerifyError {}
1482
1483impl X509VerifyError {
1484    /// Creates an [`X509VerifyResult`] from a raw error number.
1485    ///
1486    /// # Safety
1487    ///
1488    /// Some methods on [`X509VerifyError`] are not thread safe if the error
1489    /// number is invalid.
1490    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1491        if err == ffi::X509_V_OK {
1492            Ok(())
1493        } else {
1494            Err(X509VerifyError(err))
1495        }
1496    }
1497
1498    /// Return the integer representation of an [`X509VerifyError`].
1499    #[allow(clippy::trivially_copy_pass_by_ref)]
1500    #[must_use]
1501    pub fn as_raw(&self) -> c_int {
1502        self.0
1503    }
1504
1505    /// Return a human readable error string from the verification error.
1506    ///
1507    /// Returns empty string if the message was not UTF-8.
1508    #[corresponds(X509_verify_cert_error_string)]
1509    #[allow(clippy::trivially_copy_pass_by_ref)]
1510    #[must_use]
1511    pub fn error_string(&self) -> &'static str {
1512        ffi::init();
1513
1514        unsafe {
1515            let s = ffi::X509_verify_cert_error_string(c_long::from(self.0));
1516            CStr::from_ptr(s).to_str().unwrap_or_default()
1517        }
1518    }
1519}
1520
1521#[allow(missing_docs)] // no need to document the constants
1522impl X509VerifyError {
1523    pub const UNSPECIFIED: Self = Self(ffi::X509_V_ERR_UNSPECIFIED);
1524    pub const UNABLE_TO_GET_ISSUER_CERT: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
1525    pub const UNABLE_TO_GET_CRL: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL);
1526    pub const UNABLE_TO_DECRYPT_CERT_SIGNATURE: Self =
1527        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
1528    pub const UNABLE_TO_DECRYPT_CRL_SIGNATURE: Self =
1529        Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
1530    pub const UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Self =
1531        Self(ffi::X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
1532    pub const CERT_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CERT_SIGNATURE_FAILURE);
1533    pub const CRL_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE);
1534    pub const CERT_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CERT_NOT_YET_VALID);
1535    pub const CERT_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CERT_HAS_EXPIRED);
1536    pub const CRL_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CRL_NOT_YET_VALID);
1537    pub const CRL_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CRL_HAS_EXPIRED);
1538    pub const ERROR_IN_CERT_NOT_BEFORE_FIELD: Self =
1539        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
1540    pub const ERROR_IN_CERT_NOT_AFTER_FIELD: Self =
1541        Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
1542    pub const ERROR_IN_CRL_LAST_UPDATE_FIELD: Self =
1543        Self(ffi::X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
1544    pub const ERROR_IN_CRL_NEXT_UPDATE_FIELD: Self =
1545        Self(ffi::X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
1546    pub const OUT_OF_MEM: Self = Self(ffi::X509_V_ERR_OUT_OF_MEM);
1547    pub const DEPTH_ZERO_SELF_SIGNED_CERT: Self = Self(ffi::X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
1548    pub const SELF_SIGNED_CERT_IN_CHAIN: Self = Self(ffi::X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
1549    pub const UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Self =
1550        Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
1551    pub const UNABLE_TO_VERIFY_LEAF_SIGNATURE: Self =
1552        Self(ffi::X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
1553    pub const CERT_CHAIN_TOO_LONG: Self = Self(ffi::X509_V_ERR_CERT_CHAIN_TOO_LONG);
1554    pub const CERT_REVOKED: Self = Self(ffi::X509_V_ERR_CERT_REVOKED);
1555    pub const INVALID_CA: Self = Self(ffi::X509_V_ERR_INVALID_CA);
1556    pub const PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PATH_LENGTH_EXCEEDED);
1557    pub const INVALID_PURPOSE: Self = Self(ffi::X509_V_ERR_INVALID_PURPOSE);
1558    pub const CERT_UNTRUSTED: Self = Self(ffi::X509_V_ERR_CERT_UNTRUSTED);
1559    pub const CERT_REJECTED: Self = Self(ffi::X509_V_ERR_CERT_REJECTED);
1560    pub const SUBJECT_ISSUER_MISMATCH: Self = Self(ffi::X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
1561    pub const AKID_SKID_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_SKID_MISMATCH);
1562    pub const AKID_ISSUER_SERIAL_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
1563    pub const KEYUSAGE_NO_CERTSIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
1564    pub const UNABLE_TO_GET_CRL_ISSUER: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
1565    pub const UNHANDLED_CRITICAL_EXTENSION: Self =
1566        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
1567    pub const KEYUSAGE_NO_CRL_SIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
1568    pub const UNHANDLED_CRITICAL_CRL_EXTENSION: Self =
1569        Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
1570    pub const INVALID_NON_CA: Self = Self(ffi::X509_V_ERR_INVALID_NON_CA);
1571    pub const PROXY_PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
1572    pub const KEYUSAGE_NO_DIGITAL_SIGNATURE: Self =
1573        Self(ffi::X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
1574    pub const PROXY_CERTIFICATES_NOT_ALLOWED: Self =
1575        Self(ffi::X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
1576    pub const INVALID_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_EXTENSION);
1577    pub const INVALID_POLICY_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_POLICY_EXTENSION);
1578    pub const NO_EXPLICIT_POLICY: Self = Self(ffi::X509_V_ERR_NO_EXPLICIT_POLICY);
1579    pub const DIFFERENT_CRL_SCOPE: Self = Self(ffi::X509_V_ERR_DIFFERENT_CRL_SCOPE);
1580    pub const UNSUPPORTED_EXTENSION_FEATURE: Self =
1581        Self(ffi::X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
1582    pub const UNNESTED_RESOURCE: Self = Self(ffi::X509_V_ERR_UNNESTED_RESOURCE);
1583    pub const PERMITTED_VIOLATION: Self = Self(ffi::X509_V_ERR_PERMITTED_VIOLATION);
1584    pub const EXCLUDED_VIOLATION: Self = Self(ffi::X509_V_ERR_EXCLUDED_VIOLATION);
1585    pub const SUBTREE_MINMAX: Self = Self(ffi::X509_V_ERR_SUBTREE_MINMAX);
1586    pub const APPLICATION_VERIFICATION: Self = Self(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1587    pub const UNSUPPORTED_CONSTRAINT_TYPE: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
1588    pub const UNSUPPORTED_CONSTRAINT_SYNTAX: Self =
1589        Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
1590    pub const UNSUPPORTED_NAME_SYNTAX: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
1591    pub const CRL_PATH_VALIDATION_ERROR: Self = Self(ffi::X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
1592    pub const HOSTNAME_MISMATCH: Self = Self(ffi::X509_V_ERR_HOSTNAME_MISMATCH);
1593    pub const EMAIL_MISMATCH: Self = Self(ffi::X509_V_ERR_EMAIL_MISMATCH);
1594    pub const IP_ADDRESS_MISMATCH: Self = Self(ffi::X509_V_ERR_IP_ADDRESS_MISMATCH);
1595    pub const INVALID_CALL: Self = Self(ffi::X509_V_ERR_INVALID_CALL);
1596    pub const STORE_LOOKUP: Self = Self(ffi::X509_V_ERR_STORE_LOOKUP);
1597    pub const NAME_CONSTRAINTS_WITHOUT_SANS: Self =
1598        Self(ffi::X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS);
1599}
1600
1601foreign_type_and_impl_send_sync! {
1602    type CType = ffi::GENERAL_NAME;
1603    fn drop = ffi::GENERAL_NAME_free;
1604
1605    /// An `X509` certificate alternative names.
1606    pub struct GeneralName;
1607}
1608
1609impl GeneralName {
1610    unsafe fn new(
1611        type_: c_int,
1612        asn1_type: Asn1Type,
1613        value: &[u8],
1614    ) -> Result<GeneralName, ErrorStack> {
1615        ffi::init();
1616        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1617        (*gn.as_ptr()).type_ = type_;
1618        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
1619        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
1620
1621        (*gn.as_ptr()).d.ptr = s.cast();
1622
1623        Ok(gn)
1624    }
1625
1626    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
1627        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
1628    }
1629
1630    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
1631        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
1632    }
1633
1634    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
1635        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
1636    }
1637
1638    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
1639        match ip {
1640            IpAddr::V4(addr) => unsafe {
1641                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1642            },
1643            IpAddr::V6(addr) => unsafe {
1644                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1645            },
1646        }
1647    }
1648
1649    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
1650        unsafe {
1651            ffi::init();
1652            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
1653            (*gn).type_ = ffi::GEN_RID;
1654            (*gn).d.registeredID = oid.into_ptr();
1655
1656            Ok(GeneralName::from_ptr(gn))
1657        }
1658    }
1659}
1660
1661impl GeneralNameRef {
1662    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1663        unsafe {
1664            if (*self.as_ptr()).type_ != ffi_type {
1665                return None;
1666            }
1667
1668            let asn = Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ia5);
1669
1670            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1671            // OpenSSL checks that when loading a certificate but if not we'll
1672            // use this instead of from_utf8_unchecked just in case.
1673            asn.to_str()
1674        }
1675    }
1676
1677    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
1678    #[must_use]
1679    pub fn email(&self) -> Option<&str> {
1680        self.ia5_string(ffi::GEN_EMAIL)
1681    }
1682
1683    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
1684    #[must_use]
1685    pub fn dnsname(&self) -> Option<&str> {
1686        self.ia5_string(ffi::GEN_DNS)
1687    }
1688
1689    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
1690    #[must_use]
1691    pub fn uri(&self) -> Option<&str> {
1692        self.ia5_string(ffi::GEN_URI)
1693    }
1694
1695    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
1696    #[must_use]
1697    pub fn ipaddress(&self) -> Option<&[u8]> {
1698        unsafe {
1699            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1700                return None;
1701            }
1702
1703            Some(Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ip).as_slice())
1704        }
1705    }
1706}
1707
1708impl fmt::Debug for GeneralNameRef {
1709    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1710        if let Some(email) = self.email() {
1711            formatter.write_str(email)
1712        } else if let Some(dnsname) = self.dnsname() {
1713            formatter.write_str(dnsname)
1714        } else if let Some(uri) = self.uri() {
1715            formatter.write_str(uri)
1716        } else if let Some(ipaddress) = self.ipaddress() {
1717            let result = String::from_utf8_lossy(ipaddress);
1718            formatter.write_str(&result)
1719        } else {
1720            formatter.write_str("(empty)")
1721        }
1722    }
1723}
1724
1725impl Stackable for GeneralName {
1726    type StackType = ffi::stack_st_GENERAL_NAME;
1727}
1728
1729foreign_type_and_impl_send_sync! {
1730    type CType = ffi::X509_ALGOR;
1731    fn drop = ffi::X509_ALGOR_free;
1732
1733    /// An `X509` certificate signature algorithm.
1734    pub struct X509Algorithm;
1735}
1736
1737impl X509AlgorithmRef {
1738    /// Returns the ASN.1 OID of this algorithm.
1739    #[must_use]
1740    pub fn object(&self) -> &Asn1ObjectRef {
1741        unsafe {
1742            let mut oid = ptr::null();
1743            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1744            assert!(!oid.is_null());
1745            Asn1ObjectRef::from_ptr(oid.cast_mut())
1746        }
1747    }
1748}
1749
1750foreign_type_and_impl_send_sync! {
1751    type CType = ffi::X509_OBJECT;
1752    fn drop = X509_OBJECT_free;
1753
1754    /// An `X509` or an X509 certificate revocation list.
1755    pub struct X509Object;
1756}
1757
1758impl X509ObjectRef {
1759    #[must_use]
1760    pub fn x509(&self) -> Option<&X509Ref> {
1761        unsafe {
1762            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1763            if ptr.is_null() {
1764                None
1765            } else {
1766                Some(X509Ref::from_ptr(ptr))
1767            }
1768        }
1769    }
1770}
1771
1772impl Stackable for X509Object {
1773    type StackType = ffi::stack_st_X509_OBJECT;
1774}
1775
1776use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
1777
1778use crate::ffi::{
1779    X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, X509_STORE_CTX_get0_chain,
1780    X509_set1_notAfter, X509_set1_notBefore,
1781};
1782
1783use crate::ffi::X509_OBJECT_get0_X509;
1784
1785#[allow(bad_style)]
1786unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1787    ffi::X509_OBJECT_free_contents(x);
1788    ffi::OPENSSL_free(x.cast());
1789}
1790
1791unsafe fn get_new_x509_store_ctx_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1792    ffi::X509_STORE_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
1793}