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