1use cfg_if::cfg_if;
11use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
12use libc::{c_int, c_long, c_uchar, c_uint, c_void};
13use std::cmp::{self, Ordering};
14use std::convert::{TryFrom, TryInto};
15use std::error::Error;
16use std::ffi::{CStr, CString};
17use std::fmt;
18use std::marker::PhantomData;
19use std::mem;
20use std::net::IpAddr;
21use std::path::Path;
22use std::ptr;
23use std::str;
24
25use crate::asn1::{
26 Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef,
27 Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type,
28};
29use crate::bio::MemBioSlice;
30use crate::conf::ConfRef;
31use crate::error::ErrorStack;
32use crate::ex_data::Index;
33use crate::hash::{DigestBytes, MessageDigest};
34use crate::nid::Nid;
35use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
36use crate::ssl::SslRef;
37use crate::stack::{Stack, StackRef, Stackable};
38use crate::string::OpensslString;
39use crate::util::{self, ForeignTypeExt, ForeignTypeRefExt};
40use crate::{cvt, cvt_n, cvt_p, cvt_p_const};
41use openssl_macros::corresponds;
42
43pub mod verify;
44
45pub mod extension;
46pub mod store;
47
48#[cfg(test)]
49mod tests;
50
51pub unsafe trait ExtensionType {
57 const NID: Nid;
58 type Output: ForeignType;
59}
60
61foreign_type_and_impl_send_sync! {
62 type CType = ffi::X509_STORE_CTX;
63 fn drop = ffi::X509_STORE_CTX_free;
64
65 pub struct X509StoreContext;
67
68 pub struct X509StoreContextRef;
70}
71
72impl X509StoreContext {
73 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
76 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
77 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
78 }
79
80 #[corresponds(X509_STORE_CTX_new)]
82 pub fn new() -> Result<X509StoreContext, ErrorStack> {
83 unsafe {
84 ffi::init();
85 cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
86 }
87 }
88}
89
90impl X509StoreContextRef {
91 #[corresponds(X509_STORE_CTX_get_ex_data)]
93 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
94 unsafe {
95 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
96 if data.is_null() {
97 None
98 } else {
99 Some(&*(data as *const T))
100 }
101 }
102 }
103
104 #[corresponds(X509_STORE_CTX_get_error)]
106 pub fn error(&self) -> X509VerifyResult {
107 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
108 }
109
110 pub fn init<F, T>(
126 &mut self,
127 trust: &store::X509StoreRef,
128 cert: &X509Ref,
129 cert_chain: &StackRef<X509>,
130 with_context: F,
131 ) -> Result<T, ErrorStack>
132 where
133 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
134 {
135 struct Cleanup<'a>(&'a mut X509StoreContextRef);
136
137 impl Drop for Cleanup<'_> {
138 fn drop(&mut self) {
139 unsafe {
140 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
141 }
142 }
143 }
144
145 unsafe {
146 cvt(ffi::X509_STORE_CTX_init(
147 self.as_ptr(),
148 trust.as_ptr(),
149 cert.as_ptr(),
150 cert_chain.as_ptr(),
151 ))?;
152
153 let cleanup = Cleanup(self);
154 with_context(cleanup.0)
155 }
156 }
157
158 #[corresponds(X509_verify_cert)]
165 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
166 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
167 }
168
169 #[corresponds(X509_STORE_CTX_set_error)]
171 pub fn set_error(&mut self, result: X509VerifyResult) {
172 unsafe {
173 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
174 }
175 }
176
177 #[corresponds(X509_STORE_CTX_get_current_cert)]
180 pub fn current_cert(&self) -> Option<&X509Ref> {
181 unsafe {
182 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
183 X509Ref::from_const_ptr_opt(ptr)
184 }
185 }
186
187 #[corresponds(X509_STORE_CTX_get_error_depth)]
192 pub fn error_depth(&self) -> u32 {
193 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
194 }
195
196 #[corresponds(X509_STORE_CTX_get0_chain)]
198 pub fn chain(&self) -> Option<&StackRef<X509>> {
199 unsafe {
200 let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
201
202 if chain.is_null() {
203 None
204 } else {
205 Some(StackRef::from_ptr(chain))
206 }
207 }
208 }
209}
210
211pub struct X509Builder(X509);
213
214impl X509Builder {
215 #[corresponds(X509_new)]
217 pub fn new() -> Result<X509Builder, ErrorStack> {
218 unsafe {
219 ffi::init();
220 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
221 }
222 }
223
224 #[corresponds(X509_set1_notAfter)]
226 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
227 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
228 }
229
230 #[corresponds(X509_set1_notBefore)]
232 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
233 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
234 }
235
236 #[corresponds(X509_set_version)]
241 #[allow(clippy::useless_conversion)]
242 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
243 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
244 }
245
246 #[corresponds(X509_set_serialNumber)]
248 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
249 unsafe {
250 cvt(ffi::X509_set_serialNumber(
251 self.0.as_ptr(),
252 serial_number.as_ptr(),
253 ))
254 .map(|_| ())
255 }
256 }
257
258 #[corresponds(X509_set_issuer_name)]
260 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
261 unsafe {
262 cvt(ffi::X509_set_issuer_name(
263 self.0.as_ptr(),
264 issuer_name.as_ptr(),
265 ))
266 .map(|_| ())
267 }
268 }
269
270 #[corresponds(X509_set_subject_name)]
289 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
290 unsafe {
291 cvt(ffi::X509_set_subject_name(
292 self.0.as_ptr(),
293 subject_name.as_ptr(),
294 ))
295 .map(|_| ())
296 }
297 }
298
299 #[corresponds(X509_set_pubkey)]
301 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
302 where
303 T: HasPublic,
304 {
305 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
306 }
307
308 #[corresponds(X509V3_set_ctx)]
312 pub fn x509v3_context<'a>(
313 &'a self,
314 issuer: Option<&'a X509Ref>,
315 conf: Option<&'a ConfRef>,
316 ) -> X509v3Context<'a> {
317 unsafe {
318 let mut ctx = mem::zeroed();
319
320 let issuer = match issuer {
321 Some(issuer) => issuer.as_ptr(),
322 None => self.0.as_ptr(),
323 };
324 let subject = self.0.as_ptr();
325 ffi::X509V3_set_ctx(
326 &mut ctx,
327 issuer,
328 subject,
329 ptr::null_mut(),
330 ptr::null_mut(),
331 0,
332 );
333
334 if let Some(conf) = conf {
336 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
337 }
338
339 X509v3Context(ctx, PhantomData)
340 }
341 }
342
343 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
347 self.append_extension2(&extension)
348 }
349
350 #[corresponds(X509_add_ext)]
352 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
353 unsafe {
354 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
355 Ok(())
356 }
357 }
358
359 #[corresponds(X509_sign)]
361 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
362 where
363 T: HasPrivate,
364 {
365 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
366 }
367
368 pub fn build(self) -> X509 {
370 self.0
371 }
372}
373
374foreign_type_and_impl_send_sync! {
375 type CType = ffi::X509;
376 fn drop = ffi::X509_free;
377
378 pub struct X509;
380 pub struct X509Ref;
382}
383
384impl X509Ref {
385 #[corresponds(X509_get_subject_name)]
387 pub fn subject_name(&self) -> &X509NameRef {
388 unsafe {
389 let name = ffi::X509_get_subject_name(self.as_ptr());
390 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
391 }
392 }
393
394 #[corresponds(X509_subject_name_hash)]
396 pub fn subject_name_hash(&self) -> u32 {
397 #[allow(clippy::unnecessary_cast)]
398 unsafe {
399 ffi::X509_subject_name_hash(self.as_ptr()) as u32
400 }
401 }
402
403 #[corresponds(X509_get_issuer_name)]
405 pub fn issuer_name(&self) -> &X509NameRef {
406 unsafe {
407 let name = ffi::X509_get_issuer_name(self.as_ptr());
408 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
409 }
410 }
411
412 #[corresponds(X509_issuer_name_hash)]
414 pub fn issuer_name_hash(&self) -> u32 {
415 #[allow(clippy::unnecessary_cast)]
416 unsafe {
417 ffi::X509_issuer_name_hash(self.as_ptr()) as u32
418 }
419 }
420
421 #[corresponds(X509_get0_extensions)]
423 #[cfg(any(ossl111, libressl272, boringssl, awslc))]
424 pub fn extensions(&self) -> Option<&StackRef<X509Extension>> {
425 unsafe {
426 let extensions = ffi::X509_get0_extensions(self.as_ptr());
427 StackRef::from_const_ptr_opt(extensions)
428 }
429 }
430
431 #[corresponds(X509_get0_ext_by_NID)]
433 #[cfg(any(ossl111, libressl282, boringssl, awslc))]
434 pub fn get_extension_location(&self, nid: Nid, lastpos: Option<i32>) -> Option<i32> {
435 let lastpos = lastpos.unwrap_or(-1);
436 unsafe {
437 let id = ffi::X509_get_ext_by_NID(self.as_ptr(), nid.as_raw(), lastpos as _);
438 if id == -1 {
439 None
440 } else {
441 Some(id)
442 }
443 }
444 }
445
446 #[corresponds(X509_get_ext)]
448 #[cfg(any(ossl111, libressl282, boringssl, awslc))]
449 pub fn get_extension(&self, loc: i32) -> Result<&X509ExtensionRef, ErrorStack> {
450 unsafe {
451 let ext = cvt_p(ffi::X509_get_ext(self.as_ptr(), loc as _))?;
452 Ok(X509ExtensionRef::from_ptr(ext))
453 }
454 }
455
456 #[corresponds(X509_get_key_usage)]
458 #[cfg(any(ossl110, libressl, boringssl, awslc))]
459 pub fn key_usage(&self) -> Option<u32> {
460 let flags = unsafe { ffi::X509_get_key_usage(self.as_ptr()) };
461 if flags == u32::MAX {
462 None
463 } else {
464 Some(flags)
465 }
466 }
467
468 #[corresponds(X509_get_ext_d2i)]
470 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
471 unsafe {
472 let stack = ffi::X509_get_ext_d2i(
473 self.as_ptr(),
474 ffi::NID_subject_alt_name,
475 ptr::null_mut(),
476 ptr::null_mut(),
477 );
478 Stack::from_ptr_opt(stack as *mut _)
479 }
480 }
481
482 #[corresponds(X509_get_ext_d2i)]
484 pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> {
485 unsafe {
486 let stack = ffi::X509_get_ext_d2i(
487 self.as_ptr(),
488 ffi::NID_crl_distribution_points,
489 ptr::null_mut(),
490 ptr::null_mut(),
491 );
492 Stack::from_ptr_opt(stack as *mut _)
493 }
494 }
495
496 #[corresponds(X509_get_ext_d2i)]
498 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
499 unsafe {
500 let stack = ffi::X509_get_ext_d2i(
501 self.as_ptr(),
502 ffi::NID_issuer_alt_name,
503 ptr::null_mut(),
504 ptr::null_mut(),
505 );
506 Stack::from_ptr_opt(stack as *mut _)
507 }
508 }
509
510 #[corresponds(X509_get_ext_d2i)]
514 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
515 unsafe {
516 let stack = ffi::X509_get_ext_d2i(
517 self.as_ptr(),
518 ffi::NID_info_access,
519 ptr::null_mut(),
520 ptr::null_mut(),
521 );
522 Stack::from_ptr_opt(stack as *mut _)
523 }
524 }
525
526 #[corresponds(X509_get_pathlen)]
528 #[cfg(any(ossl110, boringssl, awslc))]
529 pub fn pathlen(&self) -> Option<u32> {
530 let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
531 u32::try_from(v).ok()
532 }
533
534 #[corresponds(X509_get0_subject_key_id)]
536 #[cfg(any(ossl110, boringssl, awslc))]
537 pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
538 unsafe {
539 let data = ffi::X509_get0_subject_key_id(self.as_ptr());
540 Asn1OctetStringRef::from_const_ptr_opt(data)
541 }
542 }
543
544 #[corresponds(X509_get0_authority_key_id)]
546 #[cfg(any(ossl110, boringssl, awslc))]
547 pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
548 unsafe {
549 let data = ffi::X509_get0_authority_key_id(self.as_ptr());
550 Asn1OctetStringRef::from_const_ptr_opt(data)
551 }
552 }
553
554 #[corresponds(X509_get0_authority_issuer)]
556 #[cfg(any(ossl111d, boringssl))]
557 pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
558 unsafe {
559 let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
560 StackRef::from_const_ptr_opt(stack)
561 }
562 }
563
564 #[corresponds(X509_get0_authority_serial)]
566 #[cfg(any(ossl111d, boringssl))]
567 pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
568 unsafe {
569 let r = ffi::X509_get0_authority_serial(self.as_ptr());
570 Asn1IntegerRef::from_const_ptr_opt(r)
571 }
572 }
573
574 #[corresponds(X509_get_pubkey)]
575 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
576 unsafe {
577 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
578 Ok(PKey::from_ptr(pkey))
579 }
580 }
581
582 #[corresponds(X509_get_X509_PUBKEY)]
583 #[cfg(any(ossl110, boringssl))]
584 pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
585 unsafe {
586 let key = cvt_p(ffi::X509_get_X509_PUBKEY(self.as_ptr()))?;
587 Ok(X509PubkeyRef::from_ptr(key))
588 }
589 }
590
591 digest! {
592 digest,
598 ffi::X509_digest
599 }
600
601 digest! {
602 pubkey_digest,
608 ffi::X509_pubkey_digest
609 }
610
611 #[corresponds(X509_getm_notAfter)]
613 pub fn not_after(&self) -> &Asn1TimeRef {
614 unsafe {
615 let date = X509_getm_notAfter(self.as_ptr());
616 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
617 }
618 }
619
620 #[corresponds(X509_getm_notBefore)]
622 pub fn not_before(&self) -> &Asn1TimeRef {
623 unsafe {
624 let date = X509_getm_notBefore(self.as_ptr());
625 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
626 }
627 }
628
629 #[corresponds(X509_get0_signature)]
631 pub fn signature(&self) -> &Asn1BitStringRef {
632 unsafe {
633 let mut signature = ptr::null();
634 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
635 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
636 }
637 }
638
639 #[corresponds(X509_get0_signature)]
641 pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
642 unsafe {
643 let mut algor = ptr::null();
644 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
645 X509AlgorithmRef::from_const_ptr_opt(algor)
646 .expect("signature algorithm must not be null")
647 }
648 }
649
650 #[corresponds(X509_get1_ocsp)]
653 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
654 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
655 }
656
657 #[corresponds(X509_check_issued)]
659 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
660 unsafe {
661 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
662 X509VerifyResult::from_raw(r)
663 }
664 }
665
666 #[corresponds(X509_get_version)]
671 #[cfg(any(ossl110, libressl282, boringssl, awslc))]
672 #[allow(clippy::unnecessary_cast)]
673 pub fn version(&self) -> i32 {
674 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
675 }
676
677 #[corresponds(X509_verify)]
684 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
685 where
686 T: HasPublic,
687 {
688 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
689 }
690
691 #[corresponds(X509_get_serialNumber)]
693 pub fn serial_number(&self) -> &Asn1IntegerRef {
694 unsafe {
695 let r = ffi::X509_get_serialNumber(self.as_ptr());
696 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
697 }
698 }
699
700 #[corresponds(X509_alias_get0)]
706 pub fn alias(&self) -> Option<&[u8]> {
707 unsafe {
708 let mut len = 0;
709 let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len);
710 if ptr.is_null() {
711 None
712 } else {
713 Some(util::from_raw_parts(ptr, len as usize))
714 }
715 }
716 }
717
718 to_pem! {
719 #[corresponds(PEM_write_bio_X509)]
723 to_pem,
724 ffi::PEM_write_bio_X509
725 }
726
727 to_der! {
728 #[corresponds(i2d_X509)]
730 to_der,
731 ffi::i2d_X509
732 }
733
734 to_pem! {
735 #[corresponds(X509_print)]
737 to_text,
738 ffi::X509_print
739 }
740}
741
742impl ToOwned for X509Ref {
743 type Owned = X509;
744
745 fn to_owned(&self) -> X509 {
746 unsafe {
747 X509_up_ref(self.as_ptr());
748 X509::from_ptr(self.as_ptr())
749 }
750 }
751}
752
753impl Ord for X509Ref {
754 fn cmp(&self, other: &Self) -> cmp::Ordering {
755 let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
758 cmp.cmp(&0)
759 }
760}
761
762impl PartialOrd for X509Ref {
763 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
764 Some(self.cmp(other))
765 }
766}
767
768impl PartialOrd<X509> for X509Ref {
769 fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
770 <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
771 }
772}
773
774impl PartialEq for X509Ref {
775 fn eq(&self, other: &Self) -> bool {
776 self.cmp(other) == cmp::Ordering::Equal
777 }
778}
779
780impl PartialEq<X509> for X509Ref {
781 fn eq(&self, other: &X509) -> bool {
782 <X509Ref as PartialEq<X509Ref>>::eq(self, other)
783 }
784}
785
786impl Eq for X509Ref {}
787
788impl X509 {
789 pub fn builder() -> Result<X509Builder, ErrorStack> {
791 X509Builder::new()
792 }
793
794 from_pem! {
795 #[corresponds(PEM_read_bio_X509)]
799 from_pem,
800 X509,
801 ffi::PEM_read_bio_X509
802 }
803
804 from_der! {
805 #[corresponds(d2i_X509)]
807 from_der,
808 X509,
809 ffi::d2i_X509
810 }
811
812 #[corresponds(PEM_read_bio_X509)]
814 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
815 unsafe {
816 ffi::init();
817 let bio = MemBioSlice::new(pem)?;
818
819 let mut certs = vec![];
820 loop {
821 let r =
822 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
823 if r.is_null() {
824 let e = ErrorStack::get();
825
826 if let Some(err) = e.errors().last() {
827 if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int
828 && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int
829 {
830 break;
831 }
832 }
833
834 return Err(e);
835 } else {
836 certs.push(X509(r));
837 }
838 }
839
840 Ok(certs)
841 }
842 }
843}
844
845impl Clone for X509 {
846 fn clone(&self) -> X509 {
847 X509Ref::to_owned(self)
848 }
849}
850
851impl fmt::Debug for X509 {
852 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
853 let serial = match &self.serial_number().to_bn() {
854 Ok(bn) => match bn.to_hex_str() {
855 Ok(hex) => hex.to_string(),
856 Err(_) => "".to_string(),
857 },
858 Err(_) => "".to_string(),
859 };
860 let mut debug_struct = formatter.debug_struct("X509");
861 debug_struct.field("serial_number", &serial);
862 debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
863 debug_struct.field("issuer", &self.issuer_name());
864 debug_struct.field("subject", &self.subject_name());
865 if let Some(subject_alt_names) = &self.subject_alt_names() {
866 debug_struct.field("subject_alt_names", subject_alt_names);
867 }
868 debug_struct.field("not_before", &self.not_before());
869 debug_struct.field("not_after", &self.not_after());
870
871 if let Ok(public_key) = &self.public_key() {
872 debug_struct.field("public_key", public_key);
873 };
874 debug_struct.finish()
877 }
878}
879
880impl AsRef<X509Ref> for X509Ref {
881 fn as_ref(&self) -> &X509Ref {
882 self
883 }
884}
885
886impl Stackable for X509 {
887 type StackType = ffi::stack_st_X509;
888}
889
890impl Ord for X509 {
891 fn cmp(&self, other: &Self) -> cmp::Ordering {
892 X509Ref::cmp(self, other)
893 }
894}
895
896impl PartialOrd for X509 {
897 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
898 Some(self.cmp(other))
899 }
900}
901
902impl PartialOrd<X509Ref> for X509 {
903 fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
904 X509Ref::partial_cmp(self, other)
905 }
906}
907
908impl PartialEq for X509 {
909 fn eq(&self, other: &Self) -> bool {
910 X509Ref::eq(self, other)
911 }
912}
913
914impl PartialEq<X509Ref> for X509 {
915 fn eq(&self, other: &X509Ref) -> bool {
916 X509Ref::eq(self, other)
917 }
918}
919
920impl Eq for X509 {}
921
922pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
924
925impl X509v3Context<'_> {
926 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
927 &self.0 as *const _ as *mut _
928 }
929}
930
931foreign_type_and_impl_send_sync! {
932 type CType = ffi::X509_EXTENSION;
933 fn drop = ffi::X509_EXTENSION_free;
934
935 pub struct X509Extension;
937 pub struct X509ExtensionRef;
939}
940
941impl Stackable for X509Extension {
942 type StackType = ffi::stack_st_X509_EXTENSION;
943}
944
945impl X509Extension {
946 #[deprecated(
960 note = "Use x509::extension types or new_from_der instead",
961 since = "0.10.51"
962 )]
963 pub fn new(
964 conf: Option<&ConfRef>,
965 context: Option<&X509v3Context<'_>>,
966 name: &str,
967 value: &str,
968 ) -> Result<X509Extension, ErrorStack> {
969 let name = CString::new(name).unwrap();
970 let value = CString::new(value).unwrap();
971 let mut ctx;
972 unsafe {
973 ffi::init();
974 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
975 let context_ptr = match context {
976 Some(c) => c.as_ptr(),
977 None => {
978 ctx = mem::zeroed();
979
980 ffi::X509V3_set_ctx(
981 &mut ctx,
982 ptr::null_mut(),
983 ptr::null_mut(),
984 ptr::null_mut(),
985 ptr::null_mut(),
986 0,
987 );
988 &mut ctx
989 }
990 };
991 let name = name.as_ptr() as *mut _;
992 let value = value.as_ptr() as *mut _;
993
994 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
995 }
996 }
997
998 #[deprecated(
1012 note = "Use x509::extension types or new_from_der instead",
1013 since = "0.10.51"
1014 )]
1015 pub fn new_nid(
1016 conf: Option<&ConfRef>,
1017 context: Option<&X509v3Context<'_>>,
1018 name: Nid,
1019 value: &str,
1020 ) -> Result<X509Extension, ErrorStack> {
1021 let value = CString::new(value).unwrap();
1022 let mut ctx;
1023 unsafe {
1024 ffi::init();
1025 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
1026 let context_ptr = match context {
1027 Some(c) => c.as_ptr(),
1028 None => {
1029 ctx = mem::zeroed();
1030
1031 ffi::X509V3_set_ctx(
1032 &mut ctx,
1033 ptr::null_mut(),
1034 ptr::null_mut(),
1035 ptr::null_mut(),
1036 ptr::null_mut(),
1037 0,
1038 );
1039 &mut ctx
1040 }
1041 };
1042 let name = name.as_raw();
1043 let value = value.as_ptr() as *mut _;
1044
1045 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
1046 }
1047 }
1048
1049 pub fn new_from_der(
1059 oid: &Asn1ObjectRef,
1060 critical: bool,
1061 der_contents: &Asn1OctetStringRef,
1062 ) -> Result<X509Extension, ErrorStack> {
1063 unsafe {
1064 cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1065 ptr::null_mut(),
1066 oid.as_ptr(),
1067 critical as _,
1068 der_contents.as_ptr(),
1069 ))
1070 .map(X509Extension)
1071 }
1072 }
1073
1074 pub fn new_subject_alt_name(
1076 stack: Stack<GeneralName>,
1077 critical: bool,
1078 ) -> Result<X509Extension, ErrorStack> {
1079 unsafe { Self::new_internal(Nid::SUBJECT_ALT_NAME, critical, stack.as_ptr().cast()) }
1080 }
1081
1082 pub(crate) unsafe fn new_internal(
1083 nid: Nid,
1084 critical: bool,
1085 value: *mut c_void,
1086 ) -> Result<X509Extension, ErrorStack> {
1087 ffi::init();
1088 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1089 }
1090
1091 #[cfg(not(libressl390))]
1097 #[corresponds(X509V3_EXT_add_alias)]
1098 #[deprecated(
1099 note = "Use x509::extension types or new_from_der and then this is not necessary",
1100 since = "0.10.51"
1101 )]
1102 pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1103 ffi::init();
1104 cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1105 }
1106}
1107
1108impl X509ExtensionRef {
1109 to_der! {
1110 #[corresponds(i2d_X509_EXTENSION)]
1112 to_der,
1113 ffi::i2d_X509_EXTENSION
1114 }
1115}
1116
1117pub struct X509NameBuilder(X509Name);
1119
1120impl X509NameBuilder {
1121 pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1123 unsafe {
1124 ffi::init();
1125 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1126 }
1127 }
1128
1129 #[corresponds(X509_NAME_add_entry)]
1131 pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1132 unsafe {
1133 cvt(ffi::X509_NAME_add_entry(
1134 self.0.as_ptr(),
1135 ne.as_ptr(),
1136 -1,
1137 0,
1138 ))
1139 .map(|_| ())
1140 }
1141 }
1142
1143 #[corresponds(X509_NAME_add_entry_by_txt)]
1145 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1146 unsafe {
1147 let field = CString::new(field).unwrap();
1148 assert!(value.len() <= crate::SLenType::MAX as usize);
1149 cvt(ffi::X509_NAME_add_entry_by_txt(
1150 self.0.as_ptr(),
1151 field.as_ptr() as *mut _,
1152 ffi::MBSTRING_UTF8,
1153 value.as_ptr(),
1154 value.len() as crate::SLenType,
1155 -1,
1156 0,
1157 ))
1158 .map(|_| ())
1159 }
1160 }
1161
1162 #[corresponds(X509_NAME_add_entry_by_txt)]
1164 pub fn append_entry_by_text_with_type(
1165 &mut self,
1166 field: &str,
1167 value: &str,
1168 ty: Asn1Type,
1169 ) -> Result<(), ErrorStack> {
1170 unsafe {
1171 let field = CString::new(field).unwrap();
1172 assert!(value.len() <= crate::SLenType::MAX as usize);
1173 cvt(ffi::X509_NAME_add_entry_by_txt(
1174 self.0.as_ptr(),
1175 field.as_ptr() as *mut _,
1176 ty.as_raw(),
1177 value.as_ptr(),
1178 value.len() as crate::SLenType,
1179 -1,
1180 0,
1181 ))
1182 .map(|_| ())
1183 }
1184 }
1185
1186 #[corresponds(X509_NAME_add_entry_by_NID)]
1188 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1189 unsafe {
1190 assert!(value.len() <= crate::SLenType::MAX as usize);
1191 cvt(ffi::X509_NAME_add_entry_by_NID(
1192 self.0.as_ptr(),
1193 field.as_raw(),
1194 ffi::MBSTRING_UTF8,
1195 value.as_ptr() as *mut _,
1196 value.len() as crate::SLenType,
1197 -1,
1198 0,
1199 ))
1200 .map(|_| ())
1201 }
1202 }
1203
1204 #[corresponds(X509_NAME_add_entry_by_NID)]
1206 pub fn append_entry_by_nid_with_type(
1207 &mut self,
1208 field: Nid,
1209 value: &str,
1210 ty: Asn1Type,
1211 ) -> Result<(), ErrorStack> {
1212 unsafe {
1213 assert!(value.len() <= crate::SLenType::MAX as usize);
1214 cvt(ffi::X509_NAME_add_entry_by_NID(
1215 self.0.as_ptr(),
1216 field.as_raw(),
1217 ty.as_raw(),
1218 value.as_ptr() as *mut _,
1219 value.len() as crate::SLenType,
1220 -1,
1221 0,
1222 ))
1223 .map(|_| ())
1224 }
1225 }
1226
1227 pub fn build(self) -> X509Name {
1229 X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1233 }
1234}
1235
1236foreign_type_and_impl_send_sync! {
1237 type CType = ffi::X509_NAME;
1238 fn drop = ffi::X509_NAME_free;
1239
1240 pub struct X509Name;
1242 pub struct X509NameRef;
1244}
1245
1246impl X509Name {
1247 pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1249 X509NameBuilder::new()
1250 }
1251
1252 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1256 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1257 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1258 }
1259
1260 from_der! {
1261 from_der,
1267 X509Name,
1268 ffi::d2i_X509_NAME
1269 }
1270}
1271
1272impl Stackable for X509Name {
1273 type StackType = ffi::stack_st_X509_NAME;
1274}
1275
1276impl X509NameRef {
1277 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1279 X509NameEntries {
1280 name: self,
1281 nid: Some(nid),
1282 loc: -1,
1283 }
1284 }
1285
1286 pub fn entries(&self) -> X509NameEntries<'_> {
1288 X509NameEntries {
1289 name: self,
1290 nid: None,
1291 loc: -1,
1292 }
1293 }
1294
1295 #[corresponds(X509_NAME_cmp)]
1302 pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1303 let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1304 if cfg!(ossl300) && cmp == -2 {
1305 return Err(ErrorStack::get());
1306 }
1307 Ok(cmp.cmp(&0))
1308 }
1309
1310 #[corresponds(X509_NAME_dup)]
1312 #[cfg(any(boringssl, ossl110, libressl, awslc))]
1313 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1314 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1315 }
1316
1317 to_der! {
1318 to_der,
1324 ffi::i2d_X509_NAME
1325 }
1326
1327 digest! {
1328 digest,
1334 ffi::X509_NAME_digest
1335 }
1336}
1337
1338impl fmt::Debug for X509NameRef {
1339 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1340 formatter.debug_list().entries(self.entries()).finish()
1341 }
1342}
1343
1344pub struct X509NameEntries<'a> {
1346 name: &'a X509NameRef,
1347 nid: Option<Nid>,
1348 loc: c_int,
1349}
1350
1351impl<'a> Iterator for X509NameEntries<'a> {
1352 type Item = &'a X509NameEntryRef;
1353
1354 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1355 unsafe {
1356 match self.nid {
1357 Some(nid) => {
1358 self.loc =
1360 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1361 if self.loc == -1 {
1362 return None;
1363 }
1364 }
1365 None => {
1366 self.loc += 1;
1368 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1369 return None;
1370 }
1371 }
1372 }
1373
1374 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1375
1376 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1377 }
1378 }
1379}
1380
1381foreign_type_and_impl_send_sync! {
1382 type CType = ffi::X509_NAME_ENTRY;
1383 fn drop = ffi::X509_NAME_ENTRY_free;
1384
1385 pub struct X509NameEntry;
1387 pub struct X509NameEntryRef;
1389}
1390
1391impl X509NameEntryRef {
1392 #[corresponds(X509_NAME_ENTRY_get_data)]
1394 pub fn data(&self) -> &Asn1StringRef {
1395 unsafe {
1396 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1397 Asn1StringRef::from_ptr(data)
1398 }
1399 }
1400
1401 #[corresponds(X509_NAME_ENTRY_get_object)]
1404 pub fn object(&self) -> &Asn1ObjectRef {
1405 unsafe {
1406 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1407 Asn1ObjectRef::from_ptr(object)
1408 }
1409 }
1410}
1411
1412impl fmt::Debug for X509NameEntryRef {
1413 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1414 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1415 }
1416}
1417
1418foreign_type_and_impl_send_sync! {
1419 type CType = ffi::X509_PUBKEY;
1420 fn drop = ffi::X509_PUBKEY_free;
1421
1422 pub struct X509Pubkey;
1424 pub struct X509PubkeyRef;
1426}
1427
1428impl X509Pubkey {
1429 from_der! {
1430 from_der,
1436 X509Pubkey,
1437 ffi::d2i_X509_PUBKEY
1438 }
1439
1440 pub fn from_pubkey<T>(key: &PKeyRef<T>) -> Result<Self, ErrorStack>
1446 where
1447 T: HasPublic,
1448 {
1449 let mut p = ptr::null_mut();
1450 unsafe {
1451 cvt(ffi::X509_PUBKEY_set(&mut p as *mut _, key.as_ptr()))?;
1452 }
1453 Ok(X509Pubkey(p))
1454 }
1455}
1456
1457impl X509PubkeyRef {
1458 #[corresponds(X509_PUBKEY_dup)]
1460 #[cfg(ossl300)]
1461 pub fn to_owned(&self) -> Result<X509Pubkey, ErrorStack> {
1462 unsafe { cvt_p(ffi::X509_PUBKEY_dup(self.as_ptr())).map(|n| X509Pubkey::from_ptr(n)) }
1463 }
1464
1465 to_der! {
1466 to_der,
1472 ffi::i2d_X509_PUBKEY
1473 }
1474
1475 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1481 unsafe {
1482 let key = cvt_p(ffi::X509_PUBKEY_get(self.as_ptr()))?;
1483 Ok(PKey::from_ptr(key))
1484 }
1485 }
1486
1487 pub fn encoded_bytes(&self) -> Result<&[u8], ErrorStack> {
1493 unsafe {
1494 let mut pk = ptr::null_mut() as *const c_uchar;
1495 let mut pkt_len: c_int = 0;
1496 cvt(ffi::X509_PUBKEY_get0_param(
1497 ptr::null_mut(),
1498 &mut pk as *mut _,
1499 &mut pkt_len as *mut _,
1500 ptr::null_mut(),
1501 self.as_ptr(),
1502 ))?;
1503
1504 Ok(util::from_raw_parts(pk, pkt_len as usize))
1505 }
1506 }
1507}
1508
1509pub struct X509ReqBuilder(X509Req);
1511
1512impl X509ReqBuilder {
1513 #[corresponds(X509_REQ_new)]
1515 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1516 unsafe {
1517 ffi::init();
1518 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1519 }
1520 }
1521
1522 #[corresponds(X509_REQ_set_version)]
1524 #[allow(clippy::useless_conversion)]
1525 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1526 unsafe {
1527 cvt(ffi::X509_REQ_set_version(
1528 self.0.as_ptr(),
1529 version as c_long,
1530 ))
1531 .map(|_| ())
1532 }
1533 }
1534
1535 #[corresponds(X509_REQ_set_subject_name)]
1537 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1538 unsafe {
1539 cvt(ffi::X509_REQ_set_subject_name(
1540 self.0.as_ptr(),
1541 subject_name.as_ptr(),
1542 ))
1543 .map(|_| ())
1544 }
1545 }
1546
1547 #[corresponds(X509_REQ_set_pubkey)]
1549 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1550 where
1551 T: HasPublic,
1552 {
1553 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1554 }
1555
1556 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1559 unsafe {
1560 let mut ctx = mem::zeroed();
1561
1562 ffi::X509V3_set_ctx(
1563 &mut ctx,
1564 ptr::null_mut(),
1565 ptr::null_mut(),
1566 self.0.as_ptr(),
1567 ptr::null_mut(),
1568 0,
1569 );
1570
1571 if let Some(conf) = conf {
1573 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1574 }
1575
1576 X509v3Context(ctx, PhantomData)
1577 }
1578 }
1579
1580 pub fn add_extensions(
1582 &mut self,
1583 extensions: &StackRef<X509Extension>,
1584 ) -> Result<(), ErrorStack> {
1585 unsafe {
1586 cvt(ffi::X509_REQ_add_extensions(
1587 self.0.as_ptr(),
1588 extensions.as_ptr(),
1589 ))
1590 .map(|_| ())
1591 }
1592 }
1593
1594 #[corresponds(X509_REQ_sign)]
1596 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1597 where
1598 T: HasPrivate,
1599 {
1600 unsafe {
1601 cvt(ffi::X509_REQ_sign(
1602 self.0.as_ptr(),
1603 key.as_ptr(),
1604 hash.as_ptr(),
1605 ))
1606 .map(|_| ())
1607 }
1608 }
1609
1610 pub fn build(self) -> X509Req {
1612 self.0
1613 }
1614}
1615
1616foreign_type_and_impl_send_sync! {
1617 type CType = ffi::X509_REQ;
1618 fn drop = ffi::X509_REQ_free;
1619
1620 pub struct X509Req;
1622 pub struct X509ReqRef;
1624}
1625
1626impl X509Req {
1627 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1629 X509ReqBuilder::new()
1630 }
1631
1632 from_pem! {
1633 from_pem,
1641 X509Req,
1642 ffi::PEM_read_bio_X509_REQ
1643 }
1644
1645 from_der! {
1646 from_der,
1652 X509Req,
1653 ffi::d2i_X509_REQ
1654 }
1655}
1656
1657impl X509ReqRef {
1658 to_pem! {
1659 to_pem,
1667 ffi::PEM_write_bio_X509_REQ
1668 }
1669
1670 to_der! {
1671 to_der,
1677 ffi::i2d_X509_REQ
1678 }
1679
1680 to_pem! {
1681 #[corresponds(X509_Req_print)]
1683 to_text,
1684 ffi::X509_REQ_print
1685 }
1686
1687 digest! {
1688 digest,
1694 ffi::X509_REQ_digest
1695 }
1696
1697 #[corresponds(X509_REQ_get_version)]
1699 #[allow(clippy::unnecessary_cast)]
1700 pub fn version(&self) -> i32 {
1701 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1702 }
1703
1704 #[corresponds(X509_REQ_get_subject_name)]
1706 pub fn subject_name(&self) -> &X509NameRef {
1707 unsafe {
1708 let name = X509_REQ_get_subject_name(self.as_ptr());
1709 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1710 }
1711 }
1712
1713 #[corresponds(X509_REQ_get_pubkey)]
1715 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1716 unsafe {
1717 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1718 Ok(PKey::from_ptr(key))
1719 }
1720 }
1721
1722 #[cfg(ossl110)]
1728 pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
1729 unsafe {
1730 let key = cvt_p(ffi::X509_REQ_get_X509_PUBKEY(self.as_ptr()))?;
1731 Ok(X509PubkeyRef::from_ptr(key))
1732 }
1733 }
1734
1735 #[corresponds(X509_REQ_verify)]
1739 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1740 where
1741 T: HasPublic,
1742 {
1743 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1744 }
1745
1746 #[corresponds(X509_REQ_get_extensions)]
1748 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1749 unsafe {
1750 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1751 Ok(Stack::from_ptr(extensions))
1752 }
1753 }
1754}
1755
1756#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1758pub struct CrlReason(c_int);
1759
1760#[allow(missing_docs)] impl CrlReason {
1762 pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1763 pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1764 pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1765 pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1766 pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1767 pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1768 pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1769 pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1770 pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1771 pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1772
1773 pub const fn from_raw(value: c_int) -> Self {
1775 CrlReason(value)
1776 }
1777
1778 pub const fn as_raw(&self) -> c_int {
1780 self.0
1781 }
1782}
1783
1784foreign_type_and_impl_send_sync! {
1785 type CType = ffi::X509_REVOKED;
1786 fn drop = ffi::X509_REVOKED_free;
1787
1788 pub struct X509Revoked;
1790 pub struct X509RevokedRef;
1792}
1793
1794impl Stackable for X509Revoked {
1795 type StackType = ffi::stack_st_X509_REVOKED;
1796}
1797
1798impl X509Revoked {
1799 from_der! {
1800 #[corresponds(d2i_X509_REVOKED)]
1802 from_der,
1803 X509Revoked,
1804 ffi::d2i_X509_REVOKED
1805 }
1806}
1807
1808impl X509RevokedRef {
1809 to_der! {
1810 #[corresponds(d2i_X509_REVOKED)]
1812 to_der,
1813 ffi::i2d_X509_REVOKED
1814 }
1815
1816 #[corresponds(X509_NAME_dup)]
1818 #[cfg(any(boringssl, ossl110, libressl, awslc))]
1819 pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1820 unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1821 }
1822
1823 #[corresponds(X509_REVOKED_get0_revocationDate)]
1825 pub fn revocation_date(&self) -> &Asn1TimeRef {
1826 unsafe {
1827 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1828 assert!(!r.is_null());
1829 Asn1TimeRef::from_ptr(r as *mut _)
1830 }
1831 }
1832
1833 #[corresponds(X509_REVOKED_get0_serialNumber)]
1835 pub fn serial_number(&self) -> &Asn1IntegerRef {
1836 unsafe {
1837 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1838 assert!(!r.is_null());
1839 Asn1IntegerRef::from_ptr(r as *mut _)
1840 }
1841 }
1842
1843 #[corresponds(X509_REVOKED_get_ext_d2i)]
1847 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1848 let mut critical = -1;
1849 let out = unsafe {
1850 let ext = ffi::X509_REVOKED_get_ext_d2i(
1852 self.as_ptr(),
1853 T::NID.as_raw(),
1854 &mut critical as *mut _,
1855 ptr::null_mut(),
1856 );
1857 T::Output::from_ptr_opt(ext as *mut _)
1860 };
1861 match (critical, out) {
1862 (0, Some(out)) => Ok(Some((false, out))),
1863 (1, Some(out)) => Ok(Some((true, out))),
1864 (-1 | -2, _) => Ok(None),
1866 (0 | 1, None) => Err(ErrorStack::get()),
1869 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1870 }
1871 }
1872}
1873
1874pub enum ReasonCode {}
1877
1878unsafe impl ExtensionType for ReasonCode {
1881 const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1882
1883 type Output = Asn1Enumerated;
1884}
1885
1886pub enum CertificateIssuer {}
1889
1890unsafe impl ExtensionType for CertificateIssuer {
1893 const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1894
1895 type Output = Stack<GeneralName>;
1896}
1897
1898pub enum AuthorityInformationAccess {}
1900
1901unsafe impl ExtensionType for AuthorityInformationAccess {
1904 const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1905
1906 type Output = Stack<AccessDescription>;
1907}
1908
1909foreign_type_and_impl_send_sync! {
1910 type CType = ffi::X509_CRL;
1911 fn drop = ffi::X509_CRL_free;
1912
1913 pub struct X509Crl;
1915 pub struct X509CrlRef;
1917}
1918
1919pub enum CrlStatus<'a> {
1925 NotRevoked,
1927 Revoked(&'a X509RevokedRef),
1929 RemoveFromCrl(&'a X509RevokedRef),
1934}
1935
1936impl<'a> CrlStatus<'a> {
1937 unsafe fn from_ffi_status(
1942 status: c_int,
1943 revoked_entry: *mut ffi::X509_REVOKED,
1944 ) -> CrlStatus<'a> {
1945 match status {
1946 0 => CrlStatus::NotRevoked,
1947 1 => {
1948 assert!(!revoked_entry.is_null());
1949 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1950 }
1951 2 => {
1952 assert!(!revoked_entry.is_null());
1953 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1954 }
1955 _ => unreachable!(
1956 "{}",
1957 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1958 ),
1959 }
1960 }
1961}
1962
1963impl X509Crl {
1964 from_pem! {
1965 #[corresponds(PEM_read_bio_X509_CRL)]
1969 from_pem,
1970 X509Crl,
1971 ffi::PEM_read_bio_X509_CRL
1972 }
1973
1974 from_der! {
1975 #[corresponds(d2i_X509_CRL)]
1977 from_der,
1978 X509Crl,
1979 ffi::d2i_X509_CRL
1980 }
1981}
1982
1983impl X509CrlRef {
1984 to_pem! {
1985 #[corresponds(PEM_write_bio_X509_CRL)]
1989 to_pem,
1990 ffi::PEM_write_bio_X509_CRL
1991 }
1992
1993 to_der! {
1994 #[corresponds(i2d_X509_CRL)]
1996 to_der,
1997 ffi::i2d_X509_CRL
1998 }
1999
2000 digest! {
2001 digest,
2007 ffi::X509_CRL_digest
2008 }
2009
2010 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
2012 unsafe {
2013 let revoked = X509_CRL_get_REVOKED(self.as_ptr());
2014 if revoked.is_null() {
2015 None
2016 } else {
2017 Some(StackRef::from_ptr(revoked))
2018 }
2019 }
2020 }
2021
2022 #[corresponds(X509_CRL_get0_lastUpdate)]
2024 pub fn last_update(&self) -> &Asn1TimeRef {
2025 unsafe {
2026 let date = X509_CRL_get0_lastUpdate(self.as_ptr());
2027 assert!(!date.is_null());
2028 Asn1TimeRef::from_ptr(date as *mut _)
2029 }
2030 }
2031
2032 #[corresponds(X509_CRL_get0_nextUpdate)]
2036 pub fn next_update(&self) -> Option<&Asn1TimeRef> {
2037 unsafe {
2038 let date = X509_CRL_get0_nextUpdate(self.as_ptr());
2039 Asn1TimeRef::from_const_ptr_opt(date)
2040 }
2041 }
2042
2043 #[corresponds(X509_CRL_get0_by_serial)]
2045 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
2046 unsafe {
2047 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2048 let status =
2049 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
2050 CrlStatus::from_ffi_status(status, ret)
2051 }
2052 }
2053
2054 #[corresponds(X509_CRL_get0_by_cert)]
2056 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
2057 unsafe {
2058 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2059 let status =
2060 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
2061 CrlStatus::from_ffi_status(status, ret)
2062 }
2063 }
2064
2065 #[corresponds(X509_CRL_get_issuer)]
2067 pub fn issuer_name(&self) -> &X509NameRef {
2068 unsafe {
2069 let name = X509_CRL_get_issuer(self.as_ptr());
2070 assert!(!name.is_null());
2071 X509NameRef::from_ptr(name)
2072 }
2073 }
2074
2075 #[corresponds(X509_CRL_verify)]
2082 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
2083 where
2084 T: HasPublic,
2085 {
2086 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
2087 }
2088
2089 #[corresponds(X509_CRL_get_ext_d2i)]
2093 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
2094 let mut critical = -1;
2095 let out = unsafe {
2096 let ext = ffi::X509_CRL_get_ext_d2i(
2098 self.as_ptr(),
2099 T::NID.as_raw(),
2100 &mut critical as *mut _,
2101 ptr::null_mut(),
2102 );
2103 T::Output::from_ptr_opt(ext as *mut _)
2106 };
2107 match (critical, out) {
2108 (0, Some(out)) => Ok(Some((false, out))),
2109 (1, Some(out)) => Ok(Some((true, out))),
2110 (-1 | -2, _) => Ok(None),
2112 (0 | 1, None) => Err(ErrorStack::get()),
2115 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
2116 }
2117 }
2118}
2119
2120#[derive(Copy, Clone, PartialEq, Eq)]
2122pub struct X509VerifyResult(c_int);
2123
2124impl fmt::Debug for X509VerifyResult {
2125 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2126 fmt.debug_struct("X509VerifyResult")
2127 .field("code", &self.0)
2128 .field("error", &self.error_string())
2129 .finish()
2130 }
2131}
2132
2133impl fmt::Display for X509VerifyResult {
2134 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2135 fmt.write_str(self.error_string())
2136 }
2137}
2138
2139impl Error for X509VerifyResult {}
2140
2141impl X509VerifyResult {
2142 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
2149 X509VerifyResult(err)
2150 }
2151
2152 #[allow(clippy::trivially_copy_pass_by_ref)]
2154 pub fn as_raw(&self) -> c_int {
2155 self.0
2156 }
2157
2158 #[corresponds(X509_verify_cert_error_string)]
2160 #[allow(clippy::trivially_copy_pass_by_ref)]
2161 pub fn error_string(&self) -> &'static str {
2162 ffi::init();
2163
2164 unsafe {
2165 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
2166 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
2167 }
2168 }
2169
2170 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
2172 pub const APPLICATION_VERIFICATION: X509VerifyResult =
2174 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
2175}
2176
2177foreign_type_and_impl_send_sync! {
2178 type CType = ffi::GENERAL_NAME;
2179 fn drop = ffi::GENERAL_NAME_free;
2180
2181 pub struct GeneralName;
2183 pub struct GeneralNameRef;
2185}
2186
2187impl GeneralName {
2188 unsafe fn new(
2189 type_: c_int,
2190 asn1_type: Asn1Type,
2191 value: &[u8],
2192 ) -> Result<GeneralName, ErrorStack> {
2193 ffi::init();
2194 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2195 (*gn.as_ptr()).type_ = type_;
2196 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2197 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2198
2199 #[cfg(any(boringssl, awslc))]
2200 {
2201 (*gn.as_ptr()).d.ptr = s.cast();
2202 }
2203 #[cfg(not(any(boringssl, awslc)))]
2204 {
2205 (*gn.as_ptr()).d = s.cast();
2206 }
2207
2208 Ok(gn)
2209 }
2210
2211 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2212 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2213 }
2214
2215 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2216 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2217 }
2218
2219 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2220 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2221 }
2222
2223 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2224 match ip {
2225 IpAddr::V4(addr) => unsafe {
2226 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2227 },
2228 IpAddr::V6(addr) => unsafe {
2229 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2230 },
2231 }
2232 }
2233
2234 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2235 unsafe {
2236 ffi::init();
2237 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2238 (*gn).type_ = ffi::GEN_RID;
2239
2240 #[cfg(any(boringssl, awslc))]
2241 {
2242 (*gn).d.registeredID = oid.as_ptr();
2243 }
2244 #[cfg(not(any(boringssl, awslc)))]
2245 {
2246 (*gn).d = oid.as_ptr().cast();
2247 }
2248
2249 mem::forget(oid);
2250
2251 Ok(GeneralName::from_ptr(gn))
2252 }
2253 }
2254
2255 pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2256 unsafe {
2257 ffi::init();
2258
2259 let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2260 ptr::null_mut(),
2261 &mut value.as_ptr().cast(),
2262 value.len().try_into().unwrap(),
2263 ))?;
2264
2265 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2266 (*gn).type_ = ffi::GEN_OTHERNAME;
2267
2268 if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2269 gn,
2270 oid.as_ptr().cast(),
2271 typ,
2272 )) {
2273 ffi::GENERAL_NAME_free(gn);
2274 return Err(e);
2275 }
2276
2277 mem::forget(oid);
2278
2279 Ok(GeneralName::from_ptr(gn))
2280 }
2281 }
2282}
2283
2284impl GeneralNameRef {
2285 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2286 unsafe {
2287 if (*self.as_ptr()).type_ != ffi_type {
2288 return None;
2289 }
2290
2291 #[cfg(any(boringssl, awslc))]
2292 let d = (*self.as_ptr()).d.ptr;
2293 #[cfg(not(any(boringssl, awslc)))]
2294 let d = (*self.as_ptr()).d;
2295
2296 let ptr = ASN1_STRING_get0_data(d as *mut _);
2297 let len = ffi::ASN1_STRING_length(d as *mut _);
2298
2299 #[allow(clippy::unnecessary_cast)]
2300 let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2301 str::from_utf8(slice).ok()
2305 }
2306 }
2307
2308 pub fn email(&self) -> Option<&str> {
2310 self.ia5_string(ffi::GEN_EMAIL)
2311 }
2312
2313 pub fn directory_name(&self) -> Option<&X509NameRef> {
2315 unsafe {
2316 if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2317 return None;
2318 }
2319
2320 #[cfg(any(boringssl, awslc))]
2321 let d = (*self.as_ptr()).d.ptr;
2322 #[cfg(not(any(boringssl, awslc)))]
2323 let d = (*self.as_ptr()).d;
2324
2325 Some(X509NameRef::from_const_ptr(d as *const _))
2326 }
2327 }
2328
2329 pub fn dnsname(&self) -> Option<&str> {
2331 self.ia5_string(ffi::GEN_DNS)
2332 }
2333
2334 pub fn uri(&self) -> Option<&str> {
2336 self.ia5_string(ffi::GEN_URI)
2337 }
2338
2339 pub fn ipaddress(&self) -> Option<&[u8]> {
2341 unsafe {
2342 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2343 return None;
2344 }
2345 #[cfg(any(boringssl, awslc))]
2346 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2347 #[cfg(not(any(boringssl, awslc)))]
2348 let d = (*self.as_ptr()).d;
2349
2350 let ptr = ASN1_STRING_get0_data(d as *mut _);
2351 let len = ffi::ASN1_STRING_length(d as *mut _);
2352
2353 #[allow(clippy::unnecessary_cast)]
2354 Some(util::from_raw_parts(ptr as *const u8, len as usize))
2355 }
2356 }
2357}
2358
2359impl fmt::Debug for GeneralNameRef {
2360 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2361 if let Some(email) = self.email() {
2362 formatter.write_str(email)
2363 } else if let Some(dnsname) = self.dnsname() {
2364 formatter.write_str(dnsname)
2365 } else if let Some(uri) = self.uri() {
2366 formatter.write_str(uri)
2367 } else if let Some(ipaddress) = self.ipaddress() {
2368 let address = <[u8; 16]>::try_from(ipaddress)
2369 .map(IpAddr::from)
2370 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2371 match address {
2372 Ok(a) => fmt::Debug::fmt(&a, formatter),
2373 Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2374 }
2375 } else {
2376 formatter.write_str("(empty)")
2377 }
2378 }
2379}
2380
2381impl Stackable for GeneralName {
2382 type StackType = ffi::stack_st_GENERAL_NAME;
2383}
2384
2385foreign_type_and_impl_send_sync! {
2386 type CType = ffi::DIST_POINT;
2387 fn drop = ffi::DIST_POINT_free;
2388
2389 pub struct DistPoint;
2391 pub struct DistPointRef;
2393}
2394
2395impl DistPointRef {
2396 pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2398 unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2399 }
2400}
2401
2402foreign_type_and_impl_send_sync! {
2403 type CType = ffi::DIST_POINT_NAME;
2404 fn drop = ffi::DIST_POINT_NAME_free;
2405
2406 pub struct DistPointName;
2408 pub struct DistPointNameRef;
2410}
2411
2412impl DistPointNameRef {
2413 pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2415 unsafe {
2416 if (*self.as_ptr()).type_ != 0 {
2417 return None;
2418 }
2419 StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2420 }
2421 }
2422}
2423
2424impl Stackable for DistPoint {
2425 type StackType = ffi::stack_st_DIST_POINT;
2426}
2427
2428foreign_type_and_impl_send_sync! {
2429 type CType = ffi::ACCESS_DESCRIPTION;
2430 fn drop = ffi::ACCESS_DESCRIPTION_free;
2431
2432 pub struct AccessDescription;
2434 pub struct AccessDescriptionRef;
2436}
2437
2438impl AccessDescriptionRef {
2439 pub fn method(&self) -> &Asn1ObjectRef {
2441 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2442 }
2443
2444 pub fn location(&self) -> &GeneralNameRef {
2446 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2447 }
2448}
2449
2450impl Stackable for AccessDescription {
2451 type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2452}
2453
2454foreign_type_and_impl_send_sync! {
2455 type CType = ffi::X509_ALGOR;
2456 fn drop = ffi::X509_ALGOR_free;
2457
2458 pub struct X509Algorithm;
2460 pub struct X509AlgorithmRef;
2462}
2463
2464impl X509AlgorithmRef {
2465 pub fn object(&self) -> &Asn1ObjectRef {
2467 unsafe {
2468 let mut oid = ptr::null();
2469 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2470 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2471 }
2472 }
2473}
2474
2475foreign_type_and_impl_send_sync! {
2476 type CType = ffi::X509_OBJECT;
2477 fn drop = X509_OBJECT_free;
2478
2479 pub struct X509Object;
2481 pub struct X509ObjectRef;
2483}
2484
2485impl X509ObjectRef {
2486 pub fn x509(&self) -> Option<&X509Ref> {
2487 unsafe {
2488 let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2489 X509Ref::from_const_ptr_opt(ptr)
2490 }
2491 }
2492}
2493
2494impl Stackable for X509Object {
2495 type StackType = ffi::stack_st_X509_OBJECT;
2496}
2497
2498cfg_if! {
2499 if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2500 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2501 } else {
2502 #[allow(bad_style)]
2503 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2504 (*(*(*x).cert_info).validity).notAfter
2505 }
2506
2507 #[allow(bad_style)]
2508 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2509 (*(*(*x).cert_info).validity).notBefore
2510 }
2511
2512 #[allow(bad_style)]
2513 unsafe fn X509_up_ref(x: *mut ffi::X509) {
2514 ffi::CRYPTO_add_lock(
2515 &mut (*x).references,
2516 1,
2517 ffi::CRYPTO_LOCK_X509,
2518 "mod.rs\0".as_ptr() as *const _,
2519 line!() as c_int,
2520 );
2521 }
2522
2523 #[allow(bad_style)]
2524 unsafe fn X509_get0_signature(
2525 psig: *mut *const ffi::ASN1_BIT_STRING,
2526 palg: *mut *const ffi::X509_ALGOR,
2527 x: *const ffi::X509,
2528 ) {
2529 if !psig.is_null() {
2530 *psig = (*x).signature;
2531 }
2532 if !palg.is_null() {
2533 *palg = (*x).sig_alg;
2534 }
2535 }
2536 }
2537}
2538
2539cfg_if! {
2540 if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2541 use ffi::{
2542 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2543 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2544 };
2545 } else {
2546 use ffi::{
2547 ASN1_STRING_data as ASN1_STRING_get0_data,
2548 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2549 X509_set_notAfter as X509_set1_notAfter,
2550 X509_set_notBefore as X509_set1_notBefore,
2551 };
2552
2553 #[allow(bad_style)]
2554 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2555 ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2556 }
2557
2558 #[allow(bad_style)]
2559 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2560 (*(*x).req_info).subject
2561 }
2562
2563 #[allow(bad_style)]
2564 unsafe fn X509_ALGOR_get0(
2565 paobj: *mut *const ffi::ASN1_OBJECT,
2566 pptype: *mut c_int,
2567 pval: *mut *mut ::libc::c_void,
2568 alg: *const ffi::X509_ALGOR,
2569 ) {
2570 if !paobj.is_null() {
2571 *paobj = (*alg).algorithm;
2572 }
2573 assert!(pptype.is_null());
2574 assert!(pval.is_null());
2575 }
2576 }
2577}
2578
2579cfg_if! {
2580 if #[cfg(any(ossl110, boringssl, libressl, awslc))] {
2581 use ffi::X509_OBJECT_get0_X509;
2582 } else {
2583 #[allow(bad_style)]
2584 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2585 if (*x).type_ == ffi::X509_LU_X509 {
2586 (*x).data.x509
2587 } else {
2588 ptr::null_mut()
2589 }
2590 }
2591 }
2592}
2593
2594cfg_if! {
2595 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2596 use ffi::X509_OBJECT_free;
2597 } else {
2598 #[allow(bad_style)]
2599 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2600 ffi::X509_OBJECT_free_contents(x);
2601 ffi::CRYPTO_free(x as *mut libc::c_void);
2602 }
2603 }
2604}
2605
2606cfg_if! {
2607 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2608 use ffi::{
2609 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2610 X509_CRL_get_REVOKED,
2611 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2612 };
2613 } else {
2614 #[allow(bad_style)]
2615 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2616 (*(*x).crl).lastUpdate
2617 }
2618 #[allow(bad_style)]
2619 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2620 (*(*x).crl).nextUpdate
2621 }
2622 #[allow(bad_style)]
2623 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2624 (*(*x).crl).issuer
2625 }
2626 #[allow(bad_style)]
2627 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2628 (*(*x).crl).revoked
2629 }
2630 #[allow(bad_style)]
2631 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2632 (*x).serialNumber
2633 }
2634 #[allow(bad_style)]
2635 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2636 (*x).revocationDate
2637 }
2638 }
2639}
2640
2641#[derive(Copy, Clone, PartialEq, Eq)]
2642pub struct X509PurposeId(c_int);
2643
2644impl X509PurposeId {
2645 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2646 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2647 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2648 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2649 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2650 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2651 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2652 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2653 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2654 #[cfg(ossl320)]
2655 pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2656
2657 pub fn from_raw(id: c_int) -> Self {
2659 X509PurposeId(id)
2660 }
2661
2662 pub fn as_raw(&self) -> c_int {
2664 self.0
2665 }
2666}
2667
2668pub struct X509PurposeRef(Opaque);
2670
2671impl ForeignTypeRef for X509PurposeRef {
2673 type CType = ffi::X509_PURPOSE;
2674}
2675
2676impl X509PurposeRef {
2677 #[allow(clippy::unnecessary_cast)]
2691 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2692 unsafe {
2693 let sname = CString::new(sname).unwrap();
2694 cfg_if! {
2695 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2696 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2697 } else {
2698 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2699 }
2700 }
2701 Ok(purpose)
2702 }
2703 }
2704 #[corresponds(X509_PURPOSE_get0)]
2707 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2708 unsafe {
2709 let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2710 Ok(X509PurposeRef::from_const_ptr(ptr))
2711 }
2712 }
2713
2714 pub fn purpose(&self) -> X509PurposeId {
2725 unsafe {
2726 cfg_if! {
2727 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2728 let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2729 } else {
2730 let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2731 }
2732 }
2733 X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2734 }
2735 }
2736}