• 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};
13 use std::cmp::{self, Ordering};
14 use std::convert::TryFrom;
15 use std::error::Error;
16 use std::ffi::{CStr, CString};
17 use std::fmt;
18 use std::marker::PhantomData;
19 use std::mem;
20 use std::net::IpAddr;
21 use std::path::Path;
22 use std::ptr;
23 use std::slice;
24 use std::str;
25 
26 use crate::asn1::{
27     Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, 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::{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 foreign_type_and_impl_send_sync! {
53     type CType = ffi::X509_STORE_CTX;
54     fn drop = ffi::X509_STORE_CTX_free;
55 
56     /// An `X509` certificate store context.
57     pub struct X509StoreContext;
58 
59     /// A reference to an [`X509StoreContext`].
60     pub struct X509StoreContextRef;
61 }
62 
63 impl X509StoreContext {
64     /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
65     /// context.
66     #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>67     pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
68         unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
69     }
70 
71     /// Creates a new `X509StoreContext` instance.
72     #[corresponds(X509_STORE_CTX_new)]
new() -> Result<X509StoreContext, ErrorStack>73     pub fn new() -> Result<X509StoreContext, ErrorStack> {
74         unsafe {
75             ffi::init();
76             cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
77         }
78     }
79 }
80 
81 impl X509StoreContextRef {
82     /// Returns application data pertaining to an `X509` store context.
83     #[corresponds(X509_STORE_CTX_get_ex_data)]
ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>84     pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
85         unsafe {
86             let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
87             if data.is_null() {
88                 None
89             } else {
90                 Some(&*(data as *const T))
91             }
92         }
93     }
94 
95     /// Returns the error code of the context.
96     #[corresponds(X509_STORE_CTX_get_error)]
error(&self) -> X509VerifyResult97     pub fn error(&self) -> X509VerifyResult {
98         unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
99     }
100 
101     /// Initializes this context with the given certificate, certificates chain and certificate
102     /// store. After initializing the context, the `with_context` closure is called with the prepared
103     /// context. As long as the closure is running, the context stays initialized and can be used
104     /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
105     ///
106     /// * `trust` - The certificate store with the trusted certificates.
107     /// * `cert` - The certificate that should be verified.
108     /// * `cert_chain` - The certificates chain.
109     /// * `with_context` - The closure that is called with the initialized context.
110     ///
111     /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
112     /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
113     ///
114     /// [`X509_STORE_CTX_init`]:  https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html
115     /// [`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>,116     pub fn init<F, T>(
117         &mut self,
118         trust: &store::X509StoreRef,
119         cert: &X509Ref,
120         cert_chain: &StackRef<X509>,
121         with_context: F,
122     ) -> Result<T, ErrorStack>
123     where
124         F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
125     {
126         struct Cleanup<'a>(&'a mut X509StoreContextRef);
127 
128         impl<'a> Drop for Cleanup<'a> {
129             fn drop(&mut self) {
130                 unsafe {
131                     ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
132                 }
133             }
134         }
135 
136         unsafe {
137             cvt(ffi::X509_STORE_CTX_init(
138                 self.as_ptr(),
139                 trust.as_ptr(),
140                 cert.as_ptr(),
141                 cert_chain.as_ptr(),
142             ))?;
143 
144             let cleanup = Cleanup(self);
145             with_context(cleanup.0)
146         }
147     }
148 
149     /// Verifies the stored certificate.
150     ///
151     /// Returns `true` if verification succeeds. The `error` method will return the specific
152     /// validation error if the certificate was not valid.
153     ///
154     /// This will only work inside of a call to `init`.
155     #[corresponds(X509_verify_cert)]
verify_cert(&mut self) -> Result<bool, ErrorStack>156     pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
157         unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
158     }
159 
160     /// Set the error code of the context.
161     #[corresponds(X509_STORE_CTX_set_error)]
set_error(&mut self, result: X509VerifyResult)162     pub fn set_error(&mut self, result: X509VerifyResult) {
163         unsafe {
164             ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
165         }
166     }
167 
168     /// Returns a reference to the certificate which caused the error or None if
169     /// no certificate is relevant to the error.
170     #[corresponds(X509_STORE_CTX_get_current_cert)]
current_cert(&self) -> Option<&X509Ref>171     pub fn current_cert(&self) -> Option<&X509Ref> {
172         unsafe {
173             let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
174             X509Ref::from_const_ptr_opt(ptr)
175         }
176     }
177 
178     /// Returns a non-negative integer representing the depth in the certificate
179     /// chain where the error occurred. If it is zero it occurred in the end
180     /// entity certificate, one if it is the certificate which signed the end
181     /// entity certificate and so on.
182     #[corresponds(X509_STORE_CTX_get_error_depth)]
error_depth(&self) -> u32183     pub fn error_depth(&self) -> u32 {
184         unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
185     }
186 
187     /// Returns a reference to a complete valid `X509` certificate chain.
188     #[corresponds(X509_STORE_CTX_get0_chain)]
chain(&self) -> Option<&StackRef<X509>>189     pub fn chain(&self) -> Option<&StackRef<X509>> {
190         unsafe {
191             let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
192 
193             if chain.is_null() {
194                 None
195             } else {
196                 Some(StackRef::from_ptr(chain))
197             }
198         }
199     }
200 }
201 
202 /// A builder used to construct an `X509`.
203 pub struct X509Builder(X509);
204 
205 impl X509Builder {
206     /// Creates a new builder.
207     #[corresponds(X509_new)]
new() -> Result<X509Builder, ErrorStack>208     pub fn new() -> Result<X509Builder, ErrorStack> {
209         unsafe {
210             ffi::init();
211             cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
212         }
213     }
214 
215     /// Sets the notAfter constraint on the certificate.
216     #[corresponds(X509_set1_notAfter)]
set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>217     pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
218         unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
219     }
220 
221     /// Sets the notBefore constraint on the certificate.
222     #[corresponds(X509_set1_notBefore)]
set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>223     pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
224         unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
225     }
226 
227     /// Sets the version of the certificate.
228     ///
229     /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
230     /// the X.509 standard should pass `2` to this method.
231     #[corresponds(X509_set_version)]
232     #[allow(clippy::useless_conversion)]
set_version(&mut self, version: i32) -> Result<(), ErrorStack>233     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
234         unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
235     }
236 
237     /// Sets the serial number of the certificate.
238     #[corresponds(X509_set_serialNumber)]
set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>239     pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
240         unsafe {
241             cvt(ffi::X509_set_serialNumber(
242                 self.0.as_ptr(),
243                 serial_number.as_ptr(),
244             ))
245             .map(|_| ())
246         }
247     }
248 
249     /// Sets the issuer name of the certificate.
250     #[corresponds(X509_set_issuer_name)]
set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack>251     pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
252         unsafe {
253             cvt(ffi::X509_set_issuer_name(
254                 self.0.as_ptr(),
255                 issuer_name.as_ptr(),
256             ))
257             .map(|_| ())
258         }
259     }
260 
261     /// Sets the subject name of the certificate.
262     ///
263     /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools.
264     /// The `CN` field is used for the common name, such as a DNS name.
265     ///
266     /// ```
267     /// use openssl::x509::{X509, X509NameBuilder};
268     ///
269     /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap();
270     /// x509_name.append_entry_by_text("C", "US").unwrap();
271     /// x509_name.append_entry_by_text("ST", "CA").unwrap();
272     /// x509_name.append_entry_by_text("O", "Some organization").unwrap();
273     /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap();
274     /// let x509_name = x509_name.build();
275     ///
276     /// let mut x509 = openssl::x509::X509::builder().unwrap();
277     /// x509.set_subject_name(&x509_name).unwrap();
278     /// ```
279     #[corresponds(X509_set_subject_name)]
set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>280     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
281         unsafe {
282             cvt(ffi::X509_set_subject_name(
283                 self.0.as_ptr(),
284                 subject_name.as_ptr(),
285             ))
286             .map(|_| ())
287         }
288     }
289 
290     /// Sets the public key associated with the certificate.
291     #[corresponds(X509_set_pubkey)]
set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,292     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
293     where
294         T: HasPublic,
295     {
296         unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
297     }
298 
299     /// Returns a context object which is needed to create certain X509 extension values.
300     ///
301     /// Set `issuer` to `None` if the certificate will be self-signed.
302     #[corresponds(X509V3_set_ctx)]
x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>303     pub fn x509v3_context<'a>(
304         &'a self,
305         issuer: Option<&'a X509Ref>,
306         conf: Option<&'a ConfRef>,
307     ) -> X509v3Context<'a> {
308         unsafe {
309             let mut ctx = mem::zeroed();
310 
311             let issuer = match issuer {
312                 Some(issuer) => issuer.as_ptr(),
313                 None => self.0.as_ptr(),
314             };
315             let subject = self.0.as_ptr();
316             ffi::X509V3_set_ctx(
317                 &mut ctx,
318                 issuer,
319                 subject,
320                 ptr::null_mut(),
321                 ptr::null_mut(),
322                 0,
323             );
324 
325             // nodb case taken care of since we zeroed ctx above
326             if let Some(conf) = conf {
327                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
328             }
329 
330             X509v3Context(ctx, PhantomData)
331         }
332     }
333 
334     /// Adds an X509 extension value to the certificate.
335     ///
336     /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>337     pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
338         self.append_extension2(&extension)
339     }
340 
341     /// Adds an X509 extension value to the certificate.
342     #[corresponds(X509_add_ext)]
append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack>343     pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
344         unsafe {
345             cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
346             Ok(())
347         }
348     }
349 
350     /// Signs the certificate with a private key.
351     #[corresponds(X509_sign)]
sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,352     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
353     where
354         T: HasPrivate,
355     {
356         unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
357     }
358 
359     /// Consumes the builder, returning the certificate.
build(self) -> X509360     pub fn build(self) -> X509 {
361         self.0
362     }
363 }
364 
365 foreign_type_and_impl_send_sync! {
366     type CType = ffi::X509;
367     fn drop = ffi::X509_free;
368 
369     /// An `X509` public key certificate.
370     pub struct X509;
371     /// Reference to `X509`.
372     pub struct X509Ref;
373 }
374 
375 #[cfg(boringssl)]
376 type X509LenTy = c_uint;
377 #[cfg(not(boringssl))]
378 type X509LenTy = c_int;
379 
380 impl X509Ref {
381     /// Returns this certificate's subject name.
382     #[corresponds(X509_get_subject_name)]
subject_name(&self) -> &X509NameRef383     pub fn subject_name(&self) -> &X509NameRef {
384         unsafe {
385             let name = ffi::X509_get_subject_name(self.as_ptr());
386             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
387         }
388     }
389 
390     /// Returns the hash of the certificates subject
391     #[corresponds(X509_subject_name_hash)]
subject_name_hash(&self) -> u32392     pub fn subject_name_hash(&self) -> u32 {
393         unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
394     }
395 
396     /// Returns this certificate's issuer name.
397     #[corresponds(X509_get_issuer_name)]
issuer_name(&self) -> &X509NameRef398     pub fn issuer_name(&self) -> &X509NameRef {
399         unsafe {
400             let name = ffi::X509_get_issuer_name(self.as_ptr());
401             X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
402         }
403     }
404 
405     /// Returns the hash of the certificates issuer
406     #[corresponds(X509_issuer_name_hash)]
issuer_name_hash(&self) -> u32407     pub fn issuer_name_hash(&self) -> u32 {
408         unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 }
409     }
410 
411     /// Returns this certificate's subject alternative name entries, if they exist.
412     #[corresponds(X509_get_ext_d2i)]
subject_alt_names(&self) -> Option<Stack<GeneralName>>413     pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
414         unsafe {
415             let stack = ffi::X509_get_ext_d2i(
416                 self.as_ptr(),
417                 ffi::NID_subject_alt_name,
418                 ptr::null_mut(),
419                 ptr::null_mut(),
420             );
421             Stack::from_ptr_opt(stack as *mut _)
422         }
423     }
424 
425     /// Returns this certificate's issuer alternative name entries, if they exist.
426     #[corresponds(X509_get_ext_d2i)]
issuer_alt_names(&self) -> Option<Stack<GeneralName>>427     pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
428         unsafe {
429             let stack = ffi::X509_get_ext_d2i(
430                 self.as_ptr(),
431                 ffi::NID_issuer_alt_name,
432                 ptr::null_mut(),
433                 ptr::null_mut(),
434             );
435             Stack::from_ptr_opt(stack as *mut _)
436         }
437     }
438 
439     /// Returns this certificate's [`authority information access`] entries, if they exist.
440     ///
441     /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1
442     #[corresponds(X509_get_ext_d2i)]
authority_info(&self) -> Option<Stack<AccessDescription>>443     pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
444         unsafe {
445             let stack = ffi::X509_get_ext_d2i(
446                 self.as_ptr(),
447                 ffi::NID_info_access,
448                 ptr::null_mut(),
449                 ptr::null_mut(),
450             );
451             Stack::from_ptr_opt(stack as *mut _)
452         }
453     }
454 
455     #[corresponds(X509_get_pubkey)]
public_key(&self) -> Result<PKey<Public>, ErrorStack>456     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
457         unsafe {
458             let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
459             Ok(PKey::from_ptr(pkey))
460         }
461     }
462 
463     /// Returns a digest of the DER representation of the certificate.
464     #[corresponds(X509_digest)]
digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>465     pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
466         unsafe {
467             let mut digest = DigestBytes {
468                 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
469                 len: ffi::EVP_MAX_MD_SIZE as usize,
470             };
471             let mut len = ffi::EVP_MAX_MD_SIZE as c_uint;
472             cvt(ffi::X509_digest(
473                 self.as_ptr(),
474                 hash_type.as_ptr(),
475                 digest.buf.as_mut_ptr() as *mut _,
476                 &mut len,
477             ))?;
478             digest.len = len as usize;
479 
480             Ok(digest)
481         }
482     }
483 
484     #[deprecated(since = "0.10.9", note = "renamed to digest")]
fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>485     pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
486         self.digest(hash_type).map(|b| b.to_vec())
487     }
488 
489     /// Returns the certificate's Not After validity period.
490     #[corresponds(X509_getm_notAfter)]
not_after(&self) -> &Asn1TimeRef491     pub fn not_after(&self) -> &Asn1TimeRef {
492         unsafe {
493             let date = X509_getm_notAfter(self.as_ptr());
494             Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
495         }
496     }
497 
498     /// Returns the certificate's Not Before validity period.
499     #[corresponds(X509_getm_notBefore)]
not_before(&self) -> &Asn1TimeRef500     pub fn not_before(&self) -> &Asn1TimeRef {
501         unsafe {
502             let date = X509_getm_notBefore(self.as_ptr());
503             Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
504         }
505     }
506 
507     /// Returns the certificate's signature
508     #[corresponds(X509_get0_signature)]
signature(&self) -> &Asn1BitStringRef509     pub fn signature(&self) -> &Asn1BitStringRef {
510         unsafe {
511             let mut signature = ptr::null();
512             X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
513             Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
514         }
515     }
516 
517     /// Returns the certificate's signature algorithm.
518     #[corresponds(X509_get0_signature)]
signature_algorithm(&self) -> &X509AlgorithmRef519     pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
520         unsafe {
521             let mut algor = ptr::null();
522             X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
523             X509AlgorithmRef::from_const_ptr_opt(algor)
524                 .expect("signature algorithm must not be null")
525         }
526     }
527 
528     /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
529     /// Access field.
530     #[corresponds(X509_get1_ocsp)]
ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>531     pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
532         unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
533     }
534 
535     /// Checks that this certificate issued `subject`.
536     #[corresponds(X509_check_issued)]
issued(&self, subject: &X509Ref) -> X509VerifyResult537     pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
538         unsafe {
539             let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
540             X509VerifyResult::from_raw(r)
541         }
542     }
543 
544     /// Returns certificate version. If this certificate has no explicit version set, it defaults to
545     /// version 1.
546     ///
547     /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
548     #[corresponds(X509_get_version)]
549     #[cfg(ossl110)]
version(&self) -> i32550     pub fn version(&self) -> i32 {
551         unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
552     }
553 
554     /// Check if the certificate is signed using the given public key.
555     ///
556     /// Only the signature is checked: no other checks (such as certificate chain validity)
557     /// are performed.
558     ///
559     /// Returns `true` if verification succeeds.
560     #[corresponds(X509_verify)]
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,561     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
562     where
563         T: HasPublic,
564     {
565         unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
566     }
567 
568     /// Returns this certificate's serial number.
569     #[corresponds(X509_get_serialNumber)]
serial_number(&self) -> &Asn1IntegerRef570     pub fn serial_number(&self) -> &Asn1IntegerRef {
571         unsafe {
572             let r = ffi::X509_get_serialNumber(self.as_ptr());
573             Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
574         }
575     }
576 
577     to_pem! {
578         /// Serializes the certificate into a PEM-encoded X509 structure.
579         ///
580         /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
581         #[corresponds(PEM_write_bio_X509)]
582         to_pem,
583         ffi::PEM_write_bio_X509
584     }
585 
586     to_der! {
587         /// Serializes the certificate into a DER-encoded X509 structure.
588         #[corresponds(i2d_X509)]
589         to_der,
590         ffi::i2d_X509
591     }
592 
593     to_pem! {
594         /// Converts the certificate to human readable text.
595         #[corresponds(X509_print)]
596         to_text,
597         ffi::X509_print
598     }
599 }
600 
601 impl ToOwned for X509Ref {
602     type Owned = X509;
603 
to_owned(&self) -> X509604     fn to_owned(&self) -> X509 {
605         unsafe {
606             X509_up_ref(self.as_ptr());
607             X509::from_ptr(self.as_ptr())
608         }
609     }
610 }
611 
612 impl Ord for X509Ref {
cmp(&self, other: &Self) -> cmp::Ordering613     fn cmp(&self, other: &Self) -> cmp::Ordering {
614         // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
615         // It can't fail if both pointers are valid, which we know is true.
616         let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
617         cmp.cmp(&0)
618     }
619 }
620 
621 impl PartialOrd for X509Ref {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>622     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
623         Some(self.cmp(other))
624     }
625 }
626 
627 impl PartialOrd<X509> for X509Ref {
partial_cmp(&self, other: &X509) -> Option<cmp::Ordering>628     fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
629         <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
630     }
631 }
632 
633 impl PartialEq for X509Ref {
eq(&self, other: &Self) -> bool634     fn eq(&self, other: &Self) -> bool {
635         self.cmp(other) == cmp::Ordering::Equal
636     }
637 }
638 
639 impl PartialEq<X509> for X509Ref {
eq(&self, other: &X509) -> bool640     fn eq(&self, other: &X509) -> bool {
641         <X509Ref as PartialEq<X509Ref>>::eq(self, other)
642     }
643 }
644 
645 impl Eq for X509Ref {}
646 
647 impl X509 {
648     /// Returns a new builder.
builder() -> Result<X509Builder, ErrorStack>649     pub fn builder() -> Result<X509Builder, ErrorStack> {
650         X509Builder::new()
651     }
652 
653     from_pem! {
654         /// Deserializes a PEM-encoded X509 structure.
655         ///
656         /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
657         #[corresponds(PEM_read_bio_X509)]
658         from_pem,
659         X509,
660         ffi::PEM_read_bio_X509
661     }
662 
663     from_der! {
664         /// Deserializes a DER-encoded X509 structure.
665         #[corresponds(d2i_X509)]
666         from_der,
667         X509,
668         ffi::d2i_X509
669     }
670 
671     /// Deserializes a list of PEM-formatted certificates.
672     #[corresponds(PEM_read_bio_X509)]
stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>673     pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
674         unsafe {
675             ffi::init();
676             let bio = MemBioSlice::new(pem)?;
677 
678             let mut certs = vec![];
679             loop {
680                 let r =
681                     ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
682                 if r.is_null() {
683                     let err = ffi::ERR_peek_last_error();
684                     if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM
685                         && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
686                     {
687                         ffi::ERR_clear_error();
688                         break;
689                     }
690 
691                     return Err(ErrorStack::get());
692                 } else {
693                     certs.push(X509(r));
694                 }
695             }
696 
697             Ok(certs)
698         }
699     }
700 }
701 
702 impl Clone for X509 {
clone(&self) -> X509703     fn clone(&self) -> X509 {
704         X509Ref::to_owned(self)
705     }
706 }
707 
708 impl fmt::Debug for X509 {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result709     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
710         let serial = match &self.serial_number().to_bn() {
711             Ok(bn) => match bn.to_hex_str() {
712                 Ok(hex) => hex.to_string(),
713                 Err(_) => "".to_string(),
714             },
715             Err(_) => "".to_string(),
716         };
717         let mut debug_struct = formatter.debug_struct("X509");
718         debug_struct.field("serial_number", &serial);
719         debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
720         debug_struct.field("issuer", &self.issuer_name());
721         debug_struct.field("subject", &self.subject_name());
722         if let Some(subject_alt_names) = &self.subject_alt_names() {
723             debug_struct.field("subject_alt_names", subject_alt_names);
724         }
725         debug_struct.field("not_before", &self.not_before());
726         debug_struct.field("not_after", &self.not_after());
727 
728         if let Ok(public_key) = &self.public_key() {
729             debug_struct.field("public_key", public_key);
730         };
731         // TODO: Print extensions once they are supported on the X509 struct.
732 
733         debug_struct.finish()
734     }
735 }
736 
737 impl AsRef<X509Ref> for X509Ref {
as_ref(&self) -> &X509Ref738     fn as_ref(&self) -> &X509Ref {
739         self
740     }
741 }
742 
743 impl Stackable for X509 {
744     type StackType = ffi::stack_st_X509;
745 }
746 
747 impl Ord for X509 {
cmp(&self, other: &Self) -> cmp::Ordering748     fn cmp(&self, other: &Self) -> cmp::Ordering {
749         X509Ref::cmp(self, other)
750     }
751 }
752 
753 impl PartialOrd for X509 {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>754     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
755         X509Ref::partial_cmp(self, other)
756     }
757 }
758 
759 impl PartialOrd<X509Ref> for X509 {
partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering>760     fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
761         X509Ref::partial_cmp(self, other)
762     }
763 }
764 
765 impl PartialEq for X509 {
eq(&self, other: &Self) -> bool766     fn eq(&self, other: &Self) -> bool {
767         X509Ref::eq(self, other)
768     }
769 }
770 
771 impl PartialEq<X509Ref> for X509 {
eq(&self, other: &X509Ref) -> bool772     fn eq(&self, other: &X509Ref) -> bool {
773         X509Ref::eq(self, other)
774     }
775 }
776 
777 impl Eq for X509 {}
778 
779 /// A context object required to construct certain `X509` extension values.
780 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
781 
782 impl<'a> X509v3Context<'a> {
as_ptr(&self) -> *mut ffi::X509V3_CTX783     pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
784         &self.0 as *const _ as *mut _
785     }
786 }
787 
788 foreign_type_and_impl_send_sync! {
789     type CType = ffi::X509_EXTENSION;
790     fn drop = ffi::X509_EXTENSION_free;
791 
792     /// Permit additional fields to be added to an `X509` v3 certificate.
793     pub struct X509Extension;
794     /// Reference to `X509Extension`.
795     pub struct X509ExtensionRef;
796 }
797 
798 impl Stackable for X509Extension {
799     type StackType = ffi::stack_st_X509_EXTENSION;
800 }
801 
802 impl X509Extension {
803     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
804     /// names and their value formats.
805     ///
806     /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
807     /// provided.
808     ///
809     /// See the extension module for builder types which will construct certain common extensions.
new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: &str, value: &str, ) -> Result<X509Extension, ErrorStack>810     pub fn new(
811         conf: Option<&ConfRef>,
812         context: Option<&X509v3Context<'_>>,
813         name: &str,
814         value: &str,
815     ) -> Result<X509Extension, ErrorStack> {
816         let name = CString::new(name).unwrap();
817         let value = CString::new(value).unwrap();
818         unsafe {
819             ffi::init();
820             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
821             let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr);
822             let name = name.as_ptr() as *mut _;
823             let value = value.as_ptr() as *mut _;
824 
825             cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension)
826         }
827     }
828 
829     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
830     /// extensions and their value formats.
831     ///
832     /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
833     /// be provided.
834     ///
835     /// See the extension module for builder types which will construct certain common extensions.
new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result<X509Extension, ErrorStack>836     pub fn new_nid(
837         conf: Option<&ConfRef>,
838         context: Option<&X509v3Context<'_>>,
839         name: Nid,
840         value: &str,
841     ) -> Result<X509Extension, ErrorStack> {
842         let value = CString::new(value).unwrap();
843         unsafe {
844             ffi::init();
845             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
846             let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr);
847             let name = name.as_raw();
848             let value = value.as_ptr() as *mut _;
849 
850             cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension)
851         }
852     }
853 
854     /// Adds an alias for an extension
855     ///
856     /// # Safety
857     ///
858     /// This method modifies global state without locking and therefore is not thread safe
859     #[corresponds(X509V3_EXT_add_alias)]
add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack>860     pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
861         ffi::init();
862         cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
863     }
864 }
865 
866 /// A builder used to construct an `X509Name`.
867 pub struct X509NameBuilder(X509Name);
868 
869 impl X509NameBuilder {
870     /// Creates a new builder.
new() -> Result<X509NameBuilder, ErrorStack>871     pub fn new() -> Result<X509NameBuilder, ErrorStack> {
872         unsafe {
873             ffi::init();
874             cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
875         }
876     }
877 
878     /// Add a name entry
879     #[corresponds(X509_NAME_add_entry)]
880     #[cfg(any(ossl101, libressl350))]
append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack>881     pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
882         unsafe {
883             cvt(ffi::X509_NAME_add_entry(
884                 self.0.as_ptr(),
885                 ne.as_ptr(),
886                 -1,
887                 0,
888             ))
889             .map(|_| ())
890         }
891     }
892 
893     /// Add a field entry by str.
894     ///
895     /// This corresponds to [`X509_NAME_add_entry_by_txt`].
896     ///
897     /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html
append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack>898     pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
899         unsafe {
900             let field = CString::new(field).unwrap();
901             assert!(value.len() <= c_int::max_value() as usize);
902             cvt(ffi::X509_NAME_add_entry_by_txt(
903                 self.0.as_ptr(),
904                 field.as_ptr() as *mut _,
905                 ffi::MBSTRING_UTF8,
906                 value.as_ptr(),
907                 value.len() as c_int,
908                 -1,
909                 0,
910             ))
911             .map(|_| ())
912         }
913     }
914 
915     /// Add a field entry by str with a specific type.
916     ///
917     /// This corresponds to [`X509_NAME_add_entry_by_txt`].
918     ///
919     /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/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>920     pub fn append_entry_by_text_with_type(
921         &mut self,
922         field: &str,
923         value: &str,
924         ty: Asn1Type,
925     ) -> Result<(), ErrorStack> {
926         unsafe {
927             let field = CString::new(field).unwrap();
928             assert!(value.len() <= c_int::max_value() as usize);
929             cvt(ffi::X509_NAME_add_entry_by_txt(
930                 self.0.as_ptr(),
931                 field.as_ptr() as *mut _,
932                 ty.as_raw(),
933                 value.as_ptr(),
934                 value.len() as c_int,
935                 -1,
936                 0,
937             ))
938             .map(|_| ())
939         }
940     }
941 
942     /// Add a field entry by NID.
943     ///
944     /// This corresponds to [`X509_NAME_add_entry_by_NID`].
945     ///
946     /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack>947     pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
948         unsafe {
949             assert!(value.len() <= c_int::max_value() as usize);
950             cvt(ffi::X509_NAME_add_entry_by_NID(
951                 self.0.as_ptr(),
952                 field.as_raw(),
953                 ffi::MBSTRING_UTF8,
954                 value.as_ptr() as *mut _,
955                 value.len() as c_int,
956                 -1,
957                 0,
958             ))
959             .map(|_| ())
960         }
961     }
962 
963     /// Add a field entry by NID with a specific type.
964     ///
965     /// This corresponds to [`X509_NAME_add_entry_by_NID`].
966     ///
967     /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/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>968     pub fn append_entry_by_nid_with_type(
969         &mut self,
970         field: Nid,
971         value: &str,
972         ty: Asn1Type,
973     ) -> Result<(), ErrorStack> {
974         unsafe {
975             assert!(value.len() <= c_int::max_value() as usize);
976             cvt(ffi::X509_NAME_add_entry_by_NID(
977                 self.0.as_ptr(),
978                 field.as_raw(),
979                 ty.as_raw(),
980                 value.as_ptr() as *mut _,
981                 value.len() as c_int,
982                 -1,
983                 0,
984             ))
985             .map(|_| ())
986         }
987     }
988 
989     /// Return an `X509Name`.
build(self) -> X509Name990     pub fn build(self) -> X509Name {
991         self.0
992     }
993 }
994 
995 foreign_type_and_impl_send_sync! {
996     type CType = ffi::X509_NAME;
997     fn drop = ffi::X509_NAME_free;
998 
999     /// The names of an `X509` certificate.
1000     pub struct X509Name;
1001     /// Reference to `X509Name`.
1002     pub struct X509NameRef;
1003 }
1004 
1005 impl X509Name {
1006     /// Returns a new builder.
builder() -> Result<X509NameBuilder, ErrorStack>1007     pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1008         X509NameBuilder::new()
1009     }
1010 
1011     /// Loads subject names from a file containing PEM-formatted certificates.
1012     ///
1013     /// 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>1014     pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1015         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1016         unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1017     }
1018 
1019     from_der! {
1020         /// Deserializes a DER-encoded X509 name structure.
1021         ///
1022         /// This corresponds to [`d2i_X509_NAME`].
1023         ///
1024         /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html
1025         from_der,
1026         X509Name,
1027         ffi::d2i_X509_NAME
1028     }
1029 }
1030 
1031 impl Stackable for X509Name {
1032     type StackType = ffi::stack_st_X509_NAME;
1033 }
1034 
1035 impl X509NameRef {
1036     /// Returns the name entries by the nid.
entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>1037     pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1038         X509NameEntries {
1039             name: self,
1040             nid: Some(nid),
1041             loc: -1,
1042         }
1043     }
1044 
1045     /// Returns an iterator over all `X509NameEntry` values
entries(&self) -> X509NameEntries<'_>1046     pub fn entries(&self) -> X509NameEntries<'_> {
1047         X509NameEntries {
1048             name: self,
1049             nid: None,
1050             loc: -1,
1051         }
1052     }
1053 
1054     /// Compare two names, like [`Ord`] but it may fail.
1055     ///
1056     /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
1057     /// call fails.
1058     /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
1059     /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
1060     #[corresponds(X509_NAME_cmp)]
try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack>1061     pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1062         let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1063         if cfg!(ossl300) && cmp == -2 {
1064             return Err(ErrorStack::get());
1065         }
1066         Ok(cmp.cmp(&0))
1067     }
1068 
1069     /// Copies the name to a new `X509Name`.
1070     #[corresponds(X509_NAME_dup)]
1071     #[cfg(any(boringssl, ossl110, libressl270))]
to_owned(&self) -> Result<X509Name, ErrorStack>1072     pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1073         unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1074     }
1075 
1076     to_der! {
1077         /// Serializes the certificate into a DER-encoded X509 name structure.
1078         ///
1079         /// This corresponds to [`i2d_X509_NAME`].
1080         ///
1081         /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html
1082         to_der,
1083         ffi::i2d_X509_NAME
1084     }
1085 }
1086 
1087 impl fmt::Debug for X509NameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1088     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1089         formatter.debug_list().entries(self.entries()).finish()
1090     }
1091 }
1092 
1093 /// A type to destructure and examine an `X509Name`.
1094 pub struct X509NameEntries<'a> {
1095     name: &'a X509NameRef,
1096     nid: Option<Nid>,
1097     loc: c_int,
1098 }
1099 
1100 impl<'a> Iterator for X509NameEntries<'a> {
1101     type Item = &'a X509NameEntryRef;
1102 
next(&mut self) -> Option<&'a X509NameEntryRef>1103     fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1104         unsafe {
1105             match self.nid {
1106                 Some(nid) => {
1107                     // There is a `Nid` specified to search for
1108                     self.loc =
1109                         ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1110                     if self.loc == -1 {
1111                         return None;
1112                     }
1113                 }
1114                 None => {
1115                     // Iterate over all `Nid`s
1116                     self.loc += 1;
1117                     if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1118                         return None;
1119                     }
1120                 }
1121             }
1122 
1123             let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1124 
1125             Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1126         }
1127     }
1128 }
1129 
1130 foreign_type_and_impl_send_sync! {
1131     type CType = ffi::X509_NAME_ENTRY;
1132     fn drop = ffi::X509_NAME_ENTRY_free;
1133 
1134     /// A name entry associated with a `X509Name`.
1135     pub struct X509NameEntry;
1136     /// Reference to `X509NameEntry`.
1137     pub struct X509NameEntryRef;
1138 }
1139 
1140 impl X509NameEntryRef {
1141     /// Returns the field value of an `X509NameEntry`.
1142     ///
1143     /// This corresponds to [`X509_NAME_ENTRY_get_data`].
1144     ///
1145     /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html
data(&self) -> &Asn1StringRef1146     pub fn data(&self) -> &Asn1StringRef {
1147         unsafe {
1148             let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1149             Asn1StringRef::from_ptr(data)
1150         }
1151     }
1152 
1153     /// Returns the `Asn1Object` value of an `X509NameEntry`.
1154     /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1155     ///
1156     /// This corresponds to [`X509_NAME_ENTRY_get_object`].
1157     ///
1158     /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html
object(&self) -> &Asn1ObjectRef1159     pub fn object(&self) -> &Asn1ObjectRef {
1160         unsafe {
1161             let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1162             Asn1ObjectRef::from_ptr(object)
1163         }
1164     }
1165 }
1166 
1167 impl fmt::Debug for X509NameEntryRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1168     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1169         formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1170     }
1171 }
1172 
1173 /// A builder used to construct an `X509Req`.
1174 pub struct X509ReqBuilder(X509Req);
1175 
1176 impl X509ReqBuilder {
1177     /// Returns a builder for a certificate request.
1178     ///
1179     /// This corresponds to [`X509_REQ_new`].
1180     ///
1181     ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html
new() -> Result<X509ReqBuilder, ErrorStack>1182     pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1183         unsafe {
1184             ffi::init();
1185             cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1186         }
1187     }
1188 
1189     /// Set the numerical value of the version field.
1190     ///
1191     /// This corresponds to [`X509_REQ_set_version`].
1192     ///
1193     ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html
1194     #[allow(clippy::useless_conversion)]
set_version(&mut self, version: i32) -> Result<(), ErrorStack>1195     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1196         unsafe {
1197             cvt(ffi::X509_REQ_set_version(
1198                 self.0.as_ptr(),
1199                 version as c_long,
1200             ))
1201             .map(|_| ())
1202         }
1203     }
1204 
1205     /// Set the issuer name.
1206     ///
1207     /// This corresponds to [`X509_REQ_set_subject_name`].
1208     ///
1209     /// [`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>1210     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1211         unsafe {
1212             cvt(ffi::X509_REQ_set_subject_name(
1213                 self.0.as_ptr(),
1214                 subject_name.as_ptr(),
1215             ))
1216             .map(|_| ())
1217         }
1218     }
1219 
1220     /// Set the public key.
1221     ///
1222     /// This corresponds to [`X509_REQ_set_pubkey`].
1223     ///
1224     /// [`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,1225     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1226     where
1227         T: HasPublic,
1228     {
1229         unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1230     }
1231 
1232     /// Return an `X509v3Context`. This context object can be used to construct
1233     /// certain `X509` extensions.
x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1234     pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1235         unsafe {
1236             let mut ctx = mem::zeroed();
1237 
1238             ffi::X509V3_set_ctx(
1239                 &mut ctx,
1240                 ptr::null_mut(),
1241                 ptr::null_mut(),
1242                 self.0.as_ptr(),
1243                 ptr::null_mut(),
1244                 0,
1245             );
1246 
1247             // nodb case taken care of since we zeroed ctx above
1248             if let Some(conf) = conf {
1249                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1250             }
1251 
1252             X509v3Context(ctx, PhantomData)
1253         }
1254     }
1255 
1256     /// Permits any number of extension fields to be added to the certificate.
add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1257     pub fn add_extensions(
1258         &mut self,
1259         extensions: &StackRef<X509Extension>,
1260     ) -> Result<(), ErrorStack> {
1261         unsafe {
1262             cvt(ffi::X509_REQ_add_extensions(
1263                 self.0.as_ptr(),
1264                 extensions.as_ptr(),
1265             ))
1266             .map(|_| ())
1267         }
1268     }
1269 
1270     /// Sign the request using a private key.
1271     ///
1272     /// This corresponds to [`X509_REQ_sign`].
1273     ///
1274     /// [`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,1275     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1276     where
1277         T: HasPrivate,
1278     {
1279         unsafe {
1280             cvt(ffi::X509_REQ_sign(
1281                 self.0.as_ptr(),
1282                 key.as_ptr(),
1283                 hash.as_ptr(),
1284             ))
1285             .map(|_| ())
1286         }
1287     }
1288 
1289     /// Returns the `X509Req`.
build(self) -> X509Req1290     pub fn build(self) -> X509Req {
1291         self.0
1292     }
1293 }
1294 
1295 foreign_type_and_impl_send_sync! {
1296     type CType = ffi::X509_REQ;
1297     fn drop = ffi::X509_REQ_free;
1298 
1299     /// An `X509` certificate request.
1300     pub struct X509Req;
1301     /// Reference to `X509Req`.
1302     pub struct X509ReqRef;
1303 }
1304 
1305 impl X509Req {
1306     /// A builder for `X509Req`.
builder() -> Result<X509ReqBuilder, ErrorStack>1307     pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1308         X509ReqBuilder::new()
1309     }
1310 
1311     from_pem! {
1312         /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1313         ///
1314         /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1315         ///
1316         /// This corresponds to [`PEM_read_bio_X509_REQ`].
1317         ///
1318         /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html
1319         from_pem,
1320         X509Req,
1321         ffi::PEM_read_bio_X509_REQ
1322     }
1323 
1324     from_der! {
1325         /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1326         ///
1327         /// This corresponds to [`d2i_X509_REQ`].
1328         ///
1329         /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html
1330         from_der,
1331         X509Req,
1332         ffi::d2i_X509_REQ
1333     }
1334 }
1335 
1336 impl X509ReqRef {
1337     to_pem! {
1338         /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1339         ///
1340         /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1341         ///
1342         /// This corresponds to [`PEM_write_bio_X509_REQ`].
1343         ///
1344         /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html
1345         to_pem,
1346         ffi::PEM_write_bio_X509_REQ
1347     }
1348 
1349     to_der! {
1350         /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1351         ///
1352         /// This corresponds to [`i2d_X509_REQ`].
1353         ///
1354         /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html
1355         to_der,
1356         ffi::i2d_X509_REQ
1357     }
1358 
1359     to_pem! {
1360         /// Converts the request to human readable text.
1361         #[corresponds(X509_Req_print)]
1362         to_text,
1363         ffi::X509_REQ_print
1364     }
1365 
1366     /// Returns the numerical value of the version field of the certificate request.
1367     ///
1368     /// This corresponds to [`X509_REQ_get_version`]
1369     ///
1370     /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html
version(&self) -> i321371     pub fn version(&self) -> i32 {
1372         unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1373     }
1374 
1375     /// Returns the subject name of the certificate request.
1376     ///
1377     /// This corresponds to [`X509_REQ_get_subject_name`]
1378     ///
1379     /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html
subject_name(&self) -> &X509NameRef1380     pub fn subject_name(&self) -> &X509NameRef {
1381         unsafe {
1382             let name = X509_REQ_get_subject_name(self.as_ptr());
1383             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1384         }
1385     }
1386 
1387     /// Returns the public key of the certificate request.
1388     ///
1389     /// This corresponds to [`X509_REQ_get_pubkey"]
1390     ///
1391     /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html
public_key(&self) -> Result<PKey<Public>, ErrorStack>1392     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1393         unsafe {
1394             let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1395             Ok(PKey::from_ptr(key))
1396         }
1397     }
1398 
1399     /// Check if the certificate request is signed using the given public key.
1400     ///
1401     /// Returns `true` if verification succeeds.
1402     ///
1403     /// This corresponds to [`X509_REQ_verify"].
1404     ///
1405     /// [`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,1406     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1407     where
1408         T: HasPublic,
1409     {
1410         unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1411     }
1412 
1413     /// Returns the extensions of the certificate request.
1414     ///
1415     /// This corresponds to [`X509_REQ_get_extensions"]
extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1416     pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1417         unsafe {
1418             let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1419             Ok(Stack::from_ptr(extensions))
1420         }
1421     }
1422 }
1423 
1424 foreign_type_and_impl_send_sync! {
1425     type CType = ffi::X509_REVOKED;
1426     fn drop = ffi::X509_REVOKED_free;
1427 
1428     /// An `X509` certificate request.
1429     pub struct X509Revoked;
1430     /// Reference to `X509Crl`.
1431     pub struct X509RevokedRef;
1432 }
1433 
1434 impl Stackable for X509Revoked {
1435     type StackType = ffi::stack_st_X509_REVOKED;
1436 }
1437 
1438 impl X509Revoked {
1439     from_der! {
1440         /// Deserializes a DER-encoded certificate revocation status
1441         #[corresponds(d2i_X509_REVOKED)]
1442         from_der,
1443         X509Revoked,
1444         ffi::d2i_X509_REVOKED
1445     }
1446 }
1447 
1448 impl X509RevokedRef {
1449     to_der! {
1450         /// Serializes the certificate request to a DER-encoded certificate revocation status
1451         #[corresponds(d2i_X509_REVOKED)]
1452         to_der,
1453         ffi::i2d_X509_REVOKED
1454     }
1455 
1456     /// Get the date that the certificate was revoked
1457     #[corresponds(X509_REVOKED_get0_revocationDate)]
revocation_date(&self) -> &Asn1TimeRef1458     pub fn revocation_date(&self) -> &Asn1TimeRef {
1459         unsafe {
1460             let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1461             assert!(!r.is_null());
1462             Asn1TimeRef::from_ptr(r as *mut _)
1463         }
1464     }
1465 
1466     /// Get the serial number of the revoked certificate
1467     #[corresponds(X509_REVOKED_get0_serialNumber)]
serial_number(&self) -> &Asn1IntegerRef1468     pub fn serial_number(&self) -> &Asn1IntegerRef {
1469         unsafe {
1470             let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1471             assert!(!r.is_null());
1472             Asn1IntegerRef::from_ptr(r as *mut _)
1473         }
1474     }
1475 }
1476 
1477 foreign_type_and_impl_send_sync! {
1478     type CType = ffi::X509_CRL;
1479     fn drop = ffi::X509_CRL_free;
1480 
1481     /// An `X509` certificate request.
1482     pub struct X509Crl;
1483     /// Reference to `X509Crl`.
1484     pub struct X509CrlRef;
1485 }
1486 
1487 /// The status of a certificate in a revoction list
1488 ///
1489 /// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1490 ///
1491 /// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html
1492 pub enum CrlStatus<'a> {
1493     /// The certificate is not present in the list
1494     NotRevoked,
1495     /// The certificate is in the list and is revoked
1496     Revoked(&'a X509RevokedRef),
1497     /// The certificate is in the list, but has the "removeFromCrl" status.
1498     ///
1499     /// This can occur if the certificate was revoked with the "CertificateHold"
1500     /// reason, and has since been unrevoked.
1501     RemoveFromCrl(&'a X509RevokedRef),
1502 }
1503 
1504 impl<'a> CrlStatus<'a> {
1505     // Helper used by the X509_CRL_get0_by_* methods to convert their return
1506     // value to the status enum.
1507     // Safety note: the returned CrlStatus must not outlive the owner of the
1508     // revoked_entry pointer.
from_ffi_status( status: c_int, revoked_entry: *mut ffi::X509_REVOKED, ) -> CrlStatus<'a>1509     unsafe fn from_ffi_status(
1510         status: c_int,
1511         revoked_entry: *mut ffi::X509_REVOKED,
1512     ) -> CrlStatus<'a> {
1513         match status {
1514             0 => CrlStatus::NotRevoked,
1515             1 => {
1516                 assert!(!revoked_entry.is_null());
1517                 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1518             }
1519             2 => {
1520                 assert!(!revoked_entry.is_null());
1521                 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1522             }
1523             _ => unreachable!(
1524                 "{}",
1525                 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1526             ),
1527         }
1528     }
1529 }
1530 
1531 impl X509Crl {
1532     from_pem! {
1533         /// Deserializes a PEM-encoded Certificate Revocation List
1534         ///
1535         /// The input should have a header of `-----BEGIN X509 CRL-----`.
1536         #[corresponds(PEM_read_bio_X509_CRL)]
1537         from_pem,
1538         X509Crl,
1539         ffi::PEM_read_bio_X509_CRL
1540     }
1541 
1542     from_der! {
1543         /// Deserializes a DER-encoded Certificate Revocation List
1544         #[corresponds(d2i_X509_CRL)]
1545         from_der,
1546         X509Crl,
1547         ffi::d2i_X509_CRL
1548     }
1549 }
1550 
1551 impl X509CrlRef {
1552     to_pem! {
1553         /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
1554         ///
1555         /// The output will have a header of `-----BEGIN X509 CRL-----`.
1556         #[corresponds(PEM_write_bio_X509_CRL)]
1557         to_pem,
1558         ffi::PEM_write_bio_X509_CRL
1559     }
1560 
1561     to_der! {
1562         /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
1563         #[corresponds(i2d_X509_CRL)]
1564         to_der,
1565         ffi::i2d_X509_CRL
1566     }
1567 
1568     /// Get the stack of revocation entries
get_revoked(&self) -> Option<&StackRef<X509Revoked>>1569     pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
1570         unsafe {
1571             let revoked = X509_CRL_get_REVOKED(self.as_ptr());
1572             if revoked.is_null() {
1573                 None
1574             } else {
1575                 Some(StackRef::from_ptr(revoked))
1576             }
1577         }
1578     }
1579 
1580     /// Returns the CRL's `lastUpdate` time.
1581     #[corresponds(X509_CRL_get0_lastUpdate)]
last_update(&self) -> &Asn1TimeRef1582     pub fn last_update(&self) -> &Asn1TimeRef {
1583         unsafe {
1584             let date = X509_CRL_get0_lastUpdate(self.as_ptr());
1585             assert!(!date.is_null());
1586             Asn1TimeRef::from_ptr(date as *mut _)
1587         }
1588     }
1589 
1590     /// Returns the CRL's `nextUpdate` time.
1591     ///
1592     /// If the `nextUpdate` field is missing, returns `None`.
1593     #[corresponds(X509_CRL_get0_nextUpdate)]
next_update(&self) -> Option<&Asn1TimeRef>1594     pub fn next_update(&self) -> Option<&Asn1TimeRef> {
1595         unsafe {
1596             let date = X509_CRL_get0_nextUpdate(self.as_ptr());
1597             Asn1TimeRef::from_const_ptr_opt(date)
1598         }
1599     }
1600 
1601     /// Get the revocation status of a certificate by its serial number
1602     #[corresponds(X509_CRL_get0_by_serial)]
get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a>1603     pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
1604         unsafe {
1605             let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1606             let status =
1607                 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
1608             CrlStatus::from_ffi_status(status, ret)
1609         }
1610     }
1611 
1612     /// Get the revocation status of a certificate
1613     #[corresponds(X509_CRL_get0_by_cert)]
get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a>1614     pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
1615         unsafe {
1616             let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1617             let status =
1618                 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
1619             CrlStatus::from_ffi_status(status, ret)
1620         }
1621     }
1622 
1623     /// Get the issuer name from the revocation list.
1624     #[corresponds(X509_CRL_get_issuer)]
issuer_name(&self) -> &X509NameRef1625     pub fn issuer_name(&self) -> &X509NameRef {
1626         unsafe {
1627             let name = X509_CRL_get_issuer(self.as_ptr());
1628             assert!(!name.is_null());
1629             X509NameRef::from_ptr(name)
1630         }
1631     }
1632 
1633     /// Check if the CRL is signed using the given public key.
1634     ///
1635     /// Only the signature is checked: no other checks (such as certificate chain validity)
1636     /// are performed.
1637     ///
1638     /// Returns `true` if verification succeeds.
1639     #[corresponds(X509_CRL_verify)]
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1640     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1641     where
1642         T: HasPublic,
1643     {
1644         unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1645     }
1646 }
1647 
1648 /// The result of peer certificate verification.
1649 #[derive(Copy, Clone, PartialEq, Eq)]
1650 pub struct X509VerifyResult(c_int);
1651 
1652 impl fmt::Debug for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1653     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1654         fmt.debug_struct("X509VerifyResult")
1655             .field("code", &self.0)
1656             .field("error", &self.error_string())
1657             .finish()
1658     }
1659 }
1660 
1661 impl fmt::Display for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1662     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1663         fmt.write_str(self.error_string())
1664     }
1665 }
1666 
1667 impl Error for X509VerifyResult {}
1668 
1669 impl X509VerifyResult {
1670     /// Creates an `X509VerifyResult` from a raw error number.
1671     ///
1672     /// # Safety
1673     ///
1674     /// Some methods on `X509VerifyResult` are not thread safe if the error
1675     /// number is invalid.
from_raw(err: c_int) -> X509VerifyResult1676     pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1677         X509VerifyResult(err)
1678     }
1679 
1680     /// Return the integer representation of an `X509VerifyResult`.
1681     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int1682     pub fn as_raw(&self) -> c_int {
1683         self.0
1684     }
1685 
1686     /// Return a human readable error string from the verification error.
1687     ///
1688     /// This corresponds to [`X509_verify_cert_error_string`].
1689     ///
1690     /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html
1691     #[allow(clippy::trivially_copy_pass_by_ref)]
error_string(&self) -> &'static str1692     pub fn error_string(&self) -> &'static str {
1693         ffi::init();
1694 
1695         unsafe {
1696             let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1697             str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1698         }
1699     }
1700 
1701     /// Successful peer certificate verification.
1702     pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1703     /// Application verification failure.
1704     pub const APPLICATION_VERIFICATION: X509VerifyResult =
1705         X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1706 }
1707 
1708 foreign_type_and_impl_send_sync! {
1709     type CType = ffi::GENERAL_NAME;
1710     fn drop = ffi::GENERAL_NAME_free;
1711 
1712     /// An `X509` certificate alternative names.
1713     pub struct GeneralName;
1714     /// Reference to `GeneralName`.
1715     pub struct GeneralNameRef;
1716 }
1717 
1718 impl GeneralNameRef {
ia5_string(&self, ffi_type: c_int) -> Option<&str>1719     fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1720         unsafe {
1721             if (*self.as_ptr()).type_ != ffi_type {
1722                 return None;
1723             }
1724 
1725             #[cfg(boringssl)]
1726             let d = (*self.as_ptr()).d.ptr;
1727             #[cfg(not(boringssl))]
1728             let d = (*self.as_ptr()).d;
1729 
1730             let ptr = ASN1_STRING_get0_data(d as *mut _);
1731             let len = ffi::ASN1_STRING_length(d as *mut _);
1732 
1733             let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
1734             // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1735             // OpenSSL checks that when loading a certificate but if not we'll
1736             // use this instead of from_utf8_unchecked just in case.
1737             str::from_utf8(slice).ok()
1738         }
1739     }
1740 
1741     /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
email(&self) -> Option<&str>1742     pub fn email(&self) -> Option<&str> {
1743         self.ia5_string(ffi::GEN_EMAIL)
1744     }
1745 
1746     /// Returns the contents of this `GeneralName` if it is a `dNSName`.
dnsname(&self) -> Option<&str>1747     pub fn dnsname(&self) -> Option<&str> {
1748         self.ia5_string(ffi::GEN_DNS)
1749     }
1750 
1751     /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
uri(&self) -> Option<&str>1752     pub fn uri(&self) -> Option<&str> {
1753         self.ia5_string(ffi::GEN_URI)
1754     }
1755 
1756     /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
ipaddress(&self) -> Option<&[u8]>1757     pub fn ipaddress(&self) -> Option<&[u8]> {
1758         unsafe {
1759             if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1760                 return None;
1761             }
1762             #[cfg(boringssl)]
1763             let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
1764             #[cfg(not(boringssl))]
1765             let d = (*self.as_ptr()).d;
1766 
1767             let ptr = ASN1_STRING_get0_data(d as *mut _);
1768             let len = ffi::ASN1_STRING_length(d as *mut _);
1769 
1770             Some(slice::from_raw_parts(ptr as *const u8, len as usize))
1771         }
1772     }
1773 }
1774 
1775 impl fmt::Debug for GeneralNameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1776     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1777         if let Some(email) = self.email() {
1778             formatter.write_str(email)
1779         } else if let Some(dnsname) = self.dnsname() {
1780             formatter.write_str(dnsname)
1781         } else if let Some(uri) = self.uri() {
1782             formatter.write_str(uri)
1783         } else if let Some(ipaddress) = self.ipaddress() {
1784             let address = <[u8; 16]>::try_from(ipaddress)
1785                 .map(IpAddr::from)
1786                 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
1787             match address {
1788                 Ok(a) => fmt::Debug::fmt(&a, formatter),
1789                 Err(_) => fmt::Debug::fmt(ipaddress, formatter),
1790             }
1791         } else {
1792             formatter.write_str("(empty)")
1793         }
1794     }
1795 }
1796 
1797 impl Stackable for GeneralName {
1798     type StackType = ffi::stack_st_GENERAL_NAME;
1799 }
1800 
1801 foreign_type_and_impl_send_sync! {
1802     type CType = ffi::ACCESS_DESCRIPTION;
1803     fn drop = ffi::ACCESS_DESCRIPTION_free;
1804 
1805     /// `AccessDescription` of certificate authority information.
1806     pub struct AccessDescription;
1807     /// Reference to `AccessDescription`.
1808     pub struct AccessDescriptionRef;
1809 }
1810 
1811 impl AccessDescriptionRef {
1812     /// Returns the access method OID.
method(&self) -> &Asn1ObjectRef1813     pub fn method(&self) -> &Asn1ObjectRef {
1814         unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
1815     }
1816 
1817     // Returns the access location.
location(&self) -> &GeneralNameRef1818     pub fn location(&self) -> &GeneralNameRef {
1819         unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
1820     }
1821 }
1822 
1823 impl Stackable for AccessDescription {
1824     type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
1825 }
1826 
1827 foreign_type_and_impl_send_sync! {
1828     type CType = ffi::X509_ALGOR;
1829     fn drop = ffi::X509_ALGOR_free;
1830 
1831     /// An `X509` certificate signature algorithm.
1832     pub struct X509Algorithm;
1833     /// Reference to `X509Algorithm`.
1834     pub struct X509AlgorithmRef;
1835 }
1836 
1837 impl X509AlgorithmRef {
1838     /// Returns the ASN.1 OID of this algorithm.
object(&self) -> &Asn1ObjectRef1839     pub fn object(&self) -> &Asn1ObjectRef {
1840         unsafe {
1841             let mut oid = ptr::null();
1842             X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1843             Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
1844         }
1845     }
1846 }
1847 
1848 foreign_type_and_impl_send_sync! {
1849     type CType = ffi::X509_OBJECT;
1850     fn drop = X509_OBJECT_free;
1851 
1852     /// An `X509` or an X509 certificate revocation list.
1853     pub struct X509Object;
1854     /// Reference to `X509Object`
1855     pub struct X509ObjectRef;
1856 }
1857 
1858 impl X509ObjectRef {
x509(&self) -> Option<&X509Ref>1859     pub fn x509(&self) -> Option<&X509Ref> {
1860         unsafe {
1861             let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1862             X509Ref::from_const_ptr_opt(ptr)
1863         }
1864     }
1865 }
1866 
1867 impl Stackable for X509Object {
1868     type StackType = ffi::stack_st_X509_OBJECT;
1869 }
1870 
1871 cfg_if! {
1872     if #[cfg(any(boringssl, ossl110, libressl273))] {
1873         use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
1874     } else {
1875         #[allow(bad_style)]
1876         unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1877             (*(*(*x).cert_info).validity).notAfter
1878         }
1879 
1880         #[allow(bad_style)]
1881         unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1882             (*(*(*x).cert_info).validity).notBefore
1883         }
1884 
1885         #[allow(bad_style)]
1886         unsafe fn X509_up_ref(x: *mut ffi::X509) {
1887             ffi::CRYPTO_add_lock(
1888                 &mut (*x).references,
1889                 1,
1890                 ffi::CRYPTO_LOCK_X509,
1891                 "mod.rs\0".as_ptr() as *const _,
1892                 line!() as c_int,
1893             );
1894         }
1895 
1896         #[allow(bad_style)]
1897         unsafe fn X509_get0_signature(
1898             psig: *mut *const ffi::ASN1_BIT_STRING,
1899             palg: *mut *const ffi::X509_ALGOR,
1900             x: *const ffi::X509,
1901         ) {
1902             if !psig.is_null() {
1903                 *psig = (*x).signature;
1904             }
1905             if !palg.is_null() {
1906                 *palg = (*x).sig_alg;
1907             }
1908         }
1909     }
1910 }
1911 
1912 cfg_if! {
1913     if #[cfg(any(boringssl, ossl110, libressl350))] {
1914         use ffi::{
1915             X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
1916             X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
1917         };
1918     } else {
1919         use ffi::{
1920             ASN1_STRING_data as ASN1_STRING_get0_data,
1921             X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
1922             X509_set_notAfter as X509_set1_notAfter,
1923             X509_set_notBefore as X509_set1_notBefore,
1924         };
1925 
1926         #[allow(bad_style)]
1927         unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
1928             ffi::ASN1_INTEGER_get((*(*x).req_info).version)
1929         }
1930 
1931         #[allow(bad_style)]
1932         unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
1933             (*(*x).req_info).subject
1934         }
1935 
1936         #[allow(bad_style)]
1937         unsafe fn X509_ALGOR_get0(
1938             paobj: *mut *const ffi::ASN1_OBJECT,
1939             pptype: *mut c_int,
1940             pval: *mut *mut ::libc::c_void,
1941             alg: *const ffi::X509_ALGOR,
1942         ) {
1943             if !paobj.is_null() {
1944                 *paobj = (*alg).algorithm;
1945             }
1946             assert!(pptype.is_null());
1947             assert!(pval.is_null());
1948         }
1949     }
1950 }
1951 
1952 cfg_if! {
1953     if #[cfg(any(ossl110, boringssl, libressl270))] {
1954         use ffi::X509_OBJECT_get0_X509;
1955     } else {
1956         #[allow(bad_style)]
1957         unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
1958             if (*x).type_ == ffi::X509_LU_X509 {
1959                 (*x).data.x509
1960             } else {
1961                 ptr::null_mut()
1962             }
1963         }
1964     }
1965 }
1966 
1967 cfg_if! {
1968     if #[cfg(any(ossl110, libressl350))] {
1969         use ffi::X509_OBJECT_free;
1970     } else if #[cfg(boringssl)] {
1971         use ffi::X509_OBJECT_free_contents as X509_OBJECT_free;
1972     } else {
1973         #[allow(bad_style)]
1974         unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1975             ffi::X509_OBJECT_free_contents(x);
1976             ffi::CRYPTO_free(x as *mut libc::c_void);
1977         }
1978     }
1979 }
1980 
1981 cfg_if! {
1982     if #[cfg(any(ossl110, libressl350, boringssl))] {
1983         use ffi::{
1984             X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
1985             X509_CRL_get_REVOKED,
1986             X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
1987         };
1988     } else {
1989         #[allow(bad_style)]
1990         unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
1991             (*(*x).crl).lastUpdate
1992         }
1993         #[allow(bad_style)]
1994         unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
1995             (*(*x).crl).nextUpdate
1996         }
1997         #[allow(bad_style)]
1998         unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
1999             (*(*x).crl).issuer
2000         }
2001         #[allow(bad_style)]
2002         unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2003             (*(*x).crl).revoked
2004         }
2005         #[allow(bad_style)]
2006         unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2007             (*x).serialNumber
2008         }
2009         #[allow(bad_style)]
2010         unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2011             (*x).revocationDate
2012         }
2013     }
2014 }
2015 
2016 #[derive(Copy, Clone, PartialEq, Eq)]
2017 pub struct X509PurposeId(c_int);
2018 
2019 impl X509PurposeId {
2020     pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2021     pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2022     pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2023     pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2024     pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2025     pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2026     pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2027     pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2028     pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2029 
2030     /// Constructs an `X509PurposeId` from a raw OpenSSL value.
from_raw(id: c_int) -> Self2031     pub fn from_raw(id: c_int) -> Self {
2032         X509PurposeId(id)
2033     }
2034 
2035     /// Returns the raw OpenSSL value represented by this type.
as_raw(&self) -> c_int2036     pub fn as_raw(&self) -> c_int {
2037         self.0
2038     }
2039 }
2040 
2041 /// A reference to an [`X509_PURPOSE`].
2042 pub struct X509PurposeRef(Opaque);
2043 
2044 /// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2045 impl ForeignTypeRef for X509PurposeRef {
2046     type CType = ffi::X509_PURPOSE;
2047 }
2048 
2049 impl X509PurposeRef {
2050     /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2051     /// names include
2052     ///  - "sslclient",
2053     ///  - "sslserver",
2054     ///  - "nssslserver",
2055     ///  - "smimesign",
2056     ///  - "smimeencrypt",
2057     ///  - "crlsign",
2058     ///  - "any",
2059     ///  - "ocsphelper",
2060     ///  - "timestampsign"
2061     /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2062     #[allow(clippy::unnecessary_cast)]
get_by_sname(sname: &str) -> Result<c_int, ErrorStack>2063     pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2064         unsafe {
2065             let sname = CString::new(sname).unwrap();
2066             cfg_if! {
2067                 if #[cfg(any(ossl110, libressl280))] {
2068                     let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2069                 } else {
2070                     let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2071                 }
2072             }
2073             Ok(purpose)
2074         }
2075     }
2076     /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2077     /// `X509PurposeRef::get_by_sname()`.
2078     #[corresponds(X509_PURPOSE_get0)]
from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack>2079     pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2080         unsafe {
2081             let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?;
2082             Ok(X509PurposeRef::from_ptr(ptr))
2083         }
2084     }
2085 
2086     /// Get the purpose value from an X509Purpose structure. This value is one of
2087     /// - `X509_PURPOSE_SSL_CLIENT`
2088     /// - `X509_PURPOSE_SSL_SERVER`
2089     /// - `X509_PURPOSE_NS_SSL_SERVER`
2090     /// - `X509_PURPOSE_SMIME_SIGN`
2091     /// - `X509_PURPOSE_SMIME_ENCRYPT`
2092     /// - `X509_PURPOSE_CRL_SIGN`
2093     /// - `X509_PURPOSE_ANY`
2094     /// - `X509_PURPOSE_OCSP_HELPER`
2095     /// - `X509_PURPOSE_TIMESTAMP_SIGN`
purpose(&self) -> X509PurposeId2096     pub fn purpose(&self) -> X509PurposeId {
2097         unsafe {
2098             let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr();
2099             X509PurposeId::from_raw((*x509_purpose).purpose)
2100         }
2101     }
2102 }
2103