]> git.proxmox.com Git - cargo.git/blob - vendor/openssl/src/x509/mod.rs
New upstream version 0.47.0
[cargo.git] / vendor / openssl / src / x509 / mod.rs
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.
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
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
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
98 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
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
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
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
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
200 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
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.
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.
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.
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.
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.
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.
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 /// ```
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.
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.
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`.
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
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.
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.
372 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
393 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
406 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
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
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
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
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")]
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.
493 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.
502 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
511 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.
521 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.
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`.
537 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
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
566 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
600 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.
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.
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 {
669 fn clone(&self) -> X509 {
670 X509Ref::to_owned(self)
671 }
672 }
673
674 impl fmt::Debug for X509 {
675 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 {
704 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> {
717 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.
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.
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.
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
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
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`.
845 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.
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`.
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.
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
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 {
900 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
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
959 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
972 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 {
981 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
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
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
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
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.
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.
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
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`.
1096 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`.
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
1170 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
1179 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
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
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"]
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 {
1229 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 {
1238 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.
1252 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)]
1258 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)]
1268 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 {
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`.
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`.
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`.
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`.
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 {
1343 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.
1375 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 {
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 }