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