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 ffi;
11 use foreign_types::{ForeignType, ForeignTypeRef};
12 use libc::{c_int, c_long};
13 use std::error::Error;
14 use std::ffi::{CStr, CString};
15 use std::fmt;
16 use std::marker::PhantomData;
17 use std::mem;
18 use std::path::Path;
19 use std::ptr;
20 use std::slice;
21 use std::str;
22 
23 use asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef};
24 use bio::MemBioSlice;
25 use conf::ConfRef;
26 use error::ErrorStack;
27 use ex_data::Index;
28 use hash::{DigestBytes, MessageDigest};
29 use nid::Nid;
30 use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
31 use ssl::SslRef;
32 use stack::{Stack, StackRef, Stackable};
33 use string::OpensslString;
34 use util::{ForeignTypeExt, ForeignTypeRefExt};
35 use {cvt, cvt_n, cvt_p};
36 
37 #[cfg(any(ossl102, libressl261))]
38 pub mod verify;
39 
40 pub mod extension;
41 pub mod store;
42 
43 #[cfg(test)]
44 mod tests;
45 
46 foreign_type_and_impl_send_sync! {
47     type CType = ffi::X509_STORE_CTX;
48     fn drop = ffi::X509_STORE_CTX_free;
49 
50     /// An `X509` certificate store context.
51     pub struct X509StoreContext;
52 
53     /// Reference to `X509StoreContext`.
54     pub struct X509StoreContextRef;
55 }
56 
57 impl X509StoreContext {
58     /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
59     /// context.
ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>60     pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
61         unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
62     }
63 
64     /// Creates a new `X509StoreContext` instance.
65     ///
66     /// This corresponds to [`X509_STORE_CTX_new`].
67     ///
68     /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html
new() -> Result<X509StoreContext, ErrorStack>69     pub fn new() -> Result<X509StoreContext, ErrorStack> {
70         unsafe {
71             ffi::init();
72             cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
73         }
74     }
75 }
76 
77 impl X509StoreContextRef {
78     /// Returns application data pertaining to an `X509` store context.
79     ///
80     /// This corresponds to [`X509_STORE_CTX_get_ex_data`].
81     ///
82     /// [`X509_STORE_CTX_get_ex_data`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_ex_data.html
ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>83     pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
84         unsafe {
85             let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
86             if data.is_null() {
87                 None
88             } else {
89                 Some(&*(data as *const T))
90             }
91         }
92     }
93 
94     /// Returns the error code of the context.
95     ///
96     /// This corresponds to [`X509_STORE_CTX_get_error`].
97     ///
98     /// [`X509_STORE_CTX_get_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error.html
error(&self) -> X509VerifyResult99     pub fn error(&self) -> X509VerifyResult {
100         unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
101     }
102 
103     /// Initializes this context with the given certificate, certificates chain and certificate
104     /// store. After initializing the context, the `with_context` closure is called with the prepared
105     /// context. As long as the closure is running, the context stays initialized and can be used
106     /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
107     ///
108     /// * `trust` - The certificate store with the trusted certificates.
109     /// * `cert` - The certificate that should be verified.
110     /// * `cert_chain` - The certificates chain.
111     /// * `with_context` - The closure that is called with the initialized context.
112     ///
113     /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
114     /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
115     ///
116     /// [`X509_STORE_CTX_init`]:  https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html
117     /// [`X509_STORE_CTX_cleanup`]:  https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
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>,118     pub fn init<F, T>(
119         &mut self,
120         trust: &store::X509StoreRef,
121         cert: &X509Ref,
122         cert_chain: &StackRef<X509>,
123         with_context: F,
124     ) -> Result<T, ErrorStack>
125     where
126         F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
127     {
128         struct Cleanup<'a>(&'a mut X509StoreContextRef);
129 
130         impl<'a> Drop for Cleanup<'a> {
131             fn drop(&mut self) {
132                 unsafe {
133                     ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
134                 }
135             }
136         }
137 
138         unsafe {
139             cvt(ffi::X509_STORE_CTX_init(
140                 self.as_ptr(),
141                 trust.as_ptr(),
142                 cert.as_ptr(),
143                 cert_chain.as_ptr(),
144             ))?;
145 
146             let cleanup = Cleanup(self);
147             with_context(cleanup.0)
148         }
149     }
150 
151     /// Verifies the stored certificate.
152     ///
153     /// Returns `true` if verification succeeds. The `error` method will return the specific
154     /// validation error if the certificate was not valid.
155     ///
156     /// This will only work inside of a call to `init`.
157     ///
158     /// This corresponds to [`X509_verify_cert`].
159     ///
160     /// [`X509_verify_cert`]:  https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html
verify_cert(&mut self) -> Result<bool, ErrorStack>161     pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
162         unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
163     }
164 
165     /// Set the error code of the context.
166     ///
167     /// This corresponds to [`X509_STORE_CTX_set_error`].
168     ///
169     /// [`X509_STORE_CTX_set_error`]:  https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_set_error.html
set_error(&mut self, result: X509VerifyResult)170     pub fn set_error(&mut self, result: X509VerifyResult) {
171         unsafe {
172             ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
173         }
174     }
175 
176     /// Returns a reference to the certificate which caused the error or None if
177     /// no certificate is relevant to the error.
178     ///
179     /// This corresponds to [`X509_STORE_CTX_get_current_cert`].
180     ///
181     /// [`X509_STORE_CTX_get_current_cert`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_current_cert.html
current_cert(&self) -> Option<&X509Ref>182     pub fn current_cert(&self) -> Option<&X509Ref> {
183         unsafe {
184             let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
185             X509Ref::from_const_ptr_opt(ptr)
186         }
187     }
188 
189     /// Returns a non-negative integer representing the depth in the certificate
190     /// chain where the error occurred. If it is zero it occurred in the end
191     /// entity certificate, one if it is the certificate which signed the end
192     /// entity certificate and so on.
193     ///
194     /// This corresponds to [`X509_STORE_CTX_get_error_depth`].
195     ///
196     /// [`X509_STORE_CTX_get_error_depth`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error_depth.html
error_depth(&self) -> u32197     pub fn error_depth(&self) -> u32 {
198         unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
199     }
200 
201     /// Returns a reference to a complete valid `X509` certificate chain.
202     ///
203     /// This corresponds to [`X509_STORE_CTX_get0_chain`].
204     ///
205     /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html
chain(&self) -> Option<&StackRef<X509>>206     pub fn chain(&self) -> Option<&StackRef<X509>> {
207         unsafe {
208             let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
209 
210             if chain.is_null() {
211                 None
212             } else {
213                 Some(StackRef::from_ptr(chain))
214             }
215         }
216     }
217 }
218 
219 /// A builder used to construct an `X509`.
220 pub struct X509Builder(X509);
221 
222 impl X509Builder {
223     /// Creates a new builder.
new() -> Result<X509Builder, ErrorStack>224     pub fn new() -> Result<X509Builder, ErrorStack> {
225         unsafe {
226             ffi::init();
227             cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
228         }
229     }
230 
231     /// Sets the notAfter constraint on the certificate.
set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>232     pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
233         unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
234     }
235 
236     /// Sets the notBefore constraint on the certificate.
set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>237     pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
238         unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
239     }
240 
241     /// Sets the version of the certificate.
242     ///
243     /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
244     /// the X.509 standard should pass `2` to this method.
set_version(&mut self, version: i32) -> Result<(), ErrorStack>245     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
246         unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
247     }
248 
249     /// Sets the serial number of the certificate.
set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>250     pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
251         unsafe {
252             cvt(ffi::X509_set_serialNumber(
253                 self.0.as_ptr(),
254                 serial_number.as_ptr(),
255             ))
256             .map(|_| ())
257         }
258     }
259 
260     /// Sets the issuer name of the certificate.
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     /// ```
set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>289     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
290         unsafe {
291             cvt(ffi::X509_set_subject_name(
292                 self.0.as_ptr(),
293                 subject_name.as_ptr(),
294             ))
295             .map(|_| ())
296         }
297     }
298 
299     /// Sets the public key associated with the certificate.
set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,300     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
301     where
302         T: HasPublic,
303     {
304         unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
305     }
306 
307     /// Returns a context object which is needed to create certain X509 extension values.
308     ///
309     /// Set `issuer` to `None` if the certificate will be self-signed.
x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>310     pub fn x509v3_context<'a>(
311         &'a self,
312         issuer: Option<&'a X509Ref>,
313         conf: Option<&'a ConfRef>,
314     ) -> X509v3Context<'a> {
315         unsafe {
316             let mut ctx = mem::zeroed();
317 
318             let issuer = match issuer {
319                 Some(issuer) => issuer.as_ptr(),
320                 None => self.0.as_ptr(),
321             };
322             let subject = self.0.as_ptr();
323             ffi::X509V3_set_ctx(
324                 &mut ctx,
325                 issuer,
326                 subject,
327                 ptr::null_mut(),
328                 ptr::null_mut(),
329                 0,
330             );
331 
332             // nodb case taken care of since we zeroed ctx above
333             if let Some(conf) = conf {
334                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
335             }
336 
337             X509v3Context(ctx, PhantomData)
338         }
339     }
340 
341     /// Adds an X509 extension value to the certificate.
342     ///
343     /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>344     pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
345         self.append_extension2(&extension)
346     }
347 
348     /// Adds an X509 extension value to the certificate.
349     ///
350     /// This corresponds to [`X509_add_ext`].
351     ///
352     /// [`X509_add_ext`]: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html
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.
sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,361     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
362     where
363         T: HasPrivate,
364     {
365         unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
366     }
367 
368     /// Consumes the builder, returning the certificate.
build(self) -> X509369     pub fn build(self) -> X509 {
370         self.0
371     }
372 }
373 
374 foreign_type_and_impl_send_sync! {
375     type CType = ffi::X509;
376     fn drop = ffi::X509_free;
377 
378     /// An `X509` public key certificate.
379     pub struct X509;
380     /// Reference to `X509`.
381     pub struct X509Ref;
382 }
383 
384 impl X509Ref {
385     /// Returns this certificate's subject name.
386     ///
387     /// This corresponds to [`X509_get_subject_name`].
388     ///
389     /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html
subject_name(&self) -> &X509NameRef390     pub fn subject_name(&self) -> &X509NameRef {
391         unsafe {
392             let name = ffi::X509_get_subject_name(self.as_ptr());
393             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
394         }
395     }
396 
397     /// Returns the hash of the certificates subject
398     ///
399     /// This corresponds to `X509_subject_name_hash`.
subject_name_hash(&self) -> u32400     pub fn subject_name_hash(&self) -> u32 {
401         unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
402     }
403 
404     /// Returns this certificate's issuer name.
405     ///
406     /// This corresponds to [`X509_get_issuer_name`].
407     ///
408     /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html
issuer_name(&self) -> &X509NameRef409     pub fn issuer_name(&self) -> &X509NameRef {
410         unsafe {
411             let name = ffi::X509_get_issuer_name(self.as_ptr());
412             X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
413         }
414     }
415 
416     /// Returns this certificate's subject alternative name entries, if they exist.
417     ///
418     /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`.
419     ///
420     /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html
subject_alt_names(&self) -> Option<Stack<GeneralName>>421     pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
422         unsafe {
423             let stack = ffi::X509_get_ext_d2i(
424                 self.as_ptr(),
425                 ffi::NID_subject_alt_name,
426                 ptr::null_mut(),
427                 ptr::null_mut(),
428             );
429             Stack::from_ptr_opt(stack as *mut _)
430         }
431     }
432 
433     /// Returns this certificate's issuer alternative name entries, if they exist.
434     ///
435     /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`.
436     ///
437     /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html
issuer_alt_names(&self) -> Option<Stack<GeneralName>>438     pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
439         unsafe {
440             let stack = ffi::X509_get_ext_d2i(
441                 self.as_ptr(),
442                 ffi::NID_issuer_alt_name,
443                 ptr::null_mut(),
444                 ptr::null_mut(),
445             );
446             Stack::from_ptr_opt(stack as *mut _)
447         }
448     }
449 
public_key(&self) -> Result<PKey<Public>, ErrorStack>450     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
451         unsafe {
452             let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
453             Ok(PKey::from_ptr(pkey))
454         }
455     }
456 
457     /// Returns a digest of the DER representation of the certificate.
458     ///
459     /// This corresponds to [`X509_digest`].
460     ///
461     /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html
digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>462     pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
463         unsafe {
464             let mut digest = DigestBytes {
465                 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
466                 len: ffi::EVP_MAX_MD_SIZE as usize,
467             };
468             let mut len = ffi::EVP_MAX_MD_SIZE;
469             cvt(ffi::X509_digest(
470                 self.as_ptr(),
471                 hash_type.as_ptr(),
472                 digest.buf.as_mut_ptr() as *mut _,
473                 &mut len,
474             ))?;
475             digest.len = len as usize;
476 
477             Ok(digest)
478         }
479     }
480 
481     #[deprecated(since = "0.10.9", note = "renamed to digest")]
fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>482     pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
483         self.digest(hash_type).map(|b| b.to_vec())
484     }
485 
486     /// Returns the certificate's Not After validity period.
not_after(&self) -> &Asn1TimeRef487     pub fn not_after(&self) -> &Asn1TimeRef {
488         unsafe {
489             let date = X509_getm_notAfter(self.as_ptr());
490             Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
491         }
492     }
493 
494     /// Returns the certificate's Not Before validity period.
not_before(&self) -> &Asn1TimeRef495     pub fn not_before(&self) -> &Asn1TimeRef {
496         unsafe {
497             let date = X509_getm_notBefore(self.as_ptr());
498             Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
499         }
500     }
501 
502     /// Returns the certificate's signature
signature(&self) -> &Asn1BitStringRef503     pub fn signature(&self) -> &Asn1BitStringRef {
504         unsafe {
505             let mut signature = ptr::null();
506             X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
507             Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
508         }
509     }
510 
511     /// Returns the certificate's signature algorithm.
signature_algorithm(&self) -> &X509AlgorithmRef512     pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
513         unsafe {
514             let mut algor = ptr::null();
515             X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
516             X509AlgorithmRef::from_const_ptr_opt(algor)
517                 .expect("signature algorithm must not be null")
518         }
519     }
520 
521     /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
522     /// Access field.
ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>523     pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
524         unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
525     }
526 
527     /// Checks that this certificate issued `subject`.
issued(&self, subject: &X509Ref) -> X509VerifyResult528     pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
529         unsafe {
530             let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
531             X509VerifyResult::from_raw(r)
532         }
533     }
534 
535     /// Returns certificate version. If this certificate has no explicit version set, it defaults to
536     /// version 1.
537     ///
538     /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
539     ///
540     /// This corresponds to [`X509_get_version`].
541     ///
542     /// [`X509_get_version`]: https://www.openssl.org/docs/man1.1.1/man3/X509_get_version.html
543     #[cfg(ossl110)]
version(&self) -> i32544     pub fn version(&self) -> i32 {
545         // Covered with `x509_ref_version()`, `x509_ref_version_no_version_set()` tests
546         unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
547     }
548 
549     /// Check if the certificate is signed using the given public key.
550     ///
551     /// Only the signature is checked: no other checks (such as certificate chain validity)
552     /// are performed.
553     ///
554     /// Returns `true` if verification succeeds.
555     ///
556     /// This corresponds to [`X509_verify"].
557     ///
558     /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,559     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
560     where
561         T: HasPublic,
562     {
563         unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
564     }
565 
566     /// Returns this certificate's serial number.
567     ///
568     /// This corresponds to [`X509_get_serialNumber`].
569     ///
570     /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html
serial_number(&self) -> &Asn1IntegerRef571     pub fn serial_number(&self) -> &Asn1IntegerRef {
572         unsafe {
573             let r = ffi::X509_get_serialNumber(self.as_ptr());
574             Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
575         }
576     }
577 
578     to_pem! {
579         /// Serializes the certificate into a PEM-encoded X509 structure.
580         ///
581         /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
582         ///
583         /// This corresponds to [`PEM_write_bio_X509`].
584         ///
585         /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html
586         to_pem,
587         ffi::PEM_write_bio_X509
588     }
589 
590     to_der! {
591         /// Serializes the certificate into a DER-encoded X509 structure.
592         ///
593         /// This corresponds to [`i2d_X509`].
594         ///
595         /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html
596         to_der,
597         ffi::i2d_X509
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 X509 {
613     /// Returns a new builder.
builder() -> Result<X509Builder, ErrorStack>614     pub fn builder() -> Result<X509Builder, ErrorStack> {
615         X509Builder::new()
616     }
617 
618     from_pem! {
619         /// Deserializes a PEM-encoded X509 structure.
620         ///
621         /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
622         ///
623         /// This corresponds to [`PEM_read_bio_X509`].
624         ///
625         /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html
626         from_pem,
627         X509,
628         ffi::PEM_read_bio_X509
629     }
630 
631     from_der! {
632         /// Deserializes a DER-encoded X509 structure.
633         ///
634         /// This corresponds to [`d2i_X509`].
635         ///
636         /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html
637         from_der,
638         X509,
639         ffi::d2i_X509
640     }
641 
642     /// Deserializes a list of PEM-formatted certificates.
stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>643     pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
644         unsafe {
645             ffi::init();
646             let bio = MemBioSlice::new(pem)?;
647 
648             let mut certs = vec![];
649             loop {
650                 let r =
651                     ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
652                 if r.is_null() {
653                     let err = ffi::ERR_peek_last_error();
654                     if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM
655                         && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
656                     {
657                         ffi::ERR_clear_error();
658                         break;
659                     }
660 
661                     return Err(ErrorStack::get());
662                 } else {
663                     certs.push(X509(r));
664                 }
665             }
666 
667             Ok(certs)
668         }
669     }
670 }
671 
672 impl Clone for X509 {
clone(&self) -> X509673     fn clone(&self) -> X509 {
674         X509Ref::to_owned(self)
675     }
676 }
677 
678 impl fmt::Debug for X509 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result679     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
680         let serial = match &self.serial_number().to_bn() {
681             Ok(bn) => match bn.to_hex_str() {
682                 Ok(hex) => hex.to_string(),
683                 Err(_) => "".to_string(),
684             },
685             Err(_) => "".to_string(),
686         };
687         let mut debug_struct = formatter.debug_struct("X509");
688         debug_struct.field("serial_number", &serial);
689         debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
690         debug_struct.field("issuer", &self.issuer_name());
691         debug_struct.field("subject", &self.subject_name());
692         if let Some(subject_alt_names) = &self.subject_alt_names() {
693             debug_struct.field("subject_alt_names", subject_alt_names);
694         }
695         debug_struct.field("not_before", &self.not_before());
696         debug_struct.field("not_after", &self.not_after());
697 
698         if let Ok(public_key) = &self.public_key() {
699             debug_struct.field("public_key", public_key);
700         };
701         // TODO: Print extensions once they are supported on the X509 struct.
702 
703         debug_struct.finish()
704     }
705 }
706 
707 impl AsRef<X509Ref> for X509Ref {
as_ref(&self) -> &X509Ref708     fn as_ref(&self) -> &X509Ref {
709         self
710     }
711 }
712 
713 impl Stackable for X509 {
714     type StackType = ffi::stack_st_X509;
715 }
716 
717 /// A context object required to construct certain `X509` extension values.
718 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
719 
720 impl<'a> X509v3Context<'a> {
as_ptr(&self) -> *mut ffi::X509V3_CTX721     pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
722         &self.0 as *const _ as *mut _
723     }
724 }
725 
726 foreign_type_and_impl_send_sync! {
727     type CType = ffi::X509_EXTENSION;
728     fn drop = ffi::X509_EXTENSION_free;
729 
730     /// Permit additional fields to be added to an `X509` v3 certificate.
731     pub struct X509Extension;
732     /// Reference to `X509Extension`.
733     pub struct X509ExtensionRef;
734 }
735 
736 impl Stackable for X509Extension {
737     type StackType = ffi::stack_st_X509_EXTENSION;
738 }
739 
740 impl X509Extension {
741     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
742     /// names and their value formats.
743     ///
744     /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
745     /// provided.
746     ///
747     /// 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>748     pub fn new(
749         conf: Option<&ConfRef>,
750         context: Option<&X509v3Context>,
751         name: &str,
752         value: &str,
753     ) -> Result<X509Extension, ErrorStack> {
754         let name = CString::new(name).unwrap();
755         let value = CString::new(value).unwrap();
756         unsafe {
757             ffi::init();
758             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
759             let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr);
760             let name = name.as_ptr() as *mut _;
761             let value = value.as_ptr() as *mut _;
762 
763             cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension)
764         }
765     }
766 
767     /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
768     /// extensions and their value formats.
769     ///
770     /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
771     /// be provided.
772     ///
773     /// 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>774     pub fn new_nid(
775         conf: Option<&ConfRef>,
776         context: Option<&X509v3Context>,
777         name: Nid,
778         value: &str,
779     ) -> Result<X509Extension, ErrorStack> {
780         let value = CString::new(value).unwrap();
781         unsafe {
782             ffi::init();
783             let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
784             let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr);
785             let name = name.as_raw();
786             let value = value.as_ptr() as *mut _;
787 
788             cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension)
789         }
790     }
791 }
792 
793 /// A builder used to construct an `X509Name`.
794 pub struct X509NameBuilder(X509Name);
795 
796 impl X509NameBuilder {
797     /// Creates a new builder.
new() -> Result<X509NameBuilder, ErrorStack>798     pub fn new() -> Result<X509NameBuilder, ErrorStack> {
799         unsafe {
800             ffi::init();
801             cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
802         }
803     }
804 
805     /// Add a field entry by str.
806     ///
807     /// This corresponds to [`X509_NAME_add_entry_by_txt`].
808     ///
809     /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html
append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack>810     pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
811         unsafe {
812             let field = CString::new(field).unwrap();
813             assert!(value.len() <= c_int::max_value() as usize);
814             cvt(ffi::X509_NAME_add_entry_by_txt(
815                 self.0.as_ptr(),
816                 field.as_ptr() as *mut _,
817                 ffi::MBSTRING_UTF8,
818                 value.as_ptr(),
819                 value.len() as c_int,
820                 -1,
821                 0,
822             ))
823             .map(|_| ())
824         }
825     }
826 
827     /// Add a field entry by NID.
828     ///
829     /// This corresponds to [`X509_NAME_add_entry_by_NID`].
830     ///
831     /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html
append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack>832     pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
833         unsafe {
834             assert!(value.len() <= c_int::max_value() as usize);
835             cvt(ffi::X509_NAME_add_entry_by_NID(
836                 self.0.as_ptr(),
837                 field.as_raw(),
838                 ffi::MBSTRING_UTF8,
839                 value.as_ptr() as *mut _,
840                 value.len() as c_int,
841                 -1,
842                 0,
843             ))
844             .map(|_| ())
845         }
846     }
847 
848     /// Return an `X509Name`.
build(self) -> X509Name849     pub fn build(self) -> X509Name {
850         self.0
851     }
852 }
853 
854 foreign_type_and_impl_send_sync! {
855     type CType = ffi::X509_NAME;
856     fn drop = ffi::X509_NAME_free;
857 
858     /// The names of an `X509` certificate.
859     pub struct X509Name;
860     /// Reference to `X509Name`.
861     pub struct X509NameRef;
862 }
863 
864 impl X509Name {
865     /// Returns a new builder.
builder() -> Result<X509NameBuilder, ErrorStack>866     pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
867         X509NameBuilder::new()
868     }
869 
870     /// Loads subject names from a file containing PEM-formatted certificates.
871     ///
872     /// 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>873     pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
874         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
875         unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
876     }
877 }
878 
879 impl Stackable for X509Name {
880     type StackType = ffi::stack_st_X509_NAME;
881 }
882 
883 impl X509NameRef {
884     /// Returns the name entries by the nid.
entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>885     pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
886         X509NameEntries {
887             name: self,
888             nid: Some(nid),
889             loc: -1,
890         }
891     }
892 
893     /// Returns an iterator over all `X509NameEntry` values
entries(&self) -> X509NameEntries<'_>894     pub fn entries(&self) -> X509NameEntries<'_> {
895         X509NameEntries {
896             name: self,
897             nid: None,
898             loc: -1,
899         }
900     }
901 }
902 
903 impl fmt::Debug for X509NameRef {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result904     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
905         formatter.debug_list().entries(self.entries()).finish()
906     }
907 }
908 
909 /// A type to destructure and examine an `X509Name`.
910 pub struct X509NameEntries<'a> {
911     name: &'a X509NameRef,
912     nid: Option<Nid>,
913     loc: c_int,
914 }
915 
916 impl<'a> Iterator for X509NameEntries<'a> {
917     type Item = &'a X509NameEntryRef;
918 
next(&mut self) -> Option<&'a X509NameEntryRef>919     fn next(&mut self) -> Option<&'a X509NameEntryRef> {
920         unsafe {
921             match self.nid {
922                 Some(nid) => {
923                     // There is a `Nid` specified to search for
924                     self.loc =
925                         ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
926                     if self.loc == -1 {
927                         return None;
928                     }
929                 }
930                 None => {
931                     // Iterate over all `Nid`s
932                     self.loc += 1;
933                     if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
934                         return None;
935                     }
936                 }
937             }
938 
939             let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
940 
941             Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
942         }
943     }
944 }
945 
946 foreign_type_and_impl_send_sync! {
947     type CType = ffi::X509_NAME_ENTRY;
948     fn drop = ffi::X509_NAME_ENTRY_free;
949 
950     /// A name entry associated with a `X509Name`.
951     pub struct X509NameEntry;
952     /// Reference to `X509NameEntry`.
953     pub struct X509NameEntryRef;
954 }
955 
956 impl X509NameEntryRef {
957     /// Returns the field value of an `X509NameEntry`.
958     ///
959     /// This corresponds to [`X509_NAME_ENTRY_get_data`].
960     ///
961     /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html
data(&self) -> &Asn1StringRef962     pub fn data(&self) -> &Asn1StringRef {
963         unsafe {
964             let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
965             Asn1StringRef::from_ptr(data)
966         }
967     }
968 
969     /// Returns the `Asn1Object` value of an `X509NameEntry`.
970     /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
971     ///
972     /// This corresponds to [`X509_NAME_ENTRY_get_object`].
973     ///
974     /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html
object(&self) -> &Asn1ObjectRef975     pub fn object(&self) -> &Asn1ObjectRef {
976         unsafe {
977             let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
978             Asn1ObjectRef::from_ptr(object)
979         }
980     }
981 }
982 
983 impl fmt::Debug for X509NameEntryRef {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result984     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
985         formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
986     }
987 }
988 
989 /// A builder used to construct an `X509Req`.
990 pub struct X509ReqBuilder(X509Req);
991 
992 impl X509ReqBuilder {
993     /// Returns a builder for a certificate request.
994     ///
995     /// This corresponds to [`X509_REQ_new`].
996     ///
997     ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html
new() -> Result<X509ReqBuilder, ErrorStack>998     pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
999         unsafe {
1000             ffi::init();
1001             cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1002         }
1003     }
1004 
1005     /// Set the numerical value of the version field.
1006     ///
1007     /// This corresponds to [`X509_REQ_set_version`].
1008     ///
1009     ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html
set_version(&mut self, version: i32) -> Result<(), ErrorStack>1010     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1011         unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
1012     }
1013 
1014     /// Set the issuer name.
1015     ///
1016     /// This corresponds to [`X509_REQ_set_subject_name`].
1017     ///
1018     /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html
set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>1019     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1020         unsafe {
1021             cvt(ffi::X509_REQ_set_subject_name(
1022                 self.0.as_ptr(),
1023                 subject_name.as_ptr(),
1024             ))
1025             .map(|_| ())
1026         }
1027     }
1028 
1029     /// Set the public key.
1030     ///
1031     /// This corresponds to [`X509_REQ_set_pubkey`].
1032     ///
1033     /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html
set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,1034     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1035     where
1036         T: HasPublic,
1037     {
1038         unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1039     }
1040 
1041     /// Return an `X509v3Context`. This context object can be used to construct
1042     /// certain `X509` extensions.
x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1043     pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1044         unsafe {
1045             let mut ctx = mem::zeroed();
1046 
1047             ffi::X509V3_set_ctx(
1048                 &mut ctx,
1049                 ptr::null_mut(),
1050                 ptr::null_mut(),
1051                 self.0.as_ptr(),
1052                 ptr::null_mut(),
1053                 0,
1054             );
1055 
1056             // nodb case taken care of since we zeroed ctx above
1057             if let Some(conf) = conf {
1058                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1059             }
1060 
1061             X509v3Context(ctx, PhantomData)
1062         }
1063     }
1064 
1065     /// Permits any number of extension fields to be added to the certificate.
add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1066     pub fn add_extensions(
1067         &mut self,
1068         extensions: &StackRef<X509Extension>,
1069     ) -> Result<(), ErrorStack> {
1070         unsafe {
1071             cvt(ffi::X509_REQ_add_extensions(
1072                 self.0.as_ptr(),
1073                 extensions.as_ptr(),
1074             ))
1075             .map(|_| ())
1076         }
1077     }
1078 
1079     /// Sign the request using a private key.
1080     ///
1081     /// This corresponds to [`X509_REQ_sign`].
1082     ///
1083     /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,1084     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1085     where
1086         T: HasPrivate,
1087     {
1088         unsafe {
1089             cvt(ffi::X509_REQ_sign(
1090                 self.0.as_ptr(),
1091                 key.as_ptr(),
1092                 hash.as_ptr(),
1093             ))
1094             .map(|_| ())
1095         }
1096     }
1097 
1098     /// Returns the `X509Req`.
build(self) -> X509Req1099     pub fn build(self) -> X509Req {
1100         self.0
1101     }
1102 }
1103 
1104 foreign_type_and_impl_send_sync! {
1105     type CType = ffi::X509_REQ;
1106     fn drop = ffi::X509_REQ_free;
1107 
1108     /// An `X509` certificate request.
1109     pub struct X509Req;
1110     /// Reference to `X509Req`.
1111     pub struct X509ReqRef;
1112 }
1113 
1114 impl X509Req {
1115     /// A builder for `X509Req`.
builder() -> Result<X509ReqBuilder, ErrorStack>1116     pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1117         X509ReqBuilder::new()
1118     }
1119 
1120     from_pem! {
1121         /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1122         ///
1123         /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1124         ///
1125         /// This corresponds to [`PEM_read_bio_X509_REQ`].
1126         ///
1127         /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html
1128         from_pem,
1129         X509Req,
1130         ffi::PEM_read_bio_X509_REQ
1131     }
1132 
1133     from_der! {
1134         /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1135         ///
1136         /// This corresponds to [`d2i_X509_REQ`].
1137         ///
1138         /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html
1139         from_der,
1140         X509Req,
1141         ffi::d2i_X509_REQ
1142     }
1143 }
1144 
1145 impl X509ReqRef {
1146     to_pem! {
1147         /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1148         ///
1149         /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1150         ///
1151         /// This corresponds to [`PEM_write_bio_X509_REQ`].
1152         ///
1153         /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html
1154         to_pem,
1155         ffi::PEM_write_bio_X509_REQ
1156     }
1157 
1158     to_der! {
1159         /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1160         ///
1161         /// This corresponds to [`i2d_X509_REQ`].
1162         ///
1163         /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html
1164         to_der,
1165         ffi::i2d_X509_REQ
1166     }
1167 
1168     /// Returns the numerical value of the version field of the certificate request.
1169     ///
1170     /// This corresponds to [`X509_REQ_get_version`]
1171     ///
1172     /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html
version(&self) -> i321173     pub fn version(&self) -> i32 {
1174         unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1175     }
1176 
1177     /// Returns the subject name of the certificate request.
1178     ///
1179     /// This corresponds to [`X509_REQ_get_subject_name`]
1180     ///
1181     /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html
subject_name(&self) -> &X509NameRef1182     pub fn subject_name(&self) -> &X509NameRef {
1183         unsafe {
1184             let name = X509_REQ_get_subject_name(self.as_ptr());
1185             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1186         }
1187     }
1188 
1189     /// Returns the public key of the certificate request.
1190     ///
1191     /// This corresponds to [`X509_REQ_get_pubkey"]
1192     ///
1193     /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html
public_key(&self) -> Result<PKey<Public>, ErrorStack>1194     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1195         unsafe {
1196             let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1197             Ok(PKey::from_ptr(key))
1198         }
1199     }
1200 
1201     /// Check if the certificate request is signed using the given public key.
1202     ///
1203     /// Returns `true` if verification succeeds.
1204     ///
1205     /// This corresponds to [`X509_REQ_verify"].
1206     ///
1207     /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html
verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1208     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1209     where
1210         T: HasPublic,
1211     {
1212         unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1213     }
1214 
1215     /// Returns the extensions of the certificate request.
1216     ///
1217     /// This corresponds to [`X509_REQ_get_extensions"]
extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1218     pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1219         unsafe {
1220             let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1221             Ok(Stack::from_ptr(extensions))
1222         }
1223     }
1224 }
1225 
1226 /// The result of peer certificate verification.
1227 #[derive(Copy, Clone, PartialEq, Eq)]
1228 pub struct X509VerifyResult(c_int);
1229 
1230 impl fmt::Debug for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result1231     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1232         fmt.debug_struct("X509VerifyResult")
1233             .field("code", &self.0)
1234             .field("error", &self.error_string())
1235             .finish()
1236     }
1237 }
1238 
1239 impl fmt::Display for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result1240     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1241         fmt.write_str(self.error_string())
1242     }
1243 }
1244 
1245 impl Error for X509VerifyResult {}
1246 
1247 impl X509VerifyResult {
1248     /// Creates an `X509VerifyResult` from a raw error number.
1249     ///
1250     /// # Safety
1251     ///
1252     /// Some methods on `X509VerifyResult` are not thread safe if the error
1253     /// number is invalid.
from_raw(err: c_int) -> X509VerifyResult1254     pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1255         X509VerifyResult(err)
1256     }
1257 
1258     /// Return the integer representation of an `X509VerifyResult`.
1259     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int1260     pub fn as_raw(&self) -> c_int {
1261         self.0
1262     }
1263 
1264     /// Return a human readable error string from the verification error.
1265     ///
1266     /// This corresponds to [`X509_verify_cert_error_string`].
1267     ///
1268     /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html
1269     #[allow(clippy::trivially_copy_pass_by_ref)]
error_string(&self) -> &'static str1270     pub fn error_string(&self) -> &'static str {
1271         ffi::init();
1272 
1273         unsafe {
1274             let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1275             str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1276         }
1277     }
1278 
1279     /// Successful peer certifiate verification.
1280     pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1281     /// Application verification failure.
1282     pub const APPLICATION_VERIFICATION: X509VerifyResult =
1283         X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1284 }
1285 
1286 foreign_type_and_impl_send_sync! {
1287     type CType = ffi::GENERAL_NAME;
1288     fn drop = ffi::GENERAL_NAME_free;
1289 
1290     /// An `X509` certificate alternative names.
1291     pub struct GeneralName;
1292     /// Reference to `GeneralName`.
1293     pub struct GeneralNameRef;
1294 }
1295 
1296 impl GeneralNameRef {
ia5_string(&self, ffi_type: c_int) -> Option<&str>1297     fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1298         unsafe {
1299             if (*self.as_ptr()).type_ != ffi_type {
1300                 return None;
1301             }
1302 
1303             let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _);
1304             let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
1305 
1306             let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
1307             // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1308             // OpenSSL checks that when loading a certificate but if not we'll
1309             // use this instead of from_utf8_unchecked just in case.
1310             str::from_utf8(slice).ok()
1311         }
1312     }
1313 
1314     /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
email(&self) -> Option<&str>1315     pub fn email(&self) -> Option<&str> {
1316         self.ia5_string(ffi::GEN_EMAIL)
1317     }
1318 
1319     /// Returns the contents of this `GeneralName` if it is a `dNSName`.
dnsname(&self) -> Option<&str>1320     pub fn dnsname(&self) -> Option<&str> {
1321         self.ia5_string(ffi::GEN_DNS)
1322     }
1323 
1324     /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
uri(&self) -> Option<&str>1325     pub fn uri(&self) -> Option<&str> {
1326         self.ia5_string(ffi::GEN_URI)
1327     }
1328 
1329     /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
ipaddress(&self) -> Option<&[u8]>1330     pub fn ipaddress(&self) -> Option<&[u8]> {
1331         unsafe {
1332             if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1333                 return None;
1334             }
1335 
1336             let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _);
1337             let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
1338 
1339             Some(slice::from_raw_parts(ptr as *const u8, len as usize))
1340         }
1341     }
1342 }
1343 
1344 impl fmt::Debug for GeneralNameRef {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result1345     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1346         if let Some(email) = self.email() {
1347             formatter.write_str(email)
1348         } else if let Some(dnsname) = self.dnsname() {
1349             formatter.write_str(dnsname)
1350         } else if let Some(uri) = self.uri() {
1351             formatter.write_str(uri)
1352         } else if let Some(ipaddress) = self.ipaddress() {
1353             let result = String::from_utf8_lossy(ipaddress);
1354             formatter.write_str(&result)
1355         } else {
1356             formatter.write_str("(empty)")
1357         }
1358     }
1359 }
1360 
1361 impl Stackable for GeneralName {
1362     type StackType = ffi::stack_st_GENERAL_NAME;
1363 }
1364 
1365 foreign_type_and_impl_send_sync! {
1366     type CType = ffi::X509_ALGOR;
1367     fn drop = ffi::X509_ALGOR_free;
1368 
1369     /// An `X509` certificate signature algorithm.
1370     pub struct X509Algorithm;
1371     /// Reference to `X509Algorithm`.
1372     pub struct X509AlgorithmRef;
1373 }
1374 
1375 impl X509AlgorithmRef {
1376     /// Returns the ASN.1 OID of this algorithm.
object(&self) -> &Asn1ObjectRef1377     pub fn object(&self) -> &Asn1ObjectRef {
1378         unsafe {
1379             let mut oid = ptr::null();
1380             X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1381             Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
1382         }
1383     }
1384 }
1385 
1386 foreign_type_and_impl_send_sync! {
1387     type CType = ffi::X509_OBJECT;
1388     fn drop = X509_OBJECT_free;
1389 
1390     /// An `X509` or an X509 certificate revocation list.
1391     pub struct X509Object;
1392     /// Reference to `X509Object`
1393     pub struct X509ObjectRef;
1394 }
1395 
1396 impl X509ObjectRef {
x509(&self) -> Option<&X509Ref>1397     pub fn x509(&self) -> Option<&X509Ref> {
1398         unsafe {
1399             let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1400             X509Ref::from_const_ptr_opt(ptr)
1401         }
1402     }
1403 }
1404 
1405 impl Stackable for X509Object {
1406     type StackType = ffi::stack_st_X509_OBJECT;
1407 }
1408 
1409 cfg_if! {
1410     if #[cfg(any(ossl110, libressl273))] {
1411         use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
1412     } else {
1413         #[allow(bad_style)]
1414         unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1415             (*(*(*x).cert_info).validity).notAfter
1416         }
1417 
1418         #[allow(bad_style)]
1419         unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1420             (*(*(*x).cert_info).validity).notBefore
1421         }
1422 
1423         #[allow(bad_style)]
1424         unsafe fn X509_up_ref(x: *mut ffi::X509) {
1425             ffi::CRYPTO_add_lock(
1426                 &mut (*x).references,
1427                 1,
1428                 ffi::CRYPTO_LOCK_X509,
1429                 "mod.rs\0".as_ptr() as *const _,
1430                 line!() as c_int,
1431             );
1432         }
1433 
1434         #[allow(bad_style)]
1435         unsafe fn X509_get0_signature(
1436             psig: *mut *const ffi::ASN1_BIT_STRING,
1437             palg: *mut *const ffi::X509_ALGOR,
1438             x: *const ffi::X509,
1439         ) {
1440             if !psig.is_null() {
1441                 *psig = (*x).signature;
1442             }
1443             if !palg.is_null() {
1444                 *palg = (*x).sig_alg;
1445             }
1446         }
1447     }
1448 }
1449 
1450 cfg_if! {
1451     if #[cfg(ossl110)] {
1452         use ffi::{
1453             X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
1454             X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
1455         };
1456     } else {
1457         use ffi::{
1458             ASN1_STRING_data as ASN1_STRING_get0_data,
1459             X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
1460             X509_set_notAfter as X509_set1_notAfter,
1461             X509_set_notBefore as X509_set1_notBefore,
1462         };
1463 
1464         #[allow(bad_style)]
1465         unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
1466             ffi::ASN1_INTEGER_get((*(*x).req_info).version)
1467         }
1468 
1469         #[allow(bad_style)]
1470         unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
1471             (*(*x).req_info).subject
1472         }
1473 
1474         #[allow(bad_style)]
1475         unsafe fn X509_ALGOR_get0(
1476             paobj: *mut *const ffi::ASN1_OBJECT,
1477             pptype: *mut c_int,
1478             pval: *mut *mut ::libc::c_void,
1479             alg: *const ffi::X509_ALGOR,
1480         ) {
1481             if !paobj.is_null() {
1482                 *paobj = (*alg).algorithm;
1483             }
1484             assert!(pptype.is_null());
1485             assert!(pval.is_null());
1486         }
1487     }
1488 }
1489 
1490 cfg_if! {
1491     if #[cfg(any(ossl110, libressl270))] {
1492         use ffi::X509_OBJECT_get0_X509;
1493     } else {
1494         #[allow(bad_style)]
1495         unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
1496             if (*x).type_ == ffi::X509_LU_X509 {
1497                 (*x).data.x509
1498             } else {
1499                 ptr::null_mut()
1500             }
1501         }
1502     }
1503 }
1504 
1505 cfg_if! {
1506     if #[cfg(ossl110)] {
1507         use ffi::X509_OBJECT_free;
1508     } else {
1509         #[allow(bad_style)]
1510         unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1511             ffi::X509_OBJECT_free_contents(x);
1512             ffi::CRYPTO_free(x as *mut libc::c_void);
1513         }
1514     }
1515 }
1516