variant_ssl/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 cfg_if::cfg_if;
11use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
12use libc::{c_int, c_long, c_uchar, c_uint, c_void};
13use std::cmp::{self, Ordering};
14use std::convert::{TryFrom, TryInto};
15use std::error::Error;
16use std::ffi::{CStr, CString};
17use std::fmt;
18use std::marker::PhantomData;
19use std::mem;
20use std::net::IpAddr;
21use std::path::Path;
22use std::ptr;
23use std::str;
24
25use crate::asn1::{
26    Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef,
27    Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type,
28};
29use crate::bio::MemBioSlice;
30use crate::conf::ConfRef;
31use crate::error::ErrorStack;
32use crate::ex_data::Index;
33use crate::hash::{DigestBytes, MessageDigest};
34use crate::nid::Nid;
35use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
36use crate::ssl::SslRef;
37use crate::stack::{Stack, StackRef, Stackable};
38use crate::string::OpensslString;
39use crate::util::{self, ForeignTypeExt, ForeignTypeRefExt};
40use crate::{cvt, cvt_n, cvt_p, cvt_p_const};
41use openssl_macros::corresponds;
42
43pub mod verify;
44
45pub mod extension;
46pub mod store;
47
48#[cfg(test)]
49mod tests;
50
51/// A type of X509 extension.
52///
53/// # Safety
54/// The value of NID and Output must match those in OpenSSL so that
55/// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid.
56pub unsafe trait ExtensionType {
57    const NID: Nid;
58    type Output: ForeignType;
59}
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    /// A reference to an [`X509StoreContext`].
69    pub struct X509StoreContextRef;
70}
71
72impl X509StoreContext {
73    /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
74    /// context.
75    #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
76    pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
77        unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
78    }
79
80    /// Creates a new `X509StoreContext` instance.
81    #[corresponds(X509_STORE_CTX_new)]
82    pub fn new() -> Result<X509StoreContext, ErrorStack> {
83        unsafe {
84            ffi::init();
85            cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
86        }
87    }
88}
89
90impl X509StoreContextRef {
91    /// Returns application data pertaining to an `X509` store context.
92    #[corresponds(X509_STORE_CTX_get_ex_data)]
93    pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
94        unsafe {
95            let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
96            if data.is_null() {
97                None
98            } else {
99                Some(&*(data as *const T))
100            }
101        }
102    }
103
104    /// Returns the error code of the context.
105    #[corresponds(X509_STORE_CTX_get_error)]
106    pub fn error(&self) -> X509VerifyResult {
107        unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
108    }
109
110    /// Initializes this context with the given certificate, certificates chain and certificate
111    /// store. After initializing the context, the `with_context` closure is called with the prepared
112    /// context. As long as the closure is running, the context stays initialized and can be used
113    /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
114    ///
115    /// * `trust` - The certificate store with the trusted certificates.
116    /// * `cert` - The certificate that should be verified.
117    /// * `cert_chain` - The certificates chain.
118    /// * `with_context` - The closure that is called with the initialized context.
119    ///
120    /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
121    /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
122    ///
123    /// [`X509_STORE_CTX_init`]:  https://docs.openssl.org/master/man3/X509_STORE_CTX_init/
124    /// [`X509_STORE_CTX_cleanup`]:  https://docs.openssl.org/master/man3/X509_STORE_CTX_cleanup/
125    pub fn init<F, T>(
126        &mut self,
127        trust: &store::X509StoreRef,
128        cert: &X509Ref,
129        cert_chain: &StackRef<X509>,
130        with_context: F,
131    ) -> Result<T, ErrorStack>
132    where
133        F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
134    {
135        struct Cleanup<'a>(&'a mut X509StoreContextRef);
136
137        impl Drop for Cleanup<'_> {
138            fn drop(&mut self) {
139                unsafe {
140                    ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
141                }
142            }
143        }
144
145        unsafe {
146            cvt(ffi::X509_STORE_CTX_init(
147                self.as_ptr(),
148                trust.as_ptr(),
149                cert.as_ptr(),
150                cert_chain.as_ptr(),
151            ))?;
152
153            let cleanup = Cleanup(self);
154            with_context(cleanup.0)
155        }
156    }
157
158    /// Verifies the stored certificate.
159    ///
160    /// Returns `true` if verification succeeds. The `error` method will return the specific
161    /// validation error if the certificate was not valid.
162    ///
163    /// This will only work inside of a call to `init`.
164    #[corresponds(X509_verify_cert)]
165    pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
166        unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
167    }
168
169    /// Set the error code of the context.
170    #[corresponds(X509_STORE_CTX_set_error)]
171    pub fn set_error(&mut self, result: X509VerifyResult) {
172        unsafe {
173            ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
174        }
175    }
176
177    /// Returns a reference to the certificate which caused the error or None if
178    /// no certificate is relevant to the error.
179    #[corresponds(X509_STORE_CTX_get_current_cert)]
180    pub fn current_cert(&self) -> Option<&X509Ref> {
181        unsafe {
182            let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
183            X509Ref::from_const_ptr_opt(ptr)
184        }
185    }
186
187    /// Returns a non-negative integer representing the depth in the certificate
188    /// chain where the error occurred. If it is zero it occurred in the end
189    /// entity certificate, one if it is the certificate which signed the end
190    /// entity certificate and so on.
191    #[corresponds(X509_STORE_CTX_get_error_depth)]
192    pub fn error_depth(&self) -> u32 {
193        unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
194    }
195
196    /// Returns a reference to a complete valid `X509` certificate chain.
197    #[corresponds(X509_STORE_CTX_get0_chain)]
198    pub fn chain(&self) -> Option<&StackRef<X509>> {
199        unsafe {
200            let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
201
202            if chain.is_null() {
203                None
204            } else {
205                Some(StackRef::from_ptr(chain))
206            }
207        }
208    }
209}
210
211/// A builder used to construct an `X509`.
212pub struct X509Builder(X509);
213
214impl X509Builder {
215    /// Creates a new builder.
216    #[corresponds(X509_new)]
217    pub fn new() -> Result<X509Builder, ErrorStack> {
218        unsafe {
219            ffi::init();
220            cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
221        }
222    }
223
224    /// Sets the notAfter constraint on the certificate.
225    #[corresponds(X509_set1_notAfter)]
226    pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
227        unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
228    }
229
230    /// Sets the notBefore constraint on the certificate.
231    #[corresponds(X509_set1_notBefore)]
232    pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
233        unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
234    }
235
236    /// Sets the version of the certificate.
237    ///
238    /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
239    /// the X.509 standard should pass `2` to this method.
240    #[corresponds(X509_set_version)]
241    #[allow(clippy::useless_conversion)]
242    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
243        unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
244    }
245
246    /// Sets the serial number of the certificate.
247    #[corresponds(X509_set_serialNumber)]
248    pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
249        unsafe {
250            cvt(ffi::X509_set_serialNumber(
251                self.0.as_ptr(),
252                serial_number.as_ptr(),
253            ))
254            .map(|_| ())
255        }
256    }
257
258    /// Sets the issuer name of the certificate.
259    #[corresponds(X509_set_issuer_name)]
260    pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
261        unsafe {
262            cvt(ffi::X509_set_issuer_name(
263                self.0.as_ptr(),
264                issuer_name.as_ptr(),
265            ))
266            .map(|_| ())
267        }
268    }
269
270    /// Sets the subject name of the certificate.
271    ///
272    /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools.
273    /// The `CN` field is used for the common name, such as a DNS name.
274    ///
275    /// ```
276    /// use openssl::x509::{X509, X509NameBuilder};
277    ///
278    /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap();
279    /// x509_name.append_entry_by_text("C", "US").unwrap();
280    /// x509_name.append_entry_by_text("ST", "CA").unwrap();
281    /// x509_name.append_entry_by_text("O", "Some organization").unwrap();
282    /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap();
283    /// let x509_name = x509_name.build();
284    ///
285    /// let mut x509 = openssl::x509::X509::builder().unwrap();
286    /// x509.set_subject_name(&x509_name).unwrap();
287    /// ```
288    #[corresponds(X509_set_subject_name)]
289    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
290        unsafe {
291            cvt(ffi::X509_set_subject_name(
292                self.0.as_ptr(),
293                subject_name.as_ptr(),
294            ))
295            .map(|_| ())
296        }
297    }
298
299    /// Sets the public key associated with the certificate.
300    #[corresponds(X509_set_pubkey)]
301    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
302    where
303        T: HasPublic,
304    {
305        unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
306    }
307
308    /// Returns a context object which is needed to create certain X509 extension values.
309    ///
310    /// Set `issuer` to `None` if the certificate will be self-signed.
311    #[corresponds(X509V3_set_ctx)]
312    pub fn x509v3_context<'a>(
313        &'a self,
314        issuer: Option<&'a X509Ref>,
315        conf: Option<&'a ConfRef>,
316    ) -> X509v3Context<'a> {
317        unsafe {
318            let mut ctx = mem::zeroed();
319
320            let issuer = match issuer {
321                Some(issuer) => issuer.as_ptr(),
322                None => self.0.as_ptr(),
323            };
324            let subject = self.0.as_ptr();
325            ffi::X509V3_set_ctx(
326                &mut ctx,
327                issuer,
328                subject,
329                ptr::null_mut(),
330                ptr::null_mut(),
331                0,
332            );
333
334            // nodb case taken care of since we zeroed ctx above
335            if let Some(conf) = conf {
336                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
337            }
338
339            X509v3Context(ctx, PhantomData)
340        }
341    }
342
343    /// Adds an X509 extension value to the certificate.
344    ///
345    /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
346    pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
347        self.append_extension2(&extension)
348    }
349
350    /// Adds an X509 extension value to the certificate.
351    #[corresponds(X509_add_ext)]
352    pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
353        unsafe {
354            cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
355            Ok(())
356        }
357    }
358
359    /// Signs the certificate with a private key.
360    #[corresponds(X509_sign)]
361    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
362    where
363        T: HasPrivate,
364    {
365        unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
366    }
367
368    /// Consumes the builder, returning the certificate.
369    pub fn build(self) -> X509 {
370        self.0
371    }
372}
373
374foreign_type_and_impl_send_sync! {
375    type CType = ffi::X509;
376    fn drop = ffi::X509_free;
377
378    /// An `X509` public key certificate.
379    pub struct X509;
380    /// Reference to `X509`.
381    pub struct X509Ref;
382}
383
384impl X509Ref {
385    /// Returns this certificate's subject name.
386    #[corresponds(X509_get_subject_name)]
387    pub fn subject_name(&self) -> &X509NameRef {
388        unsafe {
389            let name = ffi::X509_get_subject_name(self.as_ptr());
390            X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
391        }
392    }
393
394    /// Returns the hash of the certificates subject
395    #[corresponds(X509_subject_name_hash)]
396    pub fn subject_name_hash(&self) -> u32 {
397        #[allow(clippy::unnecessary_cast)]
398        unsafe {
399            ffi::X509_subject_name_hash(self.as_ptr()) as u32
400        }
401    }
402
403    /// Returns this certificate's issuer name.
404    #[corresponds(X509_get_issuer_name)]
405    pub fn issuer_name(&self) -> &X509NameRef {
406        unsafe {
407            let name = ffi::X509_get_issuer_name(self.as_ptr());
408            X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
409        }
410    }
411
412    /// Returns the hash of the certificates issuer
413    #[corresponds(X509_issuer_name_hash)]
414    pub fn issuer_name_hash(&self) -> u32 {
415        #[allow(clippy::unnecessary_cast)]
416        unsafe {
417            ffi::X509_issuer_name_hash(self.as_ptr()) as u32
418        }
419    }
420
421    /// Returns the extensions of the certificate.
422    #[corresponds(X509_get0_extensions)]
423    #[cfg(any(ossl111, libressl272, boringssl, awslc))]
424    pub fn extensions(&self) -> Option<&StackRef<X509Extension>> {
425        unsafe {
426            let extensions = ffi::X509_get0_extensions(self.as_ptr());
427            StackRef::from_const_ptr_opt(extensions)
428        }
429    }
430
431    /// Look for an extension with nid from the extensions of the certificate.
432    #[corresponds(X509_get0_ext_by_NID)]
433    #[cfg(any(ossl111, libressl282, boringssl, awslc))]
434    pub fn get_extension_location(&self, nid: Nid, lastpos: Option<i32>) -> Option<i32> {
435        let lastpos = lastpos.unwrap_or(-1);
436        unsafe {
437            let id = ffi::X509_get_ext_by_NID(self.as_ptr(), nid.as_raw(), lastpos as _);
438            if id == -1 {
439                None
440            } else {
441                Some(id)
442            }
443        }
444    }
445
446    /// Retrieves extension loc from certificate.
447    #[corresponds(X509_get_ext)]
448    #[cfg(any(ossl111, libressl282, boringssl, awslc))]
449    pub fn get_extension(&self, loc: i32) -> Result<&X509ExtensionRef, ErrorStack> {
450        unsafe {
451            let ext = cvt_p(ffi::X509_get_ext(self.as_ptr(), loc as _))?;
452            Ok(X509ExtensionRef::from_ptr(ext))
453        }
454    }
455
456    /// Returns the flag value of the key usage extension.
457    #[corresponds(X509_get_key_usage)]
458    #[cfg(any(ossl110, libressl, boringssl, awslc))]
459    pub fn key_usage(&self) -> Option<u32> {
460        let flags = unsafe { ffi::X509_get_key_usage(self.as_ptr()) };
461        if flags == u32::MAX {
462            None
463        } else {
464            Some(flags)
465        }
466    }
467
468    /// Returns this certificate's subject alternative name entries, if they exist.
469    #[corresponds(X509_get_ext_d2i)]
470    pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
471        unsafe {
472            let stack = ffi::X509_get_ext_d2i(
473                self.as_ptr(),
474                ffi::NID_subject_alt_name,
475                ptr::null_mut(),
476                ptr::null_mut(),
477            );
478            Stack::from_ptr_opt(stack as *mut _)
479        }
480    }
481
482    /// Returns this certificate's CRL distribution points, if they exist.
483    #[corresponds(X509_get_ext_d2i)]
484    pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> {
485        unsafe {
486            let stack = ffi::X509_get_ext_d2i(
487                self.as_ptr(),
488                ffi::NID_crl_distribution_points,
489                ptr::null_mut(),
490                ptr::null_mut(),
491            );
492            Stack::from_ptr_opt(stack as *mut _)
493        }
494    }
495
496    /// Returns this certificate's issuer alternative name entries, if they exist.
497    #[corresponds(X509_get_ext_d2i)]
498    pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
499        unsafe {
500            let stack = ffi::X509_get_ext_d2i(
501                self.as_ptr(),
502                ffi::NID_issuer_alt_name,
503                ptr::null_mut(),
504                ptr::null_mut(),
505            );
506            Stack::from_ptr_opt(stack as *mut _)
507        }
508    }
509
510    /// Returns this certificate's [`authority information access`] entries, if they exist.
511    ///
512    /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1
513    #[corresponds(X509_get_ext_d2i)]
514    pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
515        unsafe {
516            let stack = ffi::X509_get_ext_d2i(
517                self.as_ptr(),
518                ffi::NID_info_access,
519                ptr::null_mut(),
520                ptr::null_mut(),
521            );
522            Stack::from_ptr_opt(stack as *mut _)
523        }
524    }
525
526    /// Retrieves the path length extension from a certificate, if it exists.
527    #[corresponds(X509_get_pathlen)]
528    #[cfg(any(ossl110, boringssl, awslc))]
529    pub fn pathlen(&self) -> Option<u32> {
530        let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
531        u32::try_from(v).ok()
532    }
533
534    /// Returns this certificate's subject key id, if it exists.
535    #[corresponds(X509_get0_subject_key_id)]
536    #[cfg(any(ossl110, boringssl, awslc))]
537    pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
538        unsafe {
539            let data = ffi::X509_get0_subject_key_id(self.as_ptr());
540            Asn1OctetStringRef::from_const_ptr_opt(data)
541        }
542    }
543
544    /// Returns this certificate's authority key id, if it exists.
545    #[corresponds(X509_get0_authority_key_id)]
546    #[cfg(any(ossl110, boringssl, awslc))]
547    pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
548        unsafe {
549            let data = ffi::X509_get0_authority_key_id(self.as_ptr());
550            Asn1OctetStringRef::from_const_ptr_opt(data)
551        }
552    }
553
554    /// Returns this certificate's authority issuer name entries, if they exist.
555    #[corresponds(X509_get0_authority_issuer)]
556    #[cfg(any(ossl111d, boringssl))]
557    pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
558        unsafe {
559            let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
560            StackRef::from_const_ptr_opt(stack)
561        }
562    }
563
564    /// Returns this certificate's authority serial number, if it exists.
565    #[corresponds(X509_get0_authority_serial)]
566    #[cfg(any(ossl111d, boringssl))]
567    pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
568        unsafe {
569            let r = ffi::X509_get0_authority_serial(self.as_ptr());
570            Asn1IntegerRef::from_const_ptr_opt(r)
571        }
572    }
573
574    #[corresponds(X509_get_pubkey)]
575    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
576        unsafe {
577            let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
578            Ok(PKey::from_ptr(pkey))
579        }
580    }
581
582    #[corresponds(X509_get_X509_PUBKEY)]
583    #[cfg(any(ossl110, boringssl))]
584    pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
585        unsafe {
586            let key = cvt_p(ffi::X509_get_X509_PUBKEY(self.as_ptr()))?;
587            Ok(X509PubkeyRef::from_ptr(key))
588        }
589    }
590
591    digest! {
592        /// Returns a digest of the DER representation of the certificate.
593        ///
594        /// This corresponds to [`X509_digest`].
595        ///
596        /// [`X509_digest`]: https://docs.openssl.org/manmaster/man3/X509_digest/
597        digest,
598        ffi::X509_digest
599    }
600
601    digest! {
602        /// Returns a digest of the DER representation of the public key in the specified X509 data object.
603        ///
604        /// This corresponds to [`X509_pubkey_digest`].
605        ///
606        /// [`X509_pubkey_digest`]: https://docs.openssl.org/manmaster/man3/X509_pubkey_digest/
607        pubkey_digest,
608        ffi::X509_pubkey_digest
609    }
610
611    /// Returns the certificate's Not After validity period.
612    #[corresponds(X509_getm_notAfter)]
613    pub fn not_after(&self) -> &Asn1TimeRef {
614        unsafe {
615            let date = X509_getm_notAfter(self.as_ptr());
616            Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
617        }
618    }
619
620    /// Returns the certificate's Not Before validity period.
621    #[corresponds(X509_getm_notBefore)]
622    pub fn not_before(&self) -> &Asn1TimeRef {
623        unsafe {
624            let date = X509_getm_notBefore(self.as_ptr());
625            Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
626        }
627    }
628
629    /// Returns the certificate's signature
630    #[corresponds(X509_get0_signature)]
631    pub fn signature(&self) -> &Asn1BitStringRef {
632        unsafe {
633            let mut signature = ptr::null();
634            X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
635            Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
636        }
637    }
638
639    /// Returns the certificate's signature algorithm.
640    #[corresponds(X509_get0_signature)]
641    pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
642        unsafe {
643            let mut algor = ptr::null();
644            X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
645            X509AlgorithmRef::from_const_ptr_opt(algor)
646                .expect("signature algorithm must not be null")
647        }
648    }
649
650    /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
651    /// Access field.
652    #[corresponds(X509_get1_ocsp)]
653    pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
654        unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
655    }
656
657    /// Checks that this certificate issued `subject`.
658    #[corresponds(X509_check_issued)]
659    pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
660        unsafe {
661            let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
662            X509VerifyResult::from_raw(r)
663        }
664    }
665
666    /// Returns certificate version. If this certificate has no explicit version set, it defaults to
667    /// version 1.
668    ///
669    /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
670    #[corresponds(X509_get_version)]
671    #[cfg(any(ossl110, libressl282, boringssl, awslc))]
672    #[allow(clippy::unnecessary_cast)]
673    pub fn version(&self) -> i32 {
674        unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
675    }
676
677    /// Check if the certificate is signed using the given public key.
678    ///
679    /// Only the signature is checked: no other checks (such as certificate chain validity)
680    /// are performed.
681    ///
682    /// Returns `true` if verification succeeds.
683    #[corresponds(X509_verify)]
684    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
685    where
686        T: HasPublic,
687    {
688        unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
689    }
690
691    /// Returns this certificate's serial number.
692    #[corresponds(X509_get_serialNumber)]
693    pub fn serial_number(&self) -> &Asn1IntegerRef {
694        unsafe {
695            let r = ffi::X509_get_serialNumber(self.as_ptr());
696            Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
697        }
698    }
699
700    /// Returns this certificate's "alias". This field is populated by
701    /// OpenSSL in some situations -- specifically OpenSSL will store a
702    /// PKCS#12 `friendlyName` in this field. This is not a part of the X.509
703    /// certificate itself, OpenSSL merely attaches it to this structure in
704    /// memory.
705    #[corresponds(X509_alias_get0)]
706    pub fn alias(&self) -> Option<&[u8]> {
707        unsafe {
708            let mut len = 0;
709            let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len);
710            if ptr.is_null() {
711                None
712            } else {
713                Some(util::from_raw_parts(ptr, len as usize))
714            }
715        }
716    }
717
718    to_pem! {
719        /// Serializes the certificate into a PEM-encoded X509 structure.
720        ///
721        /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
722        #[corresponds(PEM_write_bio_X509)]
723        to_pem,
724        ffi::PEM_write_bio_X509
725    }
726
727    to_der! {
728        /// Serializes the certificate into a DER-encoded X509 structure.
729        #[corresponds(i2d_X509)]
730        to_der,
731        ffi::i2d_X509
732    }
733
734    to_pem! {
735        /// Converts the certificate to human readable text.
736        #[corresponds(X509_print)]
737        to_text,
738        ffi::X509_print
739    }
740}
741
742impl ToOwned for X509Ref {
743    type Owned = X509;
744
745    fn to_owned(&self) -> X509 {
746        unsafe {
747            X509_up_ref(self.as_ptr());
748            X509::from_ptr(self.as_ptr())
749        }
750    }
751}
752
753impl Ord for X509Ref {
754    fn cmp(&self, other: &Self) -> cmp::Ordering {
755        // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
756        // It can't fail if both pointers are valid, which we know is true.
757        let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
758        cmp.cmp(&0)
759    }
760}
761
762impl PartialOrd for X509Ref {
763    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
764        Some(self.cmp(other))
765    }
766}
767
768impl PartialOrd<X509> for X509Ref {
769    fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
770        <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
771    }
772}
773
774impl PartialEq for X509Ref {
775    fn eq(&self, other: &Self) -> bool {
776        self.cmp(other) == cmp::Ordering::Equal
777    }
778}
779
780impl PartialEq<X509> for X509Ref {
781    fn eq(&self, other: &X509) -> bool {
782        <X509Ref as PartialEq<X509Ref>>::eq(self, other)
783    }
784}
785
786impl Eq for X509Ref {}
787
788impl X509 {
789    /// Returns a new builder.
790    pub fn builder() -> Result<X509Builder, ErrorStack> {
791        X509Builder::new()
792    }
793
794    from_pem! {
795        /// Deserializes a PEM-encoded X509 structure.
796        ///
797        /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
798        #[corresponds(PEM_read_bio_X509)]
799        from_pem,
800        X509,
801        ffi::PEM_read_bio_X509
802    }
803
804    from_der! {
805        /// Deserializes a DER-encoded X509 structure.
806        #[corresponds(d2i_X509)]
807        from_der,
808        X509,
809        ffi::d2i_X509
810    }
811
812    /// Deserializes a list of PEM-formatted certificates.
813    #[corresponds(PEM_read_bio_X509)]
814    pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
815        unsafe {
816            ffi::init();
817            let bio = MemBioSlice::new(pem)?;
818
819            let mut certs = vec![];
820            loop {
821                let r =
822                    ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
823                if r.is_null() {
824                    let e = ErrorStack::get();
825
826                    if let Some(err) = e.errors().last() {
827                        if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int
828                            && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int
829                        {
830                            break;
831                        }
832                    }
833
834                    return Err(e);
835                } else {
836                    certs.push(X509(r));
837                }
838            }
839
840            Ok(certs)
841        }
842    }
843}
844
845impl Clone for X509 {
846    fn clone(&self) -> X509 {
847        X509Ref::to_owned(self)
848    }
849}
850
851impl fmt::Debug for X509 {
852    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
853        let serial = match &self.serial_number().to_bn() {
854            Ok(bn) => match bn.to_hex_str() {
855                Ok(hex) => hex.to_string(),
856                Err(_) => "".to_string(),
857            },
858            Err(_) => "".to_string(),
859        };
860        let mut debug_struct = formatter.debug_struct("X509");
861        debug_struct.field("serial_number", &serial);
862        debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
863        debug_struct.field("issuer", &self.issuer_name());
864        debug_struct.field("subject", &self.subject_name());
865        if let Some(subject_alt_names) = &self.subject_alt_names() {
866            debug_struct.field("subject_alt_names", subject_alt_names);
867        }
868        debug_struct.field("not_before", &self.not_before());
869        debug_struct.field("not_after", &self.not_after());
870
871        if let Ok(public_key) = &self.public_key() {
872            debug_struct.field("public_key", public_key);
873        };
874        // TODO: Print extensions once they are supported on the X509 struct.
875
876        debug_struct.finish()
877    }
878}
879
880impl AsRef<X509Ref> for X509Ref {
881    fn as_ref(&self) -> &X509Ref {
882        self
883    }
884}
885
886impl Stackable for X509 {
887    type StackType = ffi::stack_st_X509;
888}
889
890impl Ord for X509 {
891    fn cmp(&self, other: &Self) -> cmp::Ordering {
892        X509Ref::cmp(self, other)
893    }
894}
895
896impl PartialOrd for X509 {
897    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
898        Some(self.cmp(other))
899    }
900}
901
902impl PartialOrd<X509Ref> for X509 {
903    fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
904        X509Ref::partial_cmp(self, other)
905    }
906}
907
908impl PartialEq for X509 {
909    fn eq(&self, other: &Self) -> bool {
910        X509Ref::eq(self, other)
911    }
912}
913
914impl PartialEq<X509Ref> for X509 {
915    fn eq(&self, other: &X509Ref) -> bool {
916        X509Ref::eq(self, other)
917    }
918}
919
920impl Eq for X509 {}
921
922/// A context object required to construct certain `X509` extension values.
923pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
924
925impl X509v3Context<'_> {
926    pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
927        &self.0 as *const _ as *mut _
928    }
929}
930
931foreign_type_and_impl_send_sync! {
932    type CType = ffi::X509_EXTENSION;
933    fn drop = ffi::X509_EXTENSION_free;
934
935    /// Permit additional fields to be added to an `X509` v3 certificate.
936    pub struct X509Extension;
937    /// Reference to `X509Extension`.
938    pub struct X509ExtensionRef;
939}
940
941impl Stackable for X509Extension {
942    type StackType = ffi::stack_st_X509_EXTENSION;
943}
944
945impl X509Extension {
946    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
947    /// names and their value formats.
948    ///
949    /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
950    /// provided.
951    ///
952    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
953    /// mini-language that can read arbitrary files.
954    ///
955    /// See the extension module for builder types which will construct certain common extensions.
956    ///
957    /// This function is deprecated, `X509Extension::new_from_der` or the
958    /// types in `x509::extension` should be used in its place.
959    #[deprecated(
960        note = "Use x509::extension types or new_from_der instead",
961        since = "0.10.51"
962    )]
963    pub fn new(
964        conf: Option<&ConfRef>,
965        context: Option<&X509v3Context<'_>>,
966        name: &str,
967        value: &str,
968    ) -> Result<X509Extension, ErrorStack> {
969        let name = CString::new(name).unwrap();
970        let value = CString::new(value).unwrap();
971        let mut ctx;
972        unsafe {
973            ffi::init();
974            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
975            let context_ptr = match context {
976                Some(c) => c.as_ptr(),
977                None => {
978                    ctx = mem::zeroed();
979
980                    ffi::X509V3_set_ctx(
981                        &mut ctx,
982                        ptr::null_mut(),
983                        ptr::null_mut(),
984                        ptr::null_mut(),
985                        ptr::null_mut(),
986                        0,
987                    );
988                    &mut ctx
989                }
990            };
991            let name = name.as_ptr() as *mut _;
992            let value = value.as_ptr() as *mut _;
993
994            cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
995        }
996    }
997
998    /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
999    /// extensions and their value formats.
1000    ///
1001    /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
1002    /// be provided.
1003    ///
1004    /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
1005    /// mini-language that can read arbitrary files.
1006    ///
1007    /// See the extension module for builder types which will construct certain common extensions.
1008    ///
1009    /// This function is deprecated, `X509Extension::new_from_der` or the
1010    /// types in `x509::extension` should be used in its place.
1011    #[deprecated(
1012        note = "Use x509::extension types or new_from_der instead",
1013        since = "0.10.51"
1014    )]
1015    pub fn new_nid(
1016        conf: Option<&ConfRef>,
1017        context: Option<&X509v3Context<'_>>,
1018        name: Nid,
1019        value: &str,
1020    ) -> Result<X509Extension, ErrorStack> {
1021        let value = CString::new(value).unwrap();
1022        let mut ctx;
1023        unsafe {
1024            ffi::init();
1025            let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
1026            let context_ptr = match context {
1027                Some(c) => c.as_ptr(),
1028                None => {
1029                    ctx = mem::zeroed();
1030
1031                    ffi::X509V3_set_ctx(
1032                        &mut ctx,
1033                        ptr::null_mut(),
1034                        ptr::null_mut(),
1035                        ptr::null_mut(),
1036                        ptr::null_mut(),
1037                        0,
1038                    );
1039                    &mut ctx
1040                }
1041            };
1042            let name = name.as_raw();
1043            let value = value.as_ptr() as *mut _;
1044
1045            cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
1046        }
1047    }
1048
1049    /// Constructs a new X509 extension value from its OID, whether it's
1050    /// critical, and its DER contents.
1051    ///
1052    /// The extent structure of the DER value will vary based on the
1053    /// extension type, and can generally be found in the RFC defining the
1054    /// extension.
1055    ///
1056    /// For common extension types, there are Rust APIs provided in
1057    /// `openssl::x509::extensions` which are more ergonomic.
1058    pub fn new_from_der(
1059        oid: &Asn1ObjectRef,
1060        critical: bool,
1061        der_contents: &Asn1OctetStringRef,
1062    ) -> Result<X509Extension, ErrorStack> {
1063        unsafe {
1064            cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1065                ptr::null_mut(),
1066                oid.as_ptr(),
1067                critical as _,
1068                der_contents.as_ptr(),
1069            ))
1070            .map(X509Extension)
1071        }
1072    }
1073
1074    /// Construct a new SubjectAlternativeName extension
1075    pub fn new_subject_alt_name(
1076        stack: Stack<GeneralName>,
1077        critical: bool,
1078    ) -> Result<X509Extension, ErrorStack> {
1079        unsafe { Self::new_internal(Nid::SUBJECT_ALT_NAME, critical, stack.as_ptr().cast()) }
1080    }
1081
1082    pub(crate) unsafe fn new_internal(
1083        nid: Nid,
1084        critical: bool,
1085        value: *mut c_void,
1086    ) -> Result<X509Extension, ErrorStack> {
1087        ffi::init();
1088        cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1089    }
1090
1091    /// Adds an alias for an extension
1092    ///
1093    /// # Safety
1094    ///
1095    /// This method modifies global state without locking and therefore is not thread safe
1096    #[cfg(not(libressl390))]
1097    #[corresponds(X509V3_EXT_add_alias)]
1098    #[deprecated(
1099        note = "Use x509::extension types or new_from_der and then this is not necessary",
1100        since = "0.10.51"
1101    )]
1102    pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1103        ffi::init();
1104        cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1105    }
1106}
1107
1108impl X509ExtensionRef {
1109    to_der! {
1110        /// Serializes the Extension to its standard DER encoding.
1111        #[corresponds(i2d_X509_EXTENSION)]
1112        to_der,
1113        ffi::i2d_X509_EXTENSION
1114    }
1115}
1116
1117/// A builder used to construct an `X509Name`.
1118pub struct X509NameBuilder(X509Name);
1119
1120impl X509NameBuilder {
1121    /// Creates a new builder.
1122    pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1123        unsafe {
1124            ffi::init();
1125            cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1126        }
1127    }
1128
1129    /// Add a name entry
1130    #[corresponds(X509_NAME_add_entry)]
1131    pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1132        unsafe {
1133            cvt(ffi::X509_NAME_add_entry(
1134                self.0.as_ptr(),
1135                ne.as_ptr(),
1136                -1,
1137                0,
1138            ))
1139            .map(|_| ())
1140        }
1141    }
1142
1143    /// Add a field entry by str.
1144    #[corresponds(X509_NAME_add_entry_by_txt)]
1145    pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1146        unsafe {
1147            let field = CString::new(field).unwrap();
1148            assert!(value.len() <= crate::SLenType::MAX as usize);
1149            cvt(ffi::X509_NAME_add_entry_by_txt(
1150                self.0.as_ptr(),
1151                field.as_ptr() as *mut _,
1152                ffi::MBSTRING_UTF8,
1153                value.as_ptr(),
1154                value.len() as crate::SLenType,
1155                -1,
1156                0,
1157            ))
1158            .map(|_| ())
1159        }
1160    }
1161
1162    /// Add a field entry by str with a specific type.
1163    #[corresponds(X509_NAME_add_entry_by_txt)]
1164    pub fn append_entry_by_text_with_type(
1165        &mut self,
1166        field: &str,
1167        value: &str,
1168        ty: Asn1Type,
1169    ) -> Result<(), ErrorStack> {
1170        unsafe {
1171            let field = CString::new(field).unwrap();
1172            assert!(value.len() <= crate::SLenType::MAX as usize);
1173            cvt(ffi::X509_NAME_add_entry_by_txt(
1174                self.0.as_ptr(),
1175                field.as_ptr() as *mut _,
1176                ty.as_raw(),
1177                value.as_ptr(),
1178                value.len() as crate::SLenType,
1179                -1,
1180                0,
1181            ))
1182            .map(|_| ())
1183        }
1184    }
1185
1186    /// Add a field entry by NID.
1187    #[corresponds(X509_NAME_add_entry_by_NID)]
1188    pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1189        unsafe {
1190            assert!(value.len() <= crate::SLenType::MAX as usize);
1191            cvt(ffi::X509_NAME_add_entry_by_NID(
1192                self.0.as_ptr(),
1193                field.as_raw(),
1194                ffi::MBSTRING_UTF8,
1195                value.as_ptr() as *mut _,
1196                value.len() as crate::SLenType,
1197                -1,
1198                0,
1199            ))
1200            .map(|_| ())
1201        }
1202    }
1203
1204    /// Add a field entry by NID with a specific type.
1205    #[corresponds(X509_NAME_add_entry_by_NID)]
1206    pub fn append_entry_by_nid_with_type(
1207        &mut self,
1208        field: Nid,
1209        value: &str,
1210        ty: Asn1Type,
1211    ) -> Result<(), ErrorStack> {
1212        unsafe {
1213            assert!(value.len() <= crate::SLenType::MAX as usize);
1214            cvt(ffi::X509_NAME_add_entry_by_NID(
1215                self.0.as_ptr(),
1216                field.as_raw(),
1217                ty.as_raw(),
1218                value.as_ptr() as *mut _,
1219                value.len() as crate::SLenType,
1220                -1,
1221                0,
1222            ))
1223            .map(|_| ())
1224        }
1225    }
1226
1227    /// Return an `X509Name`.
1228    pub fn build(self) -> X509Name {
1229        // Round-trip through bytes because OpenSSL is not const correct and
1230        // names in a "modified" state compute various things lazily. This can
1231        // lead to data-races because OpenSSL doesn't have locks or anything.
1232        X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1233    }
1234}
1235
1236foreign_type_and_impl_send_sync! {
1237    type CType = ffi::X509_NAME;
1238    fn drop = ffi::X509_NAME_free;
1239
1240    /// The names of an `X509` certificate.
1241    pub struct X509Name;
1242    /// Reference to `X509Name`.
1243    pub struct X509NameRef;
1244}
1245
1246impl X509Name {
1247    /// Returns a new builder.
1248    pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1249        X509NameBuilder::new()
1250    }
1251
1252    /// Loads subject names from a file containing PEM-formatted certificates.
1253    ///
1254    /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
1255    pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1256        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1257        unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1258    }
1259
1260    from_der! {
1261        /// Deserializes a DER-encoded X509 name structure.
1262        ///
1263        /// This corresponds to [`d2i_X509_NAME`].
1264        ///
1265        /// [`d2i_X509_NAME`]: https://docs.openssl.org/master/man3/d2i_X509_NAME/
1266        from_der,
1267        X509Name,
1268        ffi::d2i_X509_NAME
1269    }
1270}
1271
1272impl Stackable for X509Name {
1273    type StackType = ffi::stack_st_X509_NAME;
1274}
1275
1276impl X509NameRef {
1277    /// Returns the name entries by the nid.
1278    pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1279        X509NameEntries {
1280            name: self,
1281            nid: Some(nid),
1282            loc: -1,
1283        }
1284    }
1285
1286    /// Returns an iterator over all `X509NameEntry` values
1287    pub fn entries(&self) -> X509NameEntries<'_> {
1288        X509NameEntries {
1289            name: self,
1290            nid: None,
1291            loc: -1,
1292        }
1293    }
1294
1295    /// Compare two names, like [`Ord`] but it may fail.
1296    ///
1297    /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
1298    /// call fails.
1299    /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
1300    /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
1301    #[corresponds(X509_NAME_cmp)]
1302    pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1303        let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1304        if cfg!(ossl300) && cmp == -2 {
1305            return Err(ErrorStack::get());
1306        }
1307        Ok(cmp.cmp(&0))
1308    }
1309
1310    /// Copies the name to a new `X509Name`.
1311    #[corresponds(X509_NAME_dup)]
1312    #[cfg(any(boringssl, ossl110, libressl, awslc))]
1313    pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1314        unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1315    }
1316
1317    to_der! {
1318        /// Serializes the certificate into a DER-encoded X509 name structure.
1319        ///
1320        /// This corresponds to [`i2d_X509_NAME`].
1321        ///
1322        /// [`i2d_X509_NAME`]: https://docs.openssl.org/master/man3/i2d_X509_NAME/
1323        to_der,
1324        ffi::i2d_X509_NAME
1325    }
1326
1327    digest! {
1328        /// Returns a digest of the DER representation of this 'X509Name'.
1329        ///
1330        /// This corresponds to [`X509_NAME_digest`].
1331        ///
1332        /// [`X509_NAME_digest`]: https://docs.openssl.org/manmaster/man3/X509_NAME_digest/
1333        digest,
1334        ffi::X509_NAME_digest
1335    }
1336}
1337
1338impl fmt::Debug for X509NameRef {
1339    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1340        formatter.debug_list().entries(self.entries()).finish()
1341    }
1342}
1343
1344/// A type to destructure and examine an `X509Name`.
1345pub struct X509NameEntries<'a> {
1346    name: &'a X509NameRef,
1347    nid: Option<Nid>,
1348    loc: c_int,
1349}
1350
1351impl<'a> Iterator for X509NameEntries<'a> {
1352    type Item = &'a X509NameEntryRef;
1353
1354    fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1355        unsafe {
1356            match self.nid {
1357                Some(nid) => {
1358                    // There is a `Nid` specified to search for
1359                    self.loc =
1360                        ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1361                    if self.loc == -1 {
1362                        return None;
1363                    }
1364                }
1365                None => {
1366                    // Iterate over all `Nid`s
1367                    self.loc += 1;
1368                    if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1369                        return None;
1370                    }
1371                }
1372            }
1373
1374            let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1375
1376            Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1377        }
1378    }
1379}
1380
1381foreign_type_and_impl_send_sync! {
1382    type CType = ffi::X509_NAME_ENTRY;
1383    fn drop = ffi::X509_NAME_ENTRY_free;
1384
1385    /// A name entry associated with a `X509Name`.
1386    pub struct X509NameEntry;
1387    /// Reference to `X509NameEntry`.
1388    pub struct X509NameEntryRef;
1389}
1390
1391impl X509NameEntryRef {
1392    /// Returns the field value of an `X509NameEntry`.
1393    #[corresponds(X509_NAME_ENTRY_get_data)]
1394    pub fn data(&self) -> &Asn1StringRef {
1395        unsafe {
1396            let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1397            Asn1StringRef::from_ptr(data)
1398        }
1399    }
1400
1401    /// Returns the `Asn1Object` value of an `X509NameEntry`.
1402    /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1403    #[corresponds(X509_NAME_ENTRY_get_object)]
1404    pub fn object(&self) -> &Asn1ObjectRef {
1405        unsafe {
1406            let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1407            Asn1ObjectRef::from_ptr(object)
1408        }
1409    }
1410}
1411
1412impl fmt::Debug for X509NameEntryRef {
1413    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1414        formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1415    }
1416}
1417
1418foreign_type_and_impl_send_sync! {
1419    type CType = ffi::X509_PUBKEY;
1420    fn drop = ffi::X509_PUBKEY_free;
1421
1422    /// The SubjectPublicKeyInfo of an `X509` certificate.
1423    pub struct X509Pubkey;
1424    /// Reference to `X509Pubkey`.
1425    pub struct X509PubkeyRef;
1426}
1427
1428impl X509Pubkey {
1429    from_der! {
1430        /// Deserializes a DER-encoded X509 SubjectPublicKeyInfo.
1431        ///
1432        /// This corresponds to [`d2i_X509_PUBKEY`].
1433        ///
1434        /// [`d2i_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/d2i_X509_PUBKEY/
1435        from_der,
1436        X509Pubkey,
1437        ffi::d2i_X509_PUBKEY
1438    }
1439
1440    /// Build a X509Pubkey from the public key.
1441    ///
1442    /// This corresponds to [`X509_PUBKEY_set`].
1443    ///
1444    /// [`X509_PUBKEY_set`]: https://docs.openssl.org/manmaster/crypto/X509_PUBKEY_set/
1445    pub fn from_pubkey<T>(key: &PKeyRef<T>) -> Result<Self, ErrorStack>
1446    where
1447        T: HasPublic,
1448    {
1449        let mut p = ptr::null_mut();
1450        unsafe {
1451            cvt(ffi::X509_PUBKEY_set(&mut p as *mut _, key.as_ptr()))?;
1452        }
1453        Ok(X509Pubkey(p))
1454    }
1455}
1456
1457impl X509PubkeyRef {
1458    /// Copies the X509 SubjectPublicKeyInfo to a new `X509Pubkey`.
1459    #[corresponds(X509_PUBKEY_dup)]
1460    #[cfg(ossl300)]
1461    pub fn to_owned(&self) -> Result<X509Pubkey, ErrorStack> {
1462        unsafe { cvt_p(ffi::X509_PUBKEY_dup(self.as_ptr())).map(|n| X509Pubkey::from_ptr(n)) }
1463    }
1464
1465    to_der! {
1466        /// Serializes the X509 SubjectPublicKeyInfo to DER-encoded.
1467        ///
1468        /// This corresponds to [`i2d_X509_PUBKEY`].
1469        ///
1470        /// [`i2d_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/i2d_X509_PUBKEY/
1471        to_der,
1472        ffi::i2d_X509_PUBKEY
1473    }
1474
1475    /// Returns the public key of the X509 SubjectPublicKeyInfo.
1476    ///
1477    /// This corresponds to [`X509_PUBKEY_get"]
1478    ///
1479    /// [`X509_PUBKEY_get`]: https://docs.openssl.org/manmaster/crypto/X509_PUBKEY_get/
1480    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1481        unsafe {
1482            let key = cvt_p(ffi::X509_PUBKEY_get(self.as_ptr()))?;
1483            Ok(PKey::from_ptr(key))
1484        }
1485    }
1486
1487    /// Get the encoded bytes of the X509 SubjectPublicKeyInfo.
1488    ///
1489    /// This corresponds to ['X509_PUBKEY_get0_param']
1490    ///
1491    /// ['X509_PUBKEY_get0_param']: https://docs.openssl.org/man3.0/man3/X509_PUBKEY_get0_param/
1492    pub fn encoded_bytes(&self) -> Result<&[u8], ErrorStack> {
1493        unsafe {
1494            let mut pk = ptr::null_mut() as *const c_uchar;
1495            let mut pkt_len: c_int = 0;
1496            cvt(ffi::X509_PUBKEY_get0_param(
1497                ptr::null_mut(),
1498                &mut pk as *mut _,
1499                &mut pkt_len as *mut _,
1500                ptr::null_mut(),
1501                self.as_ptr(),
1502            ))?;
1503
1504            Ok(util::from_raw_parts(pk, pkt_len as usize))
1505        }
1506    }
1507}
1508
1509/// A builder used to construct an `X509Req`.
1510pub struct X509ReqBuilder(X509Req);
1511
1512impl X509ReqBuilder {
1513    /// Returns a builder for a certificate request.
1514    #[corresponds(X509_REQ_new)]
1515    pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1516        unsafe {
1517            ffi::init();
1518            cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1519        }
1520    }
1521
1522    /// Set the numerical value of the version field.
1523    #[corresponds(X509_REQ_set_version)]
1524    #[allow(clippy::useless_conversion)]
1525    pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1526        unsafe {
1527            cvt(ffi::X509_REQ_set_version(
1528                self.0.as_ptr(),
1529                version as c_long,
1530            ))
1531            .map(|_| ())
1532        }
1533    }
1534
1535    /// Set the issuer name.
1536    #[corresponds(X509_REQ_set_subject_name)]
1537    pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1538        unsafe {
1539            cvt(ffi::X509_REQ_set_subject_name(
1540                self.0.as_ptr(),
1541                subject_name.as_ptr(),
1542            ))
1543            .map(|_| ())
1544        }
1545    }
1546
1547    /// Set the public key.
1548    #[corresponds(X509_REQ_set_pubkey)]
1549    pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1550    where
1551        T: HasPublic,
1552    {
1553        unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1554    }
1555
1556    /// Return an `X509v3Context`. This context object can be used to construct
1557    /// certain `X509` extensions.
1558    pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1559        unsafe {
1560            let mut ctx = mem::zeroed();
1561
1562            ffi::X509V3_set_ctx(
1563                &mut ctx,
1564                ptr::null_mut(),
1565                ptr::null_mut(),
1566                self.0.as_ptr(),
1567                ptr::null_mut(),
1568                0,
1569            );
1570
1571            // nodb case taken care of since we zeroed ctx above
1572            if let Some(conf) = conf {
1573                ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1574            }
1575
1576            X509v3Context(ctx, PhantomData)
1577        }
1578    }
1579
1580    /// Permits any number of extension fields to be added to the certificate.
1581    pub fn add_extensions(
1582        &mut self,
1583        extensions: &StackRef<X509Extension>,
1584    ) -> Result<(), ErrorStack> {
1585        unsafe {
1586            cvt(ffi::X509_REQ_add_extensions(
1587                self.0.as_ptr(),
1588                extensions.as_ptr(),
1589            ))
1590            .map(|_| ())
1591        }
1592    }
1593
1594    /// Sign the request using a private key.
1595    #[corresponds(X509_REQ_sign)]
1596    pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1597    where
1598        T: HasPrivate,
1599    {
1600        unsafe {
1601            cvt(ffi::X509_REQ_sign(
1602                self.0.as_ptr(),
1603                key.as_ptr(),
1604                hash.as_ptr(),
1605            ))
1606            .map(|_| ())
1607        }
1608    }
1609
1610    /// Returns the `X509Req`.
1611    pub fn build(self) -> X509Req {
1612        self.0
1613    }
1614}
1615
1616foreign_type_and_impl_send_sync! {
1617    type CType = ffi::X509_REQ;
1618    fn drop = ffi::X509_REQ_free;
1619
1620    /// An `X509` certificate request.
1621    pub struct X509Req;
1622    /// Reference to `X509Req`.
1623    pub struct X509ReqRef;
1624}
1625
1626impl X509Req {
1627    /// A builder for `X509Req`.
1628    pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1629        X509ReqBuilder::new()
1630    }
1631
1632    from_pem! {
1633        /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1634        ///
1635        /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1636        ///
1637        /// This corresponds to [`PEM_read_bio_X509_REQ`].
1638        ///
1639        /// [`PEM_read_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_read_bio_X509_REQ/
1640        from_pem,
1641        X509Req,
1642        ffi::PEM_read_bio_X509_REQ
1643    }
1644
1645    from_der! {
1646        /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1647        ///
1648        /// This corresponds to [`d2i_X509_REQ`].
1649        ///
1650        /// [`d2i_X509_REQ`]: https://docs.openssl.org/master/man3/d2i_X509_REQ/
1651        from_der,
1652        X509Req,
1653        ffi::d2i_X509_REQ
1654    }
1655}
1656
1657impl X509ReqRef {
1658    to_pem! {
1659        /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1660        ///
1661        /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1662        ///
1663        /// This corresponds to [`PEM_write_bio_X509_REQ`].
1664        ///
1665        /// [`PEM_write_bio_X509_REQ`]: https://docs.openssl.org/master/man3/PEM_write_bio_X509_REQ/
1666        to_pem,
1667        ffi::PEM_write_bio_X509_REQ
1668    }
1669
1670    to_der! {
1671        /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1672        ///
1673        /// This corresponds to [`i2d_X509_REQ`].
1674        ///
1675        /// [`i2d_X509_REQ`]: https://docs.openssl.org/master/man3/i2d_X509_REQ/
1676        to_der,
1677        ffi::i2d_X509_REQ
1678    }
1679
1680    to_pem! {
1681        /// Converts the request to human readable text.
1682        #[corresponds(X509_Req_print)]
1683        to_text,
1684        ffi::X509_REQ_print
1685    }
1686
1687    digest! {
1688        /// Returns a digest of the DER representation of this 'X509Req'.
1689        ///
1690        /// This corresponds to [`X509_REQ_digest`].
1691        ///
1692        /// [`X509_REQ_digest`]: https://docs.openssl.org/manmaster/man3/X509_REQ_digest/
1693        digest,
1694        ffi::X509_REQ_digest
1695    }
1696
1697    /// Returns the numerical value of the version field of the certificate request.
1698    #[corresponds(X509_REQ_get_version)]
1699    #[allow(clippy::unnecessary_cast)]
1700    pub fn version(&self) -> i32 {
1701        unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1702    }
1703
1704    /// Returns the subject name of the certificate request.
1705    #[corresponds(X509_REQ_get_subject_name)]
1706    pub fn subject_name(&self) -> &X509NameRef {
1707        unsafe {
1708            let name = X509_REQ_get_subject_name(self.as_ptr());
1709            X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1710        }
1711    }
1712
1713    /// Returns the public key of the certificate request.
1714    #[corresponds(X509_REQ_get_pubkey)]
1715    pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1716        unsafe {
1717            let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1718            Ok(PKey::from_ptr(key))
1719        }
1720    }
1721
1722    /// Returns the X509Pubkey of the certificate request.
1723    ///
1724    /// This corresponds to [`X509_REQ_get_X509_PUBKEY"]
1725    ///
1726    /// [`X509_REQ_get_X509_PUBKEY`]: https://docs.openssl.org/manmaster/crypto/X509_REQ_get_X509_PUBKEY/
1727    #[cfg(ossl110)]
1728    pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
1729        unsafe {
1730            let key = cvt_p(ffi::X509_REQ_get_X509_PUBKEY(self.as_ptr()))?;
1731            Ok(X509PubkeyRef::from_ptr(key))
1732        }
1733    }
1734
1735    /// Check if the certificate request is signed using the given public key.
1736    ///
1737    /// Returns `true` if verification succeeds.
1738    #[corresponds(X509_REQ_verify)]
1739    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1740    where
1741        T: HasPublic,
1742    {
1743        unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1744    }
1745
1746    /// Returns the extensions of the certificate request.
1747    #[corresponds(X509_REQ_get_extensions)]
1748    pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1749        unsafe {
1750            let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1751            Ok(Stack::from_ptr(extensions))
1752        }
1753    }
1754}
1755
1756/// The reason that a certificate was revoked.
1757#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1758pub struct CrlReason(c_int);
1759
1760#[allow(missing_docs)] // no need to document the constants
1761impl CrlReason {
1762    pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1763    pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1764    pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1765    pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1766    pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1767    pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1768    pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1769    pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1770    pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1771    pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1772
1773    /// Constructs an `CrlReason` from a raw OpenSSL value.
1774    pub const fn from_raw(value: c_int) -> Self {
1775        CrlReason(value)
1776    }
1777
1778    /// Returns the raw OpenSSL value represented by this type.
1779    pub const fn as_raw(&self) -> c_int {
1780        self.0
1781    }
1782}
1783
1784foreign_type_and_impl_send_sync! {
1785    type CType = ffi::X509_REVOKED;
1786    fn drop = ffi::X509_REVOKED_free;
1787
1788    /// An `X509` certificate revocation status.
1789    pub struct X509Revoked;
1790    /// Reference to `X509Revoked`.
1791    pub struct X509RevokedRef;
1792}
1793
1794impl Stackable for X509Revoked {
1795    type StackType = ffi::stack_st_X509_REVOKED;
1796}
1797
1798impl X509Revoked {
1799    from_der! {
1800        /// Deserializes a DER-encoded certificate revocation status
1801        #[corresponds(d2i_X509_REVOKED)]
1802        from_der,
1803        X509Revoked,
1804        ffi::d2i_X509_REVOKED
1805    }
1806}
1807
1808impl X509RevokedRef {
1809    to_der! {
1810        /// Serializes the certificate request to a DER-encoded certificate revocation status
1811        #[corresponds(d2i_X509_REVOKED)]
1812        to_der,
1813        ffi::i2d_X509_REVOKED
1814    }
1815
1816    /// Copies the entry to a new `X509Revoked`.
1817    #[corresponds(X509_NAME_dup)]
1818    #[cfg(any(boringssl, ossl110, libressl, awslc))]
1819    pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1820        unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1821    }
1822
1823    /// Get the date that the certificate was revoked
1824    #[corresponds(X509_REVOKED_get0_revocationDate)]
1825    pub fn revocation_date(&self) -> &Asn1TimeRef {
1826        unsafe {
1827            let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1828            assert!(!r.is_null());
1829            Asn1TimeRef::from_ptr(r as *mut _)
1830        }
1831    }
1832
1833    /// Get the serial number of the revoked certificate
1834    #[corresponds(X509_REVOKED_get0_serialNumber)]
1835    pub fn serial_number(&self) -> &Asn1IntegerRef {
1836        unsafe {
1837            let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1838            assert!(!r.is_null());
1839            Asn1IntegerRef::from_ptr(r as *mut _)
1840        }
1841    }
1842
1843    /// Get the criticality and value of an extension.
1844    ///
1845    /// This returns None if the extension is not present or occurs multiple times.
1846    #[corresponds(X509_REVOKED_get_ext_d2i)]
1847    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1848        let mut critical = -1;
1849        let out = unsafe {
1850            // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
1851            let ext = ffi::X509_REVOKED_get_ext_d2i(
1852                self.as_ptr(),
1853                T::NID.as_raw(),
1854                &mut critical as *mut _,
1855                ptr::null_mut(),
1856            );
1857            // SAFETY: Extensions's contract promises that the type returned by
1858            // OpenSSL here is T::Output.
1859            T::Output::from_ptr_opt(ext as *mut _)
1860        };
1861        match (critical, out) {
1862            (0, Some(out)) => Ok(Some((false, out))),
1863            (1, Some(out)) => Ok(Some((true, out))),
1864            // -1 means the extension wasn't found, -2 means multiple were found.
1865            (-1 | -2, _) => Ok(None),
1866            // A critical value of 0 or 1 suggests success, but a null pointer
1867            // was returned so something went wrong.
1868            (0 | 1, None) => Err(ErrorStack::get()),
1869            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1870        }
1871    }
1872}
1873
1874/// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
1875/// this is as defined in RFC 5280 Section 5.3.1.
1876pub enum ReasonCode {}
1877
1878// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1879// and in OpenSSL.
1880unsafe impl ExtensionType for ReasonCode {
1881    const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1882
1883    type Output = Asn1Enumerated;
1884}
1885
1886/// The CRL entry extension identifying the issuer of a certificate used in
1887/// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
1888pub enum CertificateIssuer {}
1889
1890// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1891// and in OpenSSL.
1892unsafe impl ExtensionType for CertificateIssuer {
1893    const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1894
1895    type Output = Stack<GeneralName>;
1896}
1897
1898/// The CRL extension identifying how to access information and services for the issuer of the CRL
1899pub enum AuthorityInformationAccess {}
1900
1901// SAFETY: AuthorityInformationAccess is defined to be a stack of AccessDescription in the RFC
1902// and in OpenSSL.
1903unsafe impl ExtensionType for AuthorityInformationAccess {
1904    const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1905
1906    type Output = Stack<AccessDescription>;
1907}
1908
1909foreign_type_and_impl_send_sync! {
1910    type CType = ffi::X509_CRL;
1911    fn drop = ffi::X509_CRL_free;
1912
1913    /// An `X509` certificate revocation list.
1914    pub struct X509Crl;
1915    /// Reference to `X509Crl`.
1916    pub struct X509CrlRef;
1917}
1918
1919/// The status of a certificate in a revoction list
1920///
1921/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1922///
1923/// [`X509_CRL_get0_by_*`]: https://docs.openssl.org/master/man3/X509_CRL_get0_by_serial/
1924pub enum CrlStatus<'a> {
1925    /// The certificate is not present in the list
1926    NotRevoked,
1927    /// The certificate is in the list and is revoked
1928    Revoked(&'a X509RevokedRef),
1929    /// The certificate is in the list, but has the "removeFromCrl" status.
1930    ///
1931    /// This can occur if the certificate was revoked with the "CertificateHold"
1932    /// reason, and has since been unrevoked.
1933    RemoveFromCrl(&'a X509RevokedRef),
1934}
1935
1936impl<'a> CrlStatus<'a> {
1937    // Helper used by the X509_CRL_get0_by_* methods to convert their return
1938    // value to the status enum.
1939    // Safety note: the returned CrlStatus must not outlive the owner of the
1940    // revoked_entry pointer.
1941    unsafe fn from_ffi_status(
1942        status: c_int,
1943        revoked_entry: *mut ffi::X509_REVOKED,
1944    ) -> CrlStatus<'a> {
1945        match status {
1946            0 => CrlStatus::NotRevoked,
1947            1 => {
1948                assert!(!revoked_entry.is_null());
1949                CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1950            }
1951            2 => {
1952                assert!(!revoked_entry.is_null());
1953                CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1954            }
1955            _ => unreachable!(
1956                "{}",
1957                "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1958            ),
1959        }
1960    }
1961}
1962
1963impl X509Crl {
1964    from_pem! {
1965        /// Deserializes a PEM-encoded Certificate Revocation List
1966        ///
1967        /// The input should have a header of `-----BEGIN X509 CRL-----`.
1968        #[corresponds(PEM_read_bio_X509_CRL)]
1969        from_pem,
1970        X509Crl,
1971        ffi::PEM_read_bio_X509_CRL
1972    }
1973
1974    from_der! {
1975        /// Deserializes a DER-encoded Certificate Revocation List
1976        #[corresponds(d2i_X509_CRL)]
1977        from_der,
1978        X509Crl,
1979        ffi::d2i_X509_CRL
1980    }
1981}
1982
1983impl X509CrlRef {
1984    to_pem! {
1985        /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
1986        ///
1987        /// The output will have a header of `-----BEGIN X509 CRL-----`.
1988        #[corresponds(PEM_write_bio_X509_CRL)]
1989        to_pem,
1990        ffi::PEM_write_bio_X509_CRL
1991    }
1992
1993    to_der! {
1994        /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
1995        #[corresponds(i2d_X509_CRL)]
1996        to_der,
1997        ffi::i2d_X509_CRL
1998    }
1999
2000    digest! {
2001        /// Returns a digest of the DER representation of this 'X509Crl'.
2002        ///
2003        /// This corresponds to [`X509_CRL_digest`].
2004        ///
2005        /// [`X509_CRL_digest`]: https://docs.openssl.org/manmaster/man3/X509_CRL_digest/
2006        digest,
2007        ffi::X509_CRL_digest
2008    }
2009
2010    /// Get the stack of revocation entries
2011    pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
2012        unsafe {
2013            let revoked = X509_CRL_get_REVOKED(self.as_ptr());
2014            if revoked.is_null() {
2015                None
2016            } else {
2017                Some(StackRef::from_ptr(revoked))
2018            }
2019        }
2020    }
2021
2022    /// Returns the CRL's `lastUpdate` time.
2023    #[corresponds(X509_CRL_get0_lastUpdate)]
2024    pub fn last_update(&self) -> &Asn1TimeRef {
2025        unsafe {
2026            let date = X509_CRL_get0_lastUpdate(self.as_ptr());
2027            assert!(!date.is_null());
2028            Asn1TimeRef::from_ptr(date as *mut _)
2029        }
2030    }
2031
2032    /// Returns the CRL's `nextUpdate` time.
2033    ///
2034    /// If the `nextUpdate` field is missing, returns `None`.
2035    #[corresponds(X509_CRL_get0_nextUpdate)]
2036    pub fn next_update(&self) -> Option<&Asn1TimeRef> {
2037        unsafe {
2038            let date = X509_CRL_get0_nextUpdate(self.as_ptr());
2039            Asn1TimeRef::from_const_ptr_opt(date)
2040        }
2041    }
2042
2043    /// Get the revocation status of a certificate by its serial number
2044    #[corresponds(X509_CRL_get0_by_serial)]
2045    pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
2046        unsafe {
2047            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2048            let status =
2049                ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
2050            CrlStatus::from_ffi_status(status, ret)
2051        }
2052    }
2053
2054    /// Get the revocation status of a certificate
2055    #[corresponds(X509_CRL_get0_by_cert)]
2056    pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
2057        unsafe {
2058            let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2059            let status =
2060                ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
2061            CrlStatus::from_ffi_status(status, ret)
2062        }
2063    }
2064
2065    /// Get the issuer name from the revocation list.
2066    #[corresponds(X509_CRL_get_issuer)]
2067    pub fn issuer_name(&self) -> &X509NameRef {
2068        unsafe {
2069            let name = X509_CRL_get_issuer(self.as_ptr());
2070            assert!(!name.is_null());
2071            X509NameRef::from_ptr(name)
2072        }
2073    }
2074
2075    /// Check if the CRL is signed using the given public key.
2076    ///
2077    /// Only the signature is checked: no other checks (such as certificate chain validity)
2078    /// are performed.
2079    ///
2080    /// Returns `true` if verification succeeds.
2081    #[corresponds(X509_CRL_verify)]
2082    pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
2083    where
2084        T: HasPublic,
2085    {
2086        unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
2087    }
2088
2089    /// Get the criticality and value of an extension.
2090    ///
2091    /// This returns None if the extension is not present or occurs multiple times.
2092    #[corresponds(X509_CRL_get_ext_d2i)]
2093    pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
2094        let mut critical = -1;
2095        let out = unsafe {
2096            // SAFETY: self.as_ptr() is a valid pointer to an X509_CRL.
2097            let ext = ffi::X509_CRL_get_ext_d2i(
2098                self.as_ptr(),
2099                T::NID.as_raw(),
2100                &mut critical as *mut _,
2101                ptr::null_mut(),
2102            );
2103            // SAFETY: Extensions's contract promises that the type returned by
2104            // OpenSSL here is T::Output.
2105            T::Output::from_ptr_opt(ext as *mut _)
2106        };
2107        match (critical, out) {
2108            (0, Some(out)) => Ok(Some((false, out))),
2109            (1, Some(out)) => Ok(Some((true, out))),
2110            // -1 means the extension wasn't found, -2 means multiple were found.
2111            (-1 | -2, _) => Ok(None),
2112            // A critical value of 0 or 1 suggests success, but a null pointer
2113            // was returned so something went wrong.
2114            (0 | 1, None) => Err(ErrorStack::get()),
2115            (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
2116        }
2117    }
2118}
2119
2120/// The result of peer certificate verification.
2121#[derive(Copy, Clone, PartialEq, Eq)]
2122pub struct X509VerifyResult(c_int);
2123
2124impl fmt::Debug for X509VerifyResult {
2125    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2126        fmt.debug_struct("X509VerifyResult")
2127            .field("code", &self.0)
2128            .field("error", &self.error_string())
2129            .finish()
2130    }
2131}
2132
2133impl fmt::Display for X509VerifyResult {
2134    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2135        fmt.write_str(self.error_string())
2136    }
2137}
2138
2139impl Error for X509VerifyResult {}
2140
2141impl X509VerifyResult {
2142    /// Creates an `X509VerifyResult` from a raw error number.
2143    ///
2144    /// # Safety
2145    ///
2146    /// Some methods on `X509VerifyResult` are not thread safe if the error
2147    /// number is invalid.
2148    pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
2149        X509VerifyResult(err)
2150    }
2151
2152    /// Return the integer representation of an `X509VerifyResult`.
2153    #[allow(clippy::trivially_copy_pass_by_ref)]
2154    pub fn as_raw(&self) -> c_int {
2155        self.0
2156    }
2157
2158    /// Return a human readable error string from the verification error.
2159    #[corresponds(X509_verify_cert_error_string)]
2160    #[allow(clippy::trivially_copy_pass_by_ref)]
2161    pub fn error_string(&self) -> &'static str {
2162        ffi::init();
2163
2164        unsafe {
2165            let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
2166            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
2167        }
2168    }
2169
2170    /// Successful peer certificate verification.
2171    pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
2172    /// Application verification failure.
2173    pub const APPLICATION_VERIFICATION: X509VerifyResult =
2174        X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
2175}
2176
2177foreign_type_and_impl_send_sync! {
2178    type CType = ffi::GENERAL_NAME;
2179    fn drop = ffi::GENERAL_NAME_free;
2180
2181    /// An `X509` certificate alternative names.
2182    pub struct GeneralName;
2183    /// Reference to `GeneralName`.
2184    pub struct GeneralNameRef;
2185}
2186
2187impl GeneralName {
2188    unsafe fn new(
2189        type_: c_int,
2190        asn1_type: Asn1Type,
2191        value: &[u8],
2192    ) -> Result<GeneralName, ErrorStack> {
2193        ffi::init();
2194        let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2195        (*gn.as_ptr()).type_ = type_;
2196        let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2197        ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2198
2199        #[cfg(any(boringssl, awslc))]
2200        {
2201            (*gn.as_ptr()).d.ptr = s.cast();
2202        }
2203        #[cfg(not(any(boringssl, awslc)))]
2204        {
2205            (*gn.as_ptr()).d = s.cast();
2206        }
2207
2208        Ok(gn)
2209    }
2210
2211    pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2212        unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2213    }
2214
2215    pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2216        unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2217    }
2218
2219    pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2220        unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2221    }
2222
2223    pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2224        match ip {
2225            IpAddr::V4(addr) => unsafe {
2226                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2227            },
2228            IpAddr::V6(addr) => unsafe {
2229                GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2230            },
2231        }
2232    }
2233
2234    pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2235        unsafe {
2236            ffi::init();
2237            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2238            (*gn).type_ = ffi::GEN_RID;
2239
2240            #[cfg(any(boringssl, awslc))]
2241            {
2242                (*gn).d.registeredID = oid.as_ptr();
2243            }
2244            #[cfg(not(any(boringssl, awslc)))]
2245            {
2246                (*gn).d = oid.as_ptr().cast();
2247            }
2248
2249            mem::forget(oid);
2250
2251            Ok(GeneralName::from_ptr(gn))
2252        }
2253    }
2254
2255    pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2256        unsafe {
2257            ffi::init();
2258
2259            let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2260                ptr::null_mut(),
2261                &mut value.as_ptr().cast(),
2262                value.len().try_into().unwrap(),
2263            ))?;
2264
2265            let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2266            (*gn).type_ = ffi::GEN_OTHERNAME;
2267
2268            if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2269                gn,
2270                oid.as_ptr().cast(),
2271                typ,
2272            )) {
2273                ffi::GENERAL_NAME_free(gn);
2274                return Err(e);
2275            }
2276
2277            mem::forget(oid);
2278
2279            Ok(GeneralName::from_ptr(gn))
2280        }
2281    }
2282}
2283
2284impl GeneralNameRef {
2285    fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2286        unsafe {
2287            if (*self.as_ptr()).type_ != ffi_type {
2288                return None;
2289            }
2290
2291            #[cfg(any(boringssl, awslc))]
2292            let d = (*self.as_ptr()).d.ptr;
2293            #[cfg(not(any(boringssl, awslc)))]
2294            let d = (*self.as_ptr()).d;
2295
2296            let ptr = ASN1_STRING_get0_data(d as *mut _);
2297            let len = ffi::ASN1_STRING_length(d as *mut _);
2298
2299            #[allow(clippy::unnecessary_cast)]
2300            let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2301            // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
2302            // OpenSSL checks that when loading a certificate but if not we'll
2303            // use this instead of from_utf8_unchecked just in case.
2304            str::from_utf8(slice).ok()
2305        }
2306    }
2307
2308    /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
2309    pub fn email(&self) -> Option<&str> {
2310        self.ia5_string(ffi::GEN_EMAIL)
2311    }
2312
2313    /// Returns the contents of this `GeneralName` if it is a `directoryName`.
2314    pub fn directory_name(&self) -> Option<&X509NameRef> {
2315        unsafe {
2316            if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2317                return None;
2318            }
2319
2320            #[cfg(any(boringssl, awslc))]
2321            let d = (*self.as_ptr()).d.ptr;
2322            #[cfg(not(any(boringssl, awslc)))]
2323            let d = (*self.as_ptr()).d;
2324
2325            Some(X509NameRef::from_const_ptr(d as *const _))
2326        }
2327    }
2328
2329    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
2330    pub fn dnsname(&self) -> Option<&str> {
2331        self.ia5_string(ffi::GEN_DNS)
2332    }
2333
2334    /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
2335    pub fn uri(&self) -> Option<&str> {
2336        self.ia5_string(ffi::GEN_URI)
2337    }
2338
2339    /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
2340    pub fn ipaddress(&self) -> Option<&[u8]> {
2341        unsafe {
2342            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2343                return None;
2344            }
2345            #[cfg(any(boringssl, awslc))]
2346            let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2347            #[cfg(not(any(boringssl, awslc)))]
2348            let d = (*self.as_ptr()).d;
2349
2350            let ptr = ASN1_STRING_get0_data(d as *mut _);
2351            let len = ffi::ASN1_STRING_length(d as *mut _);
2352
2353            #[allow(clippy::unnecessary_cast)]
2354            Some(util::from_raw_parts(ptr as *const u8, len as usize))
2355        }
2356    }
2357}
2358
2359impl fmt::Debug for GeneralNameRef {
2360    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2361        if let Some(email) = self.email() {
2362            formatter.write_str(email)
2363        } else if let Some(dnsname) = self.dnsname() {
2364            formatter.write_str(dnsname)
2365        } else if let Some(uri) = self.uri() {
2366            formatter.write_str(uri)
2367        } else if let Some(ipaddress) = self.ipaddress() {
2368            let address = <[u8; 16]>::try_from(ipaddress)
2369                .map(IpAddr::from)
2370                .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2371            match address {
2372                Ok(a) => fmt::Debug::fmt(&a, formatter),
2373                Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2374            }
2375        } else {
2376            formatter.write_str("(empty)")
2377        }
2378    }
2379}
2380
2381impl Stackable for GeneralName {
2382    type StackType = ffi::stack_st_GENERAL_NAME;
2383}
2384
2385foreign_type_and_impl_send_sync! {
2386    type CType = ffi::DIST_POINT;
2387    fn drop = ffi::DIST_POINT_free;
2388
2389    /// A `X509` distribution point.
2390    pub struct DistPoint;
2391    /// Reference to `DistPoint`.
2392    pub struct DistPointRef;
2393}
2394
2395impl DistPointRef {
2396    /// Returns the name of this distribution point if it exists
2397    pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2398        unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2399    }
2400}
2401
2402foreign_type_and_impl_send_sync! {
2403    type CType = ffi::DIST_POINT_NAME;
2404    fn drop = ffi::DIST_POINT_NAME_free;
2405
2406    /// A `X509` distribution point.
2407    pub struct DistPointName;
2408    /// Reference to `DistPointName`.
2409    pub struct DistPointNameRef;
2410}
2411
2412impl DistPointNameRef {
2413    /// Returns the contents of this DistPointName if it is a fullname.
2414    pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2415        unsafe {
2416            if (*self.as_ptr()).type_ != 0 {
2417                return None;
2418            }
2419            StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2420        }
2421    }
2422}
2423
2424impl Stackable for DistPoint {
2425    type StackType = ffi::stack_st_DIST_POINT;
2426}
2427
2428foreign_type_and_impl_send_sync! {
2429    type CType = ffi::ACCESS_DESCRIPTION;
2430    fn drop = ffi::ACCESS_DESCRIPTION_free;
2431
2432    /// `AccessDescription` of certificate authority information.
2433    pub struct AccessDescription;
2434    /// Reference to `AccessDescription`.
2435    pub struct AccessDescriptionRef;
2436}
2437
2438impl AccessDescriptionRef {
2439    /// Returns the access method OID.
2440    pub fn method(&self) -> &Asn1ObjectRef {
2441        unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2442    }
2443
2444    // Returns the access location.
2445    pub fn location(&self) -> &GeneralNameRef {
2446        unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2447    }
2448}
2449
2450impl Stackable for AccessDescription {
2451    type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2452}
2453
2454foreign_type_and_impl_send_sync! {
2455    type CType = ffi::X509_ALGOR;
2456    fn drop = ffi::X509_ALGOR_free;
2457
2458    /// An `X509` certificate signature algorithm.
2459    pub struct X509Algorithm;
2460    /// Reference to `X509Algorithm`.
2461    pub struct X509AlgorithmRef;
2462}
2463
2464impl X509AlgorithmRef {
2465    /// Returns the ASN.1 OID of this algorithm.
2466    pub fn object(&self) -> &Asn1ObjectRef {
2467        unsafe {
2468            let mut oid = ptr::null();
2469            X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2470            Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2471        }
2472    }
2473}
2474
2475foreign_type_and_impl_send_sync! {
2476    type CType = ffi::X509_OBJECT;
2477    fn drop = X509_OBJECT_free;
2478
2479    /// An `X509` or an X509 certificate revocation list.
2480    pub struct X509Object;
2481    /// Reference to `X509Object`
2482    pub struct X509ObjectRef;
2483}
2484
2485impl X509ObjectRef {
2486    pub fn x509(&self) -> Option<&X509Ref> {
2487        unsafe {
2488            let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2489            X509Ref::from_const_ptr_opt(ptr)
2490        }
2491    }
2492}
2493
2494impl Stackable for X509Object {
2495    type StackType = ffi::stack_st_X509_OBJECT;
2496}
2497
2498cfg_if! {
2499    if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2500        use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2501    } else {
2502        #[allow(bad_style)]
2503        unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2504            (*(*(*x).cert_info).validity).notAfter
2505        }
2506
2507        #[allow(bad_style)]
2508        unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2509            (*(*(*x).cert_info).validity).notBefore
2510        }
2511
2512        #[allow(bad_style)]
2513        unsafe fn X509_up_ref(x: *mut ffi::X509) {
2514            ffi::CRYPTO_add_lock(
2515                &mut (*x).references,
2516                1,
2517                ffi::CRYPTO_LOCK_X509,
2518                "mod.rs\0".as_ptr() as *const _,
2519                line!() as c_int,
2520            );
2521        }
2522
2523        #[allow(bad_style)]
2524        unsafe fn X509_get0_signature(
2525            psig: *mut *const ffi::ASN1_BIT_STRING,
2526            palg: *mut *const ffi::X509_ALGOR,
2527            x: *const ffi::X509,
2528        ) {
2529            if !psig.is_null() {
2530                *psig = (*x).signature;
2531            }
2532            if !palg.is_null() {
2533                *palg = (*x).sig_alg;
2534            }
2535        }
2536    }
2537}
2538
2539cfg_if! {
2540    if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2541        use ffi::{
2542            X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2543            X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2544        };
2545    } else {
2546        use ffi::{
2547            ASN1_STRING_data as ASN1_STRING_get0_data,
2548            X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2549            X509_set_notAfter as X509_set1_notAfter,
2550            X509_set_notBefore as X509_set1_notBefore,
2551        };
2552
2553        #[allow(bad_style)]
2554        unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2555            ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2556        }
2557
2558        #[allow(bad_style)]
2559        unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2560            (*(*x).req_info).subject
2561        }
2562
2563        #[allow(bad_style)]
2564        unsafe fn X509_ALGOR_get0(
2565            paobj: *mut *const ffi::ASN1_OBJECT,
2566            pptype: *mut c_int,
2567            pval: *mut *mut ::libc::c_void,
2568            alg: *const ffi::X509_ALGOR,
2569        ) {
2570            if !paobj.is_null() {
2571                *paobj = (*alg).algorithm;
2572            }
2573            assert!(pptype.is_null());
2574            assert!(pval.is_null());
2575        }
2576    }
2577}
2578
2579cfg_if! {
2580    if #[cfg(any(ossl110, boringssl, libressl, awslc))] {
2581        use ffi::X509_OBJECT_get0_X509;
2582    } else {
2583        #[allow(bad_style)]
2584        unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2585            if (*x).type_ == ffi::X509_LU_X509 {
2586                (*x).data.x509
2587            } else {
2588                ptr::null_mut()
2589            }
2590        }
2591    }
2592}
2593
2594cfg_if! {
2595    if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2596        use ffi::X509_OBJECT_free;
2597    } else {
2598        #[allow(bad_style)]
2599        unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2600            ffi::X509_OBJECT_free_contents(x);
2601            ffi::CRYPTO_free(x as *mut libc::c_void);
2602        }
2603    }
2604}
2605
2606cfg_if! {
2607    if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2608        use ffi::{
2609            X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2610            X509_CRL_get_REVOKED,
2611            X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2612        };
2613    } else {
2614        #[allow(bad_style)]
2615        unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2616            (*(*x).crl).lastUpdate
2617        }
2618        #[allow(bad_style)]
2619        unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2620            (*(*x).crl).nextUpdate
2621        }
2622        #[allow(bad_style)]
2623        unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2624            (*(*x).crl).issuer
2625        }
2626        #[allow(bad_style)]
2627        unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2628            (*(*x).crl).revoked
2629        }
2630        #[allow(bad_style)]
2631        unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2632            (*x).serialNumber
2633        }
2634        #[allow(bad_style)]
2635        unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2636            (*x).revocationDate
2637        }
2638    }
2639}
2640
2641#[derive(Copy, Clone, PartialEq, Eq)]
2642pub struct X509PurposeId(c_int);
2643
2644impl X509PurposeId {
2645    pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2646    pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2647    pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2648    pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2649    pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2650    pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2651    pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2652    pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2653    pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2654    #[cfg(ossl320)]
2655    pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2656
2657    /// Constructs an `X509PurposeId` from a raw OpenSSL value.
2658    pub fn from_raw(id: c_int) -> Self {
2659        X509PurposeId(id)
2660    }
2661
2662    /// Returns the raw OpenSSL value represented by this type.
2663    pub fn as_raw(&self) -> c_int {
2664        self.0
2665    }
2666}
2667
2668/// A reference to an [`X509_PURPOSE`].
2669pub struct X509PurposeRef(Opaque);
2670
2671/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2672impl ForeignTypeRef for X509PurposeRef {
2673    type CType = ffi::X509_PURPOSE;
2674}
2675
2676impl X509PurposeRef {
2677    /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2678    /// names include
2679    ///  - "sslclient",
2680    ///  - "sslserver",
2681    ///  - "nssslserver",
2682    ///  - "smimesign",
2683    ///  - "smimeencrypt",
2684    ///  - "crlsign",
2685    ///  - "any",
2686    ///  - "ocsphelper",
2687    ///  - "timestampsign"
2688    ///
2689    /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2690    #[allow(clippy::unnecessary_cast)]
2691    pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2692        unsafe {
2693            let sname = CString::new(sname).unwrap();
2694            cfg_if! {
2695                if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2696                    let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2697                } else {
2698                    let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2699                }
2700            }
2701            Ok(purpose)
2702        }
2703    }
2704    /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2705    /// `X509PurposeRef::get_by_sname()`.
2706    #[corresponds(X509_PURPOSE_get0)]
2707    pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2708        unsafe {
2709            let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2710            Ok(X509PurposeRef::from_const_ptr(ptr))
2711        }
2712    }
2713
2714    /// Get the purpose value from an X509Purpose structure. This value is one of
2715    /// - `X509_PURPOSE_SSL_CLIENT`
2716    /// - `X509_PURPOSE_SSL_SERVER`
2717    /// - `X509_PURPOSE_NS_SSL_SERVER`
2718    /// - `X509_PURPOSE_SMIME_SIGN`
2719    /// - `X509_PURPOSE_SMIME_ENCRYPT`
2720    /// - `X509_PURPOSE_CRL_SIGN`
2721    /// - `X509_PURPOSE_ANY`
2722    /// - `X509_PURPOSE_OCSP_HELPER`
2723    /// - `X509_PURPOSE_TIMESTAMP_SIGN`
2724    pub fn purpose(&self) -> X509PurposeId {
2725        unsafe {
2726            cfg_if! {
2727                if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2728                    let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2729                } else {
2730                    let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2731                }
2732            }
2733            X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2734        }
2735    }
2736}