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