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