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     from_der! {
952         /// Deserializes a DER-encoded X509 name structure.
953         ///
954         /// This corresponds to [`d2i_X509_NAME`].
955         ///
956         /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html
957         from_der,
958         X509Name,
959         ffi::d2i_X509_NAME
960     }
961 }
962 
963 impl Stackable for X509Name {
964     type StackType = ffi::stack_st_X509_NAME;
965 }
966 
967 impl X509NameRef {
968     /// Returns the name entries by the nid.
entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>969     pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
970         X509NameEntries {
971             name: self,
972             nid: Some(nid),
973             loc: -1,
974         }
975     }
976 
977     /// Returns an iterator over all `X509NameEntry` values
entries(&self) -> X509NameEntries<'_>978     pub fn entries(&self) -> X509NameEntries<'_> {
979         X509NameEntries {
980             name: self,
981             nid: None,
982             loc: -1,
983         }
984     }
985 
986     to_der! {
987         /// Serializes the certificate into a DER-encoded X509 name structure.
988         ///
989         /// This corresponds to [`i2d_X509_NAME`].
990         ///
991         /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509_NAME.html
992         to_der,
993         ffi::i2d_X509_NAME
994     }
995 }
996 
997 impl fmt::Debug for X509NameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result998     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
999         formatter.debug_list().entries(self.entries()).finish()
1000     }
1001 }
1002 
1003 /// A type to destructure and examine an `X509Name`.
1004 pub struct X509NameEntries<'a> {
1005     name: &'a X509NameRef,
1006     nid: Option<Nid>,
1007     loc: c_int,
1008 }
1009 
1010 impl<'a> Iterator for X509NameEntries<'a> {
1011     type Item = &'a X509NameEntryRef;
1012 
next(&mut self) -> Option<&'a X509NameEntryRef>1013     fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1014         unsafe {
1015             match self.nid {
1016                 Some(nid) => {
1017                     // There is a `Nid` specified to search for
1018                     self.loc =
1019                         ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1020                     if self.loc == -1 {
1021                         return None;
1022                     }
1023                 }
1024                 None => {
1025                     // Iterate over all `Nid`s
1026                     self.loc += 1;
1027                     if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1028                         return None;
1029                     }
1030                 }
1031             }
1032 
1033             let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1034 
1035             Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1036         }
1037     }
1038 }
1039 
1040 foreign_type_and_impl_send_sync! {
1041     type CType = ffi::X509_NAME_ENTRY;
1042     fn drop = ffi::X509_NAME_ENTRY_free;
1043 
1044     /// A name entry associated with a `X509Name`.
1045     pub struct X509NameEntry;
1046     /// Reference to `X509NameEntry`.
1047     pub struct X509NameEntryRef;
1048 }
1049 
1050 impl X509NameEntryRef {
1051     /// Returns the field value of an `X509NameEntry`.
1052     ///
1053     /// This corresponds to [`X509_NAME_ENTRY_get_data`].
1054     ///
1055     /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html
data(&self) -> &Asn1StringRef1056     pub fn data(&self) -> &Asn1StringRef {
1057         unsafe {
1058             let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1059             Asn1StringRef::from_ptr(data)
1060         }
1061     }
1062 
1063     /// Returns the `Asn1Object` value of an `X509NameEntry`.
1064     /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1065     ///
1066     /// This corresponds to [`X509_NAME_ENTRY_get_object`].
1067     ///
1068     /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html
object(&self) -> &Asn1ObjectRef1069     pub fn object(&self) -> &Asn1ObjectRef {
1070         unsafe {
1071             let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1072             Asn1ObjectRef::from_ptr(object)
1073         }
1074     }
1075 }
1076 
1077 impl fmt::Debug for X509NameEntryRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1078     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1079         formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1080     }
1081 }
1082 
1083 /// A builder used to construct an `X509Req`.
1084 pub struct X509ReqBuilder(X509Req);
1085 
1086 impl X509ReqBuilder {
1087     /// Returns a builder for a certificate request.
1088     ///
1089     /// This corresponds to [`X509_REQ_new`].
1090     ///
1091     ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html
new() -> Result<X509ReqBuilder, ErrorStack>1092     pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1093         unsafe {
1094             ffi::init();
1095             cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1096         }
1097     }
1098 
1099     /// Set the numerical value of the version field.
1100     ///
1101     /// This corresponds to [`X509_REQ_set_version`].
1102     ///
1103     ///[`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>1104     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1105         unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
1106     }
1107 
1108     /// Set the issuer name.
1109     ///
1110     /// This corresponds to [`X509_REQ_set_subject_name`].
1111     ///
1112     /// [`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>1113     pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1114         unsafe {
1115             cvt(ffi::X509_REQ_set_subject_name(
1116                 self.0.as_ptr(),
1117                 subject_name.as_ptr(),
1118             ))
1119             .map(|_| ())
1120         }
1121     }
1122 
1123     /// Set the public key.
1124     ///
1125     /// This corresponds to [`X509_REQ_set_pubkey`].
1126     ///
1127     /// [`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,1128     pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1129     where
1130         T: HasPublic,
1131     {
1132         unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1133     }
1134 
1135     /// Return an `X509v3Context`. This context object can be used to construct
1136     /// certain `X509` extensions.
x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1137     pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1138         unsafe {
1139             let mut ctx = mem::zeroed();
1140 
1141             ffi::X509V3_set_ctx(
1142                 &mut ctx,
1143                 ptr::null_mut(),
1144                 ptr::null_mut(),
1145                 self.0.as_ptr(),
1146                 ptr::null_mut(),
1147                 0,
1148             );
1149 
1150             // nodb case taken care of since we zeroed ctx above
1151             if let Some(conf) = conf {
1152                 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1153             }
1154 
1155             X509v3Context(ctx, PhantomData)
1156         }
1157     }
1158 
1159     /// Permits any number of extension fields to be added to the certificate.
add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1160     pub fn add_extensions(
1161         &mut self,
1162         extensions: &StackRef<X509Extension>,
1163     ) -> Result<(), ErrorStack> {
1164         unsafe {
1165             cvt(ffi::X509_REQ_add_extensions(
1166                 self.0.as_ptr(),
1167                 extensions.as_ptr(),
1168             ))
1169             .map(|_| ())
1170         }
1171     }
1172 
1173     /// Sign the request using a private key.
1174     ///
1175     /// This corresponds to [`X509_REQ_sign`].
1176     ///
1177     /// [`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,1178     pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1179     where
1180         T: HasPrivate,
1181     {
1182         unsafe {
1183             cvt(ffi::X509_REQ_sign(
1184                 self.0.as_ptr(),
1185                 key.as_ptr(),
1186                 hash.as_ptr(),
1187             ))
1188             .map(|_| ())
1189         }
1190     }
1191 
1192     /// Returns the `X509Req`.
build(self) -> X509Req1193     pub fn build(self) -> X509Req {
1194         self.0
1195     }
1196 }
1197 
1198 foreign_type_and_impl_send_sync! {
1199     type CType = ffi::X509_REQ;
1200     fn drop = ffi::X509_REQ_free;
1201 
1202     /// An `X509` certificate request.
1203     pub struct X509Req;
1204     /// Reference to `X509Req`.
1205     pub struct X509ReqRef;
1206 }
1207 
1208 impl X509Req {
1209     /// A builder for `X509Req`.
builder() -> Result<X509ReqBuilder, ErrorStack>1210     pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1211         X509ReqBuilder::new()
1212     }
1213 
1214     from_pem! {
1215         /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1216         ///
1217         /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1218         ///
1219         /// This corresponds to [`PEM_read_bio_X509_REQ`].
1220         ///
1221         /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html
1222         from_pem,
1223         X509Req,
1224         ffi::PEM_read_bio_X509_REQ
1225     }
1226 
1227     from_der! {
1228         /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1229         ///
1230         /// This corresponds to [`d2i_X509_REQ`].
1231         ///
1232         /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html
1233         from_der,
1234         X509Req,
1235         ffi::d2i_X509_REQ
1236     }
1237 }
1238 
1239 impl X509ReqRef {
1240     to_pem! {
1241         /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1242         ///
1243         /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1244         ///
1245         /// This corresponds to [`PEM_write_bio_X509_REQ`].
1246         ///
1247         /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html
1248         to_pem,
1249         ffi::PEM_write_bio_X509_REQ
1250     }
1251 
1252     to_der! {
1253         /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1254         ///
1255         /// This corresponds to [`i2d_X509_REQ`].
1256         ///
1257         /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html
1258         to_der,
1259         ffi::i2d_X509_REQ
1260     }
1261 
1262     /// Returns the numerical value of the version field of the certificate request.
1263     ///
1264     /// This corresponds to [`X509_REQ_get_version`]
1265     ///
1266     /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html
version(&self) -> i321267     pub fn version(&self) -> i32 {
1268         unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1269     }
1270 
1271     /// Returns the subject name of the certificate request.
1272     ///
1273     /// This corresponds to [`X509_REQ_get_subject_name`]
1274     ///
1275     /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html
subject_name(&self) -> &X509NameRef1276     pub fn subject_name(&self) -> &X509NameRef {
1277         unsafe {
1278             let name = X509_REQ_get_subject_name(self.as_ptr());
1279             X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1280         }
1281     }
1282 
1283     /// Returns the public key of the certificate request.
1284     ///
1285     /// This corresponds to [`X509_REQ_get_pubkey"]
1286     ///
1287     /// [`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>1288     pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1289         unsafe {
1290             let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1291             Ok(PKey::from_ptr(key))
1292         }
1293     }
1294 
1295     /// Check if the certificate request is signed using the given public key.
1296     ///
1297     /// Returns `true` if verification succeeds.
1298     ///
1299     /// This corresponds to [`X509_REQ_verify"].
1300     ///
1301     /// [`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,1302     pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1303     where
1304         T: HasPublic,
1305     {
1306         unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1307     }
1308 
1309     /// Returns the extensions of the certificate request.
1310     ///
1311     /// This corresponds to [`X509_REQ_get_extensions"]
extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1312     pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1313         unsafe {
1314             let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1315             Ok(Stack::from_ptr(extensions))
1316         }
1317     }
1318 }
1319 
1320 /// The result of peer certificate verification.
1321 #[derive(Copy, Clone, PartialEq, Eq)]
1322 pub struct X509VerifyResult(c_int);
1323 
1324 impl fmt::Debug for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1325     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1326         fmt.debug_struct("X509VerifyResult")
1327             .field("code", &self.0)
1328             .field("error", &self.error_string())
1329             .finish()
1330     }
1331 }
1332 
1333 impl fmt::Display for X509VerifyResult {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1334     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1335         fmt.write_str(self.error_string())
1336     }
1337 }
1338 
1339 impl Error for X509VerifyResult {}
1340 
1341 impl X509VerifyResult {
1342     /// Creates an `X509VerifyResult` from a raw error number.
1343     ///
1344     /// # Safety
1345     ///
1346     /// Some methods on `X509VerifyResult` are not thread safe if the error
1347     /// number is invalid.
from_raw(err: c_int) -> X509VerifyResult1348     pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1349         X509VerifyResult(err)
1350     }
1351 
1352     /// Return the integer representation of an `X509VerifyResult`.
1353     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int1354     pub fn as_raw(&self) -> c_int {
1355         self.0
1356     }
1357 
1358     /// Return a human readable error string from the verification error.
1359     ///
1360     /// This corresponds to [`X509_verify_cert_error_string`].
1361     ///
1362     /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html
1363     #[allow(clippy::trivially_copy_pass_by_ref)]
error_string(&self) -> &'static str1364     pub fn error_string(&self) -> &'static str {
1365         ffi::init();
1366 
1367         unsafe {
1368             let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1369             str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1370         }
1371     }
1372 
1373     /// Successful peer certifiate verification.
1374     pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1375     /// Application verification failure.
1376     pub const APPLICATION_VERIFICATION: X509VerifyResult =
1377         X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1378 }
1379 
1380 foreign_type_and_impl_send_sync! {
1381     type CType = ffi::GENERAL_NAME;
1382     fn drop = ffi::GENERAL_NAME_free;
1383 
1384     /// An `X509` certificate alternative names.
1385     pub struct GeneralName;
1386     /// Reference to `GeneralName`.
1387     pub struct GeneralNameRef;
1388 }
1389 
1390 impl GeneralNameRef {
ia5_string(&self, ffi_type: c_int) -> Option<&str>1391     fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1392         unsafe {
1393             if (*self.as_ptr()).type_ != ffi_type {
1394                 return None;
1395             }
1396 
1397             let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _);
1398             let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
1399 
1400             let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
1401             // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
1402             // OpenSSL checks that when loading a certificate but if not we'll
1403             // use this instead of from_utf8_unchecked just in case.
1404             str::from_utf8(slice).ok()
1405         }
1406     }
1407 
1408     /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
email(&self) -> Option<&str>1409     pub fn email(&self) -> Option<&str> {
1410         self.ia5_string(ffi::GEN_EMAIL)
1411     }
1412 
1413     /// Returns the contents of this `GeneralName` if it is a `dNSName`.
dnsname(&self) -> Option<&str>1414     pub fn dnsname(&self) -> Option<&str> {
1415         self.ia5_string(ffi::GEN_DNS)
1416     }
1417 
1418     /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
uri(&self) -> Option<&str>1419     pub fn uri(&self) -> Option<&str> {
1420         self.ia5_string(ffi::GEN_URI)
1421     }
1422 
1423     /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
ipaddress(&self) -> Option<&[u8]>1424     pub fn ipaddress(&self) -> Option<&[u8]> {
1425         unsafe {
1426             if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1427                 return None;
1428             }
1429 
1430             let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _);
1431             let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
1432 
1433             Some(slice::from_raw_parts(ptr as *const u8, len as usize))
1434         }
1435     }
1436 }
1437 
1438 impl fmt::Debug for GeneralNameRef {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1439     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1440         if let Some(email) = self.email() {
1441             formatter.write_str(email)
1442         } else if let Some(dnsname) = self.dnsname() {
1443             formatter.write_str(dnsname)
1444         } else if let Some(uri) = self.uri() {
1445             formatter.write_str(uri)
1446         } else if let Some(ipaddress) = self.ipaddress() {
1447             let result = String::from_utf8_lossy(ipaddress);
1448             formatter.write_str(&result)
1449         } else {
1450             formatter.write_str("(empty)")
1451         }
1452     }
1453 }
1454 
1455 impl Stackable for GeneralName {
1456     type StackType = ffi::stack_st_GENERAL_NAME;
1457 }
1458 
1459 foreign_type_and_impl_send_sync! {
1460     type CType = ffi::ACCESS_DESCRIPTION;
1461     fn drop = ffi::ACCESS_DESCRIPTION_free;
1462 
1463     /// `AccessDescription` of certificate authority information.
1464     pub struct AccessDescription;
1465     /// Reference to `AccessDescription`.
1466     pub struct AccessDescriptionRef;
1467 }
1468 
1469 impl AccessDescriptionRef {
1470     /// Returns the access method OID.
method(&self) -> &Asn1ObjectRef1471     pub fn method(&self) -> &Asn1ObjectRef {
1472         unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
1473     }
1474 
1475     // Returns the access location.
location(&self) -> &GeneralNameRef1476     pub fn location(&self) -> &GeneralNameRef {
1477         unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
1478     }
1479 }
1480 
1481 impl Stackable for AccessDescription {
1482     type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
1483 }
1484 
1485 foreign_type_and_impl_send_sync! {
1486     type CType = ffi::X509_ALGOR;
1487     fn drop = ffi::X509_ALGOR_free;
1488 
1489     /// An `X509` certificate signature algorithm.
1490     pub struct X509Algorithm;
1491     /// Reference to `X509Algorithm`.
1492     pub struct X509AlgorithmRef;
1493 }
1494 
1495 impl X509AlgorithmRef {
1496     /// Returns the ASN.1 OID of this algorithm.
object(&self) -> &Asn1ObjectRef1497     pub fn object(&self) -> &Asn1ObjectRef {
1498         unsafe {
1499             let mut oid = ptr::null();
1500             X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1501             Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
1502         }
1503     }
1504 }
1505 
1506 foreign_type_and_impl_send_sync! {
1507     type CType = ffi::X509_OBJECT;
1508     fn drop = X509_OBJECT_free;
1509 
1510     /// An `X509` or an X509 certificate revocation list.
1511     pub struct X509Object;
1512     /// Reference to `X509Object`
1513     pub struct X509ObjectRef;
1514 }
1515 
1516 impl X509ObjectRef {
x509(&self) -> Option<&X509Ref>1517     pub fn x509(&self) -> Option<&X509Ref> {
1518         unsafe {
1519             let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1520             X509Ref::from_const_ptr_opt(ptr)
1521         }
1522     }
1523 }
1524 
1525 impl Stackable for X509Object {
1526     type StackType = ffi::stack_st_X509_OBJECT;
1527 }
1528 
1529 cfg_if! {
1530     if #[cfg(any(ossl110, libressl273))] {
1531         use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
1532     } else {
1533         #[allow(bad_style)]
1534         unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1535             (*(*(*x).cert_info).validity).notAfter
1536         }
1537 
1538         #[allow(bad_style)]
1539         unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
1540             (*(*(*x).cert_info).validity).notBefore
1541         }
1542 
1543         #[allow(bad_style)]
1544         unsafe fn X509_up_ref(x: *mut ffi::X509) {
1545             ffi::CRYPTO_add_lock(
1546                 &mut (*x).references,
1547                 1,
1548                 ffi::CRYPTO_LOCK_X509,
1549                 "mod.rs\0".as_ptr() as *const _,
1550                 line!() as c_int,
1551             );
1552         }
1553 
1554         #[allow(bad_style)]
1555         unsafe fn X509_get0_signature(
1556             psig: *mut *const ffi::ASN1_BIT_STRING,
1557             palg: *mut *const ffi::X509_ALGOR,
1558             x: *const ffi::X509,
1559         ) {
1560             if !psig.is_null() {
1561                 *psig = (*x).signature;
1562             }
1563             if !palg.is_null() {
1564                 *palg = (*x).sig_alg;
1565             }
1566         }
1567     }
1568 }
1569 
1570 cfg_if! {
1571     if #[cfg(ossl110)] {
1572         use ffi::{
1573             X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
1574             X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
1575         };
1576     } else {
1577         use ffi::{
1578             ASN1_STRING_data as ASN1_STRING_get0_data,
1579             X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
1580             X509_set_notAfter as X509_set1_notAfter,
1581             X509_set_notBefore as X509_set1_notBefore,
1582         };
1583 
1584         #[allow(bad_style)]
1585         unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
1586             ffi::ASN1_INTEGER_get((*(*x).req_info).version)
1587         }
1588 
1589         #[allow(bad_style)]
1590         unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
1591             (*(*x).req_info).subject
1592         }
1593 
1594         #[allow(bad_style)]
1595         unsafe fn X509_ALGOR_get0(
1596             paobj: *mut *const ffi::ASN1_OBJECT,
1597             pptype: *mut c_int,
1598             pval: *mut *mut ::libc::c_void,
1599             alg: *const ffi::X509_ALGOR,
1600         ) {
1601             if !paobj.is_null() {
1602                 *paobj = (*alg).algorithm;
1603             }
1604             assert!(pptype.is_null());
1605             assert!(pval.is_null());
1606         }
1607     }
1608 }
1609 
1610 cfg_if! {
1611     if #[cfg(any(ossl110, libressl270))] {
1612         use ffi::X509_OBJECT_get0_X509;
1613     } else {
1614         #[allow(bad_style)]
1615         unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
1616             if (*x).type_ == ffi::X509_LU_X509 {
1617                 (*x).data.x509
1618             } else {
1619                 ptr::null_mut()
1620             }
1621         }
1622     }
1623 }
1624 
1625 cfg_if! {
1626     if #[cfg(ossl110)] {
1627         use ffi::X509_OBJECT_free;
1628     } else {
1629         #[allow(bad_style)]
1630         unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1631             ffi::X509_OBJECT_free_contents(x);
1632             ffi::CRYPTO_free(x as *mut libc::c_void);
1633         }
1634     }
1635 }
1636