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