1use foreign_types::{ForeignType, ForeignTypeRef};
11use libc::{c_int, c_long, c_void};
12use std::convert::TryInto;
13use std::error::Error;
14use std::ffi::{CStr, CString};
15use std::fmt;
16use std::marker::PhantomData;
17use std::mem;
18use std::net::IpAddr;
19use std::path::Path;
20use std::ptr;
21use std::slice;
22use std::str;
23
24use crate::asn1::{
25 Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef,
26 Asn1Type,
27};
28use crate::bio::MemBioSlice;
29use crate::conf::ConfRef;
30use crate::error::ErrorStack;
31use crate::ex_data::Index;
32use crate::ffi;
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::x509::verify::X509VerifyParamRef;
40use crate::{cvt, cvt_n, cvt_p};
41
42pub mod extension;
43pub mod store;
44pub mod verify;
45
46#[cfg(test)]
47mod tests;
48
49foreign_type_and_impl_send_sync! {
50 type CType = ffi::X509_STORE_CTX;
51 fn drop = ffi::X509_STORE_CTX_free;
52
53 pub struct X509StoreContext;
55}
56
57impl X509StoreContext {
58 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
61 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
62 }
63
64 pub fn new() -> Result<X509StoreContext, ErrorStack> {
70 unsafe {
71 ffi::init();
72 cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext::from_ptr(p))
73 }
74 }
75}
76
77impl X509StoreContextRef {
78 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
84 unsafe {
85 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
86 if data.is_null() {
87 None
88 } else {
89 Some(&*(data as *const T))
90 }
91 }
92 }
93
94 pub fn verify_result(&self) -> X509VerifyResult {
100 unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
101 }
102
103 pub fn init<F, T>(
119 &mut self,
120 trust: &store::X509StoreRef,
121 cert: &X509Ref,
122 cert_chain: &StackRef<X509>,
123 with_context: F,
124 ) -> Result<T, ErrorStack>
125 where
126 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
127 {
128 struct Cleanup<'a>(&'a mut X509StoreContextRef);
129
130 impl<'a> Drop for Cleanup<'a> {
131 fn drop(&mut self) {
132 unsafe {
133 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
134 }
135 }
136 }
137
138 unsafe {
139 cvt(ffi::X509_STORE_CTX_init(
140 self.as_ptr(),
141 trust.as_ptr(),
142 cert.as_ptr(),
143 cert_chain.as_ptr(),
144 ))?;
145
146 let cleanup = Cleanup(self);
147 with_context(cleanup.0)
148 }
149 }
150
151 pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
157 unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) }
158 }
159
160 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
171 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
172 }
173
174 pub fn set_error(&mut self, result: X509VerifyResult) {
180 unsafe {
181 ffi::X509_STORE_CTX_set_error(
182 self.as_ptr(),
183 result
184 .err()
185 .as_ref()
186 .map_or(ffi::X509_V_OK, X509VerifyError::as_raw),
187 );
188 }
189 }
190
191 pub fn current_cert(&self) -> Option<&X509Ref> {
198 unsafe {
199 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
200 if ptr.is_null() {
201 None
202 } else {
203 Some(X509Ref::from_ptr(ptr))
204 }
205 }
206 }
207
208 pub fn error_depth(&self) -> u32 {
217 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
218 }
219
220 pub fn chain(&self) -> Option<&StackRef<X509>> {
226 unsafe {
227 let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
228
229 if chain.is_null() {
230 None
231 } else {
232 Some(StackRef::from_ptr(chain))
233 }
234 }
235 }
236}
237
238pub struct X509Builder(X509);
240
241impl X509Builder {
242 pub fn new() -> Result<X509Builder, ErrorStack> {
244 unsafe {
245 ffi::init();
246 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509::from_ptr(p)))
247 }
248 }
249
250 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
252 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
253 }
254
255 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
257 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
258 }
259
260 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
265 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
266 }
267
268 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
270 unsafe {
271 cvt(ffi::X509_set_serialNumber(
272 self.0.as_ptr(),
273 serial_number.as_ptr(),
274 ))
275 .map(|_| ())
276 }
277 }
278
279 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
281 unsafe {
282 cvt(ffi::X509_set_issuer_name(
283 self.0.as_ptr(),
284 issuer_name.as_ptr(),
285 ))
286 .map(|_| ())
287 }
288 }
289
290 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
309 unsafe {
310 cvt(ffi::X509_set_subject_name(
311 self.0.as_ptr(),
312 subject_name.as_ptr(),
313 ))
314 .map(|_| ())
315 }
316 }
317
318 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
320 where
321 T: HasPublic,
322 {
323 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
324 }
325
326 pub fn x509v3_context<'a>(
330 &'a self,
331 issuer: Option<&'a X509Ref>,
332 conf: Option<&'a ConfRef>,
333 ) -> X509v3Context<'a> {
334 unsafe {
335 let mut ctx = mem::zeroed();
336
337 let issuer = match issuer {
338 Some(issuer) => issuer.as_ptr(),
339 None => self.0.as_ptr(),
340 };
341 let subject = self.0.as_ptr();
342 ffi::X509V3_set_ctx(
343 &mut ctx,
344 issuer,
345 subject,
346 ptr::null_mut(),
347 ptr::null_mut(),
348 0,
349 );
350
351 if let Some(conf) = conf {
353 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
354 }
355
356 X509v3Context(ctx, PhantomData)
357 }
358 }
359
360 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
364 self.append_extension2(&extension)
365 }
366
367 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
373 unsafe {
374 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
375 Ok(())
376 }
377 }
378
379 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
381 where
382 T: HasPrivate,
383 {
384 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
385 }
386
387 pub fn build(self) -> X509 {
389 self.0
390 }
391}
392
393foreign_type_and_impl_send_sync! {
394 type CType = ffi::X509;
395 fn drop = ffi::X509_free;
396
397 pub struct X509;
399}
400
401impl X509Ref {
402 pub fn subject_name(&self) -> &X509NameRef {
408 unsafe {
409 let name = ffi::X509_get_subject_name(self.as_ptr());
410 assert!(!name.is_null());
411 X509NameRef::from_ptr(name)
412 }
413 }
414
415 pub fn subject_name_hash(&self) -> u32 {
419 unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
420 }
421
422 pub fn issuer_name(&self) -> &X509NameRef {
428 unsafe {
429 let name = ffi::X509_get_issuer_name(self.as_ptr());
430 assert!(!name.is_null());
431 X509NameRef::from_ptr(name)
432 }
433 }
434
435 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
441 unsafe {
442 let stack = ffi::X509_get_ext_d2i(
443 self.as_ptr(),
444 ffi::NID_subject_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 issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
462 unsafe {
463 let stack = ffi::X509_get_ext_d2i(
464 self.as_ptr(),
465 ffi::NID_issuer_alt_name,
466 ptr::null_mut(),
467 ptr::null_mut(),
468 );
469 if stack.is_null() {
470 None
471 } else {
472 Some(Stack::from_ptr(stack as *mut _))
473 }
474 }
475 }
476
477 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
478 unsafe {
479 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
480 Ok(PKey::from_ptr(pkey))
481 }
482 }
483
484 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
490 unsafe {
491 let mut digest = DigestBytes {
492 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
493 len: ffi::EVP_MAX_MD_SIZE as usize,
494 };
495 let mut len = ffi::EVP_MAX_MD_SIZE.try_into().unwrap();
496 cvt(ffi::X509_digest(
497 self.as_ptr(),
498 hash_type.as_ptr(),
499 digest.buf.as_mut_ptr() as *mut _,
500 &mut len,
501 ))?;
502 digest.len = len as usize;
503
504 Ok(digest)
505 }
506 }
507
508 #[deprecated(since = "0.10.9", note = "renamed to digest")]
509 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
510 self.digest(hash_type).map(|b| b.to_vec())
511 }
512
513 pub fn not_after(&self) -> &Asn1TimeRef {
515 unsafe {
516 let date = X509_getm_notAfter(self.as_ptr());
517 assert!(!date.is_null());
518 Asn1TimeRef::from_ptr(date)
519 }
520 }
521
522 pub fn not_before(&self) -> &Asn1TimeRef {
524 unsafe {
525 let date = X509_getm_notBefore(self.as_ptr());
526 assert!(!date.is_null());
527 Asn1TimeRef::from_ptr(date)
528 }
529 }
530
531 pub fn signature(&self) -> &Asn1BitStringRef {
533 unsafe {
534 let mut signature = ptr::null();
535 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
536 assert!(!signature.is_null());
537 Asn1BitStringRef::from_ptr(signature as *mut _)
538 }
539 }
540
541 pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
543 unsafe {
544 let mut algor = ptr::null();
545 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
546 assert!(!algor.is_null());
547 X509AlgorithmRef::from_ptr(algor as *mut _)
548 }
549 }
550
551 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
554 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
555 }
556
557 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
559 unsafe {
560 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
561 X509VerifyError::from_raw(r)
562 }
563 }
564
565 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
576 where
577 T: HasPublic,
578 {
579 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
580 }
581
582 pub fn serial_number(&self) -> &Asn1IntegerRef {
588 unsafe {
589 let r = ffi::X509_get_serialNumber(self.as_ptr());
590 assert!(!r.is_null());
591 Asn1IntegerRef::from_ptr(r)
592 }
593 }
594
595 pub fn check_host(&self, host: &str) -> Result<bool, ErrorStack> {
596 unsafe {
597 cvt_n(ffi::X509_check_host(
598 self.as_ptr(),
599 host.as_ptr() as _,
600 host.len(),
601 0,
602 std::ptr::null_mut(),
603 ))
604 .map(|n| n == 1)
605 }
606 }
607
608 to_pem! {
609 to_pem,
617 ffi::PEM_write_bio_X509
618 }
619
620 to_der! {
621 to_der,
627 ffi::i2d_X509
628 }
629}
630
631impl ToOwned for X509Ref {
632 type Owned = X509;
633
634 fn to_owned(&self) -> X509 {
635 unsafe {
636 X509_up_ref(self.as_ptr());
637 X509::from_ptr(self.as_ptr())
638 }
639 }
640}
641
642impl X509 {
643 pub fn builder() -> Result<X509Builder, ErrorStack> {
645 X509Builder::new()
646 }
647
648 from_pem! {
649 from_pem,
657 X509,
658 ffi::PEM_read_bio_X509
659 }
660
661 from_der! {
662 from_der,
668 X509,
669 ffi::d2i_X509,
670 ::libc::c_long
671 }
672
673 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
675 unsafe {
676 ffi::init();
677 let bio = MemBioSlice::new(pem)?;
678
679 let mut certs = vec![];
680 loop {
681 let r =
682 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
683 if r.is_null() {
684 let err = ffi::ERR_peek_last_error();
685
686 if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM.0.try_into().unwrap()
687 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
688 {
689 ffi::ERR_clear_error();
690 break;
691 }
692
693 return Err(ErrorStack::get());
694 } else {
695 certs.push(X509::from_ptr(r));
696 }
697 }
698
699 Ok(certs)
700 }
701 }
702}
703
704impl Clone for X509 {
705 fn clone(&self) -> X509 {
706 X509Ref::to_owned(self)
707 }
708}
709
710impl fmt::Debug for X509 {
711 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
712 let serial = match &self.serial_number().to_bn() {
713 Ok(bn) => match bn.to_hex_str() {
714 Ok(hex) => hex.to_string(),
715 Err(_) => "".to_string(),
716 },
717 Err(_) => "".to_string(),
718 };
719 let mut debug_struct = formatter.debug_struct("X509");
720 debug_struct.field("serial_number", &serial);
721 debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
722 debug_struct.field("issuer", &self.issuer_name());
723 debug_struct.field("subject", &self.subject_name());
724 if let Some(subject_alt_names) = &self.subject_alt_names() {
725 debug_struct.field("subject_alt_names", subject_alt_names);
726 }
727 debug_struct.field("not_before", &self.not_before());
728 debug_struct.field("not_after", &self.not_after());
729
730 if let Ok(public_key) = &self.public_key() {
731 debug_struct.field("public_key", public_key);
732 };
733 debug_struct.finish()
736 }
737}
738
739impl AsRef<X509Ref> for X509Ref {
740 fn as_ref(&self) -> &X509Ref {
741 self
742 }
743}
744
745impl Stackable for X509 {
746 type StackType = ffi::stack_st_X509;
747}
748
749pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
751
752impl<'a> X509v3Context<'a> {
753 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
754 &self.0 as *const _ as *mut _
755 }
756}
757
758foreign_type_and_impl_send_sync! {
759 type CType = ffi::X509_EXTENSION;
760 fn drop = ffi::X509_EXTENSION_free;
761
762 pub struct X509Extension;
764}
765
766impl Stackable for X509Extension {
767 type StackType = ffi::stack_st_X509_EXTENSION;
768}
769
770impl X509Extension {
771 pub fn new(
782 conf: Option<&ConfRef>,
783 context: Option<&X509v3Context>,
784 name: &str,
785 value: &str,
786 ) -> Result<X509Extension, ErrorStack> {
787 let name = CString::new(name).unwrap();
788 let value = CString::new(value).unwrap();
789 let mut ctx;
790 unsafe {
791 ffi::init();
792 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
793 let context_ptr = match context {
794 Some(c) => c.as_ptr(),
795 None => {
796 ctx = mem::zeroed();
797
798 ffi::X509V3_set_ctx(
799 &mut ctx,
800 ptr::null_mut(),
801 ptr::null_mut(),
802 ptr::null_mut(),
803 ptr::null_mut(),
804 0,
805 );
806 &mut ctx
807 }
808 };
809 let name = name.as_ptr() as *mut _;
810 let value = value.as_ptr() as *mut _;
811
812 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value))
813 .map(|p| X509Extension::from_ptr(p))
814 }
815 }
816
817 pub fn new_nid(
828 conf: Option<&ConfRef>,
829 context: Option<&X509v3Context>,
830 name: Nid,
831 value: &str,
832 ) -> Result<X509Extension, ErrorStack> {
833 let value = CString::new(value).unwrap();
834 let mut ctx;
835 unsafe {
836 ffi::init();
837 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
838 let context_ptr = match context {
839 Some(c) => c.as_ptr(),
840 None => {
841 ctx = mem::zeroed();
842
843 ffi::X509V3_set_ctx(
844 &mut ctx,
845 ptr::null_mut(),
846 ptr::null_mut(),
847 ptr::null_mut(),
848 ptr::null_mut(),
849 0,
850 );
851 &mut ctx
852 }
853 };
854 let name = name.as_raw();
855 let value = value.as_ptr() as *mut _;
856
857 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value))
858 .map(|p| X509Extension::from_ptr(p))
859 }
860 }
861
862 pub(crate) unsafe fn new_internal(
863 nid: Nid,
864 critical: bool,
865 value: *mut c_void,
866 ) -> Result<X509Extension, ErrorStack> {
867 ffi::init();
868 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value))
869 .map(|p| X509Extension::from_ptr(p))
870 }
871}
872
873impl X509ExtensionRef {
874 to_der! {
875 to_der,
877 ffi::i2d_X509_EXTENSION
878 }
879}
880
881pub struct X509NameBuilder(X509Name);
883
884impl X509NameBuilder {
885 pub fn new() -> Result<X509NameBuilder, ErrorStack> {
887 unsafe {
888 ffi::init();
889 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name::from_ptr(p)))
890 }
891 }
892
893 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
899 unsafe {
900 let field = CString::new(field).unwrap();
901 assert!(value.len() <= ValueLen::MAX as usize);
902 cvt(ffi::X509_NAME_add_entry_by_txt(
903 self.0.as_ptr(),
904 field.as_ptr() as *mut _,
905 ffi::MBSTRING_UTF8,
906 value.as_ptr(),
907 value.len() as ValueLen,
908 -1,
909 0,
910 ))
911 .map(|_| ())
912 }
913 }
914
915 pub fn append_entry_by_text_with_type(
921 &mut self,
922 field: &str,
923 value: &str,
924 ty: Asn1Type,
925 ) -> Result<(), ErrorStack> {
926 unsafe {
927 let field = CString::new(field).unwrap();
928 assert!(value.len() <= ValueLen::MAX as usize);
929 cvt(ffi::X509_NAME_add_entry_by_txt(
930 self.0.as_ptr(),
931 field.as_ptr() as *mut _,
932 ty.as_raw(),
933 value.as_ptr(),
934 value.len() as ValueLen,
935 -1,
936 0,
937 ))
938 .map(|_| ())
939 }
940 }
941
942 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
948 unsafe {
949 assert!(value.len() <= ValueLen::MAX as usize);
950 cvt(ffi::X509_NAME_add_entry_by_NID(
951 self.0.as_ptr(),
952 field.as_raw(),
953 ffi::MBSTRING_UTF8,
954 value.as_ptr() as *mut _,
955 value.len() as ValueLen,
956 -1,
957 0,
958 ))
959 .map(|_| ())
960 }
961 }
962
963 pub fn append_entry_by_nid_with_type(
969 &mut self,
970 field: Nid,
971 value: &str,
972 ty: Asn1Type,
973 ) -> Result<(), ErrorStack> {
974 unsafe {
975 assert!(value.len() <= ValueLen::MAX as usize);
976 cvt(ffi::X509_NAME_add_entry_by_NID(
977 self.0.as_ptr(),
978 field.as_raw(),
979 ty.as_raw(),
980 value.as_ptr() as *mut _,
981 value.len() as ValueLen,
982 -1,
983 0,
984 ))
985 .map(|_| ())
986 }
987 }
988
989 pub fn build(self) -> X509Name {
991 X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
995 }
996}
997
998#[cfg(not(feature = "fips"))]
999type ValueLen = isize;
1000#[cfg(feature = "fips")]
1001type ValueLen = i32;
1002
1003foreign_type_and_impl_send_sync! {
1004 type CType = ffi::X509_NAME;
1005 fn drop = ffi::X509_NAME_free;
1006
1007 pub struct X509Name;
1009}
1010
1011impl X509Name {
1012 pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1014 X509NameBuilder::new()
1015 }
1016
1017 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1021 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1022 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1023 }
1024
1025 from_der! {
1026 from_der,
1032 X509Name,
1033 ffi::d2i_X509_NAME,
1034 ::libc::c_long
1035 }
1036}
1037
1038impl Stackable for X509Name {
1039 type StackType = ffi::stack_st_X509_NAME;
1040}
1041
1042impl X509NameRef {
1043 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1045 X509NameEntries {
1046 name: self,
1047 nid: Some(nid),
1048 loc: -1,
1049 }
1050 }
1051
1052 pub fn entries(&self) -> X509NameEntries<'_> {
1054 X509NameEntries {
1055 name: self,
1056 nid: None,
1057 loc: -1,
1058 }
1059 }
1060
1061 to_der! {
1062 to_der,
1068 ffi::i2d_X509_NAME
1069 }
1070}
1071
1072impl fmt::Debug for X509NameRef {
1073 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1074 formatter.debug_list().entries(self.entries()).finish()
1075 }
1076}
1077
1078pub struct X509NameEntries<'a> {
1080 name: &'a X509NameRef,
1081 nid: Option<Nid>,
1082 loc: c_int,
1083}
1084
1085impl<'a> Iterator for X509NameEntries<'a> {
1086 type Item = &'a X509NameEntryRef;
1087
1088 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1089 unsafe {
1090 match self.nid {
1091 Some(nid) => {
1092 self.loc =
1094 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1095 if self.loc == -1 {
1096 return None;
1097 }
1098 }
1099 None => {
1100 self.loc += 1;
1102 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1103 return None;
1104 }
1105 }
1106 }
1107
1108 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1109 assert!(!entry.is_null());
1110
1111 Some(X509NameEntryRef::from_ptr(entry))
1112 }
1113 }
1114}
1115
1116foreign_type_and_impl_send_sync! {
1117 type CType = ffi::X509_NAME_ENTRY;
1118 fn drop = ffi::X509_NAME_ENTRY_free;
1119
1120 pub struct X509NameEntry;
1122}
1123
1124impl X509NameEntryRef {
1125 pub fn data(&self) -> &Asn1StringRef {
1131 unsafe {
1132 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1133 Asn1StringRef::from_ptr(data)
1134 }
1135 }
1136
1137 pub fn object(&self) -> &Asn1ObjectRef {
1144 unsafe {
1145 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1146 Asn1ObjectRef::from_ptr(object)
1147 }
1148 }
1149}
1150
1151impl fmt::Debug for X509NameEntryRef {
1152 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1153 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1154 }
1155}
1156
1157pub struct X509ReqBuilder(X509Req);
1159
1160impl X509ReqBuilder {
1161 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1167 unsafe {
1168 ffi::init();
1169 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req::from_ptr(p)))
1170 }
1171 }
1172
1173 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1179 unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
1180 }
1181
1182 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1188 unsafe {
1189 cvt(ffi::X509_REQ_set_subject_name(
1190 self.0.as_ptr(),
1191 subject_name.as_ptr(),
1192 ))
1193 .map(|_| ())
1194 }
1195 }
1196
1197 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1203 where
1204 T: HasPublic,
1205 {
1206 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1207 }
1208
1209 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1212 unsafe {
1213 let mut ctx = mem::zeroed();
1214
1215 ffi::X509V3_set_ctx(
1216 &mut ctx,
1217 ptr::null_mut(),
1218 ptr::null_mut(),
1219 self.0.as_ptr(),
1220 ptr::null_mut(),
1221 0,
1222 );
1223
1224 if let Some(conf) = conf {
1226 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1227 }
1228
1229 X509v3Context(ctx, PhantomData)
1230 }
1231 }
1232
1233 pub fn add_extensions(
1235 &mut self,
1236 extensions: &StackRef<X509Extension>,
1237 ) -> Result<(), ErrorStack> {
1238 unsafe {
1239 cvt(ffi::X509_REQ_add_extensions(
1240 self.0.as_ptr(),
1241 extensions.as_ptr(),
1242 ))
1243 .map(|_| ())
1244 }
1245 }
1246
1247 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1253 where
1254 T: HasPrivate,
1255 {
1256 unsafe {
1257 cvt(ffi::X509_REQ_sign(
1258 self.0.as_ptr(),
1259 key.as_ptr(),
1260 hash.as_ptr(),
1261 ))
1262 .map(|_| ())
1263 }
1264 }
1265
1266 pub fn build(self) -> X509Req {
1268 self.0
1269 }
1270}
1271
1272foreign_type_and_impl_send_sync! {
1273 type CType = ffi::X509_REQ;
1274 fn drop = ffi::X509_REQ_free;
1275
1276 pub struct X509Req;
1278}
1279
1280impl X509Req {
1281 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1283 X509ReqBuilder::new()
1284 }
1285
1286 from_pem! {
1287 from_pem,
1295 X509Req,
1296 ffi::PEM_read_bio_X509_REQ
1297 }
1298
1299 from_der! {
1300 from_der,
1306 X509Req,
1307 ffi::d2i_X509_REQ,
1308 ::libc::c_long
1309 }
1310}
1311
1312impl X509ReqRef {
1313 to_pem! {
1314 to_pem,
1322 ffi::PEM_write_bio_X509_REQ
1323 }
1324
1325 to_der! {
1326 to_der,
1332 ffi::i2d_X509_REQ
1333 }
1334
1335 pub fn version(&self) -> i32 {
1341 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1342 }
1343
1344 pub fn subject_name(&self) -> &X509NameRef {
1350 unsafe {
1351 let name = X509_REQ_get_subject_name(self.as_ptr());
1352 assert!(!name.is_null());
1353 X509NameRef::from_ptr(name)
1354 }
1355 }
1356
1357 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1363 unsafe {
1364 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1365 Ok(PKey::from_ptr(key))
1366 }
1367 }
1368
1369 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1377 where
1378 T: HasPublic,
1379 {
1380 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1381 }
1382
1383 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1387 unsafe {
1388 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1389 Ok(Stack::from_ptr(extensions))
1390 }
1391 }
1392}
1393
1394pub type X509VerifyResult = Result<(), X509VerifyError>;
1396
1397#[derive(Copy, Clone, PartialEq, Eq)]
1398pub struct X509VerifyError(c_int);
1399
1400impl fmt::Debug for X509VerifyError {
1401 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1402 fmt.debug_struct("X509VerifyError")
1403 .field("code", &self.0)
1404 .field("error", &self.error_string())
1405 .finish()
1406 }
1407}
1408
1409impl fmt::Display for X509VerifyError {
1410 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1411 fmt.write_str(self.error_string())
1412 }
1413}
1414
1415impl Error for X509VerifyError {}
1416
1417impl X509VerifyError {
1418 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1425 if err == ffi::X509_V_OK {
1426 Ok(())
1427 } else {
1428 Err(X509VerifyError(err))
1429 }
1430 }
1431
1432 #[allow(clippy::trivially_copy_pass_by_ref)]
1434 pub fn as_raw(&self) -> c_int {
1435 self.0
1436 }
1437
1438 #[allow(clippy::trivially_copy_pass_by_ref)]
1444 pub fn error_string(&self) -> &'static str {
1445 ffi::init();
1446
1447 unsafe {
1448 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1449 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1450 }
1451 }
1452}
1453
1454#[allow(missing_docs)] impl X509VerifyError {
1456 pub const UNSPECIFIED: Self = Self(ffi::X509_V_ERR_UNSPECIFIED);
1457 pub const UNABLE_TO_GET_ISSUER_CERT: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
1458 pub const UNABLE_TO_GET_CRL: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL);
1459 pub const UNABLE_TO_DECRYPT_CERT_SIGNATURE: Self =
1460 Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
1461 pub const UNABLE_TO_DECRYPT_CRL_SIGNATURE: Self =
1462 Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
1463 pub const UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Self =
1464 Self(ffi::X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
1465 pub const CERT_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CERT_SIGNATURE_FAILURE);
1466 pub const CRL_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE);
1467 pub const CERT_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CERT_NOT_YET_VALID);
1468 pub const CERT_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CERT_HAS_EXPIRED);
1469 pub const CRL_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CRL_NOT_YET_VALID);
1470 pub const CRL_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CRL_HAS_EXPIRED);
1471 pub const ERROR_IN_CERT_NOT_BEFORE_FIELD: Self =
1472 Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
1473 pub const ERROR_IN_CERT_NOT_AFTER_FIELD: Self =
1474 Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
1475 pub const ERROR_IN_CRL_LAST_UPDATE_FIELD: Self =
1476 Self(ffi::X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
1477 pub const ERROR_IN_CRL_NEXT_UPDATE_FIELD: Self =
1478 Self(ffi::X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
1479 pub const OUT_OF_MEM: Self = Self(ffi::X509_V_ERR_OUT_OF_MEM);
1480 pub const DEPTH_ZERO_SELF_SIGNED_CERT: Self = Self(ffi::X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
1481 pub const SELF_SIGNED_CERT_IN_CHAIN: Self = Self(ffi::X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
1482 pub const UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Self =
1483 Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
1484 pub const UNABLE_TO_VERIFY_LEAF_SIGNATURE: Self =
1485 Self(ffi::X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
1486 pub const CERT_CHAIN_TOO_LONG: Self = Self(ffi::X509_V_ERR_CERT_CHAIN_TOO_LONG);
1487 pub const CERT_REVOKED: Self = Self(ffi::X509_V_ERR_CERT_REVOKED);
1488 pub const INVALID_CA: Self = Self(ffi::X509_V_ERR_INVALID_CA);
1489 pub const PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PATH_LENGTH_EXCEEDED);
1490 pub const INVALID_PURPOSE: Self = Self(ffi::X509_V_ERR_INVALID_PURPOSE);
1491 pub const CERT_UNTRUSTED: Self = Self(ffi::X509_V_ERR_CERT_UNTRUSTED);
1492 pub const CERT_REJECTED: Self = Self(ffi::X509_V_ERR_CERT_REJECTED);
1493 pub const SUBJECT_ISSUER_MISMATCH: Self = Self(ffi::X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
1494 pub const AKID_SKID_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_SKID_MISMATCH);
1495 pub const AKID_ISSUER_SERIAL_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
1496 pub const KEYUSAGE_NO_CERTSIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
1497 pub const UNABLE_TO_GET_CRL_ISSUER: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
1498 pub const UNHANDLED_CRITICAL_EXTENSION: Self =
1499 Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
1500 pub const KEYUSAGE_NO_CRL_SIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
1501 pub const UNHANDLED_CRITICAL_CRL_EXTENSION: Self =
1502 Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
1503 pub const INVALID_NON_CA: Self = Self(ffi::X509_V_ERR_INVALID_NON_CA);
1504 pub const PROXY_PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
1505 pub const KEYUSAGE_NO_DIGITAL_SIGNATURE: Self =
1506 Self(ffi::X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
1507 pub const PROXY_CERTIFICATES_NOT_ALLOWED: Self =
1508 Self(ffi::X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
1509 pub const INVALID_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_EXTENSION);
1510 pub const INVALID_POLICY_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_POLICY_EXTENSION);
1511 pub const NO_EXPLICIT_POLICY: Self = Self(ffi::X509_V_ERR_NO_EXPLICIT_POLICY);
1512 pub const DIFFERENT_CRL_SCOPE: Self = Self(ffi::X509_V_ERR_DIFFERENT_CRL_SCOPE);
1513 pub const UNSUPPORTED_EXTENSION_FEATURE: Self =
1514 Self(ffi::X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
1515 pub const UNNESTED_RESOURCE: Self = Self(ffi::X509_V_ERR_UNNESTED_RESOURCE);
1516 pub const PERMITTED_VIOLATION: Self = Self(ffi::X509_V_ERR_PERMITTED_VIOLATION);
1517 pub const EXCLUDED_VIOLATION: Self = Self(ffi::X509_V_ERR_EXCLUDED_VIOLATION);
1518 pub const SUBTREE_MINMAX: Self = Self(ffi::X509_V_ERR_SUBTREE_MINMAX);
1519 pub const APPLICATION_VERIFICATION: Self = Self(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1520 pub const UNSUPPORTED_CONSTRAINT_TYPE: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
1521 pub const UNSUPPORTED_CONSTRAINT_SYNTAX: Self =
1522 Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
1523 pub const UNSUPPORTED_NAME_SYNTAX: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
1524 pub const CRL_PATH_VALIDATION_ERROR: Self = Self(ffi::X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
1525 pub const HOSTNAME_MISMATCH: Self = Self(ffi::X509_V_ERR_HOSTNAME_MISMATCH);
1526 pub const EMAIL_MISMATCH: Self = Self(ffi::X509_V_ERR_EMAIL_MISMATCH);
1527 pub const IP_ADDRESS_MISMATCH: Self = Self(ffi::X509_V_ERR_IP_ADDRESS_MISMATCH);
1528 pub const INVALID_CALL: Self = Self(ffi::X509_V_ERR_INVALID_CALL);
1529 pub const STORE_LOOKUP: Self = Self(ffi::X509_V_ERR_STORE_LOOKUP);
1530 pub const NAME_CONSTRAINTS_WITHOUT_SANS: Self =
1531 Self(ffi::X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS);
1532}
1533
1534foreign_type_and_impl_send_sync! {
1535 type CType = ffi::GENERAL_NAME;
1536 fn drop = ffi::GENERAL_NAME_free;
1537
1538 pub struct GeneralName;
1540}
1541
1542impl GeneralName {
1543 unsafe fn new(
1544 type_: c_int,
1545 asn1_type: Asn1Type,
1546 value: &[u8],
1547 ) -> Result<GeneralName, ErrorStack> {
1548 ffi::init();
1549 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1550 (*gn.as_ptr()).type_ = type_;
1551 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
1552 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
1553
1554 (*gn.as_ptr()).d.ptr = s.cast();
1555
1556 Ok(gn)
1557 }
1558
1559 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
1560 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
1561 }
1562
1563 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
1564 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
1565 }
1566
1567 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
1568 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
1569 }
1570
1571 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
1572 match ip {
1573 IpAddr::V4(addr) => unsafe {
1574 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1575 },
1576 IpAddr::V6(addr) => unsafe {
1577 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1578 },
1579 }
1580 }
1581
1582 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
1583 unsafe {
1584 ffi::init();
1585 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
1586 (*gn).type_ = ffi::GEN_RID;
1587 (*gn).d.registeredID = oid.as_ptr();
1588
1589 mem::forget(oid);
1590
1591 Ok(GeneralName::from_ptr(gn))
1592 }
1593 }
1594}
1595
1596impl GeneralNameRef {
1597 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1598 unsafe {
1599 if (*self.as_ptr()).type_ != ffi_type {
1600 return None;
1601 }
1602
1603 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
1604 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
1605
1606 let slice = slice::from_raw_parts(ptr, len as usize);
1607 str::from_utf8(slice).ok()
1611 }
1612 }
1613
1614 pub fn email(&self) -> Option<&str> {
1616 self.ia5_string(ffi::GEN_EMAIL)
1617 }
1618
1619 pub fn dnsname(&self) -> Option<&str> {
1621 self.ia5_string(ffi::GEN_DNS)
1622 }
1623
1624 pub fn uri(&self) -> Option<&str> {
1626 self.ia5_string(ffi::GEN_URI)
1627 }
1628
1629 pub fn ipaddress(&self) -> Option<&[u8]> {
1631 unsafe {
1632 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1633 return None;
1634 }
1635
1636 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
1637 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
1638
1639 Some(slice::from_raw_parts(ptr, len as usize))
1640 }
1641 }
1642}
1643
1644impl fmt::Debug for GeneralNameRef {
1645 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1646 if let Some(email) = self.email() {
1647 formatter.write_str(email)
1648 } else if let Some(dnsname) = self.dnsname() {
1649 formatter.write_str(dnsname)
1650 } else if let Some(uri) = self.uri() {
1651 formatter.write_str(uri)
1652 } else if let Some(ipaddress) = self.ipaddress() {
1653 let result = String::from_utf8_lossy(ipaddress);
1654 formatter.write_str(&result)
1655 } else {
1656 formatter.write_str("(empty)")
1657 }
1658 }
1659}
1660
1661impl Stackable for GeneralName {
1662 type StackType = ffi::stack_st_GENERAL_NAME;
1663}
1664
1665foreign_type_and_impl_send_sync! {
1666 type CType = ffi::X509_ALGOR;
1667 fn drop = ffi::X509_ALGOR_free;
1668
1669 pub struct X509Algorithm;
1671}
1672
1673impl X509AlgorithmRef {
1674 pub fn object(&self) -> &Asn1ObjectRef {
1676 unsafe {
1677 let mut oid = ptr::null();
1678 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1679 assert!(!oid.is_null());
1680 Asn1ObjectRef::from_ptr(oid as *mut _)
1681 }
1682 }
1683}
1684
1685foreign_type_and_impl_send_sync! {
1686 type CType = ffi::X509_OBJECT;
1687 fn drop = X509_OBJECT_free;
1688
1689 pub struct X509Object;
1691}
1692
1693impl X509ObjectRef {
1694 pub fn x509(&self) -> Option<&X509Ref> {
1695 unsafe {
1696 let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1697 if ptr.is_null() {
1698 None
1699 } else {
1700 Some(X509Ref::from_ptr(ptr))
1701 }
1702 }
1703 }
1704}
1705
1706impl Stackable for X509Object {
1707 type StackType = ffi::stack_st_X509_OBJECT;
1708}
1709
1710use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
1711
1712use crate::ffi::{
1713 ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
1714 X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
1715};
1716
1717use crate::ffi::X509_OBJECT_get0_X509;
1718
1719#[allow(bad_style)]
1720unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1721 ffi::X509_OBJECT_free_contents(x);
1722 ffi::OPENSSL_free(x as *mut libc::c_void);
1723}