1use foreign_types::{ForeignType, ForeignTypeRef};
11use libc::{c_int, c_long, c_void};
12use openssl_macros::corresponds;
13use std::convert::TryInto;
14use std::error::Error;
15use std::ffi::{CStr, CString};
16use std::fmt;
17use std::marker::PhantomData;
18use std::mem;
19use std::net::IpAddr;
20use std::path::Path;
21use std::ptr;
22use std::slice;
23use std::str;
24
25use crate::asn1::{
26 Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef,
27 Asn1Type,
28};
29use crate::bio::{MemBio, MemBioSlice};
30use crate::conf::ConfRef;
31use crate::error::ErrorStack;
32use crate::ex_data::Index;
33use crate::ffi;
34use crate::hash::{DigestBytes, MessageDigest};
35use crate::nid::Nid;
36use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
37use crate::ssl::SslRef;
38use crate::stack::{Stack, StackRef, Stackable};
39use crate::string::OpensslString;
40use crate::util::ForeignTypeRefExt;
41use crate::x509::verify::X509VerifyParamRef;
42use crate::{cvt, cvt_n, cvt_p};
43
44pub mod extension;
45pub mod store;
46pub mod verify;
47
48#[cfg(test)]
49mod tests;
50
51foreign_type_and_impl_send_sync! {
52 type CType = ffi::X509_STORE_CTX;
53 fn drop = ffi::X509_STORE_CTX_free;
54
55 pub struct X509StoreContext;
57}
58
59impl X509StoreContext {
60 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
63 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
64 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
65 }
66
67 #[corresponds(X509_STORE_CTX_new)]
69 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 #[corresponds(X509_STORE_CTX_get_ex_data)]
80 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
81 unsafe {
82 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
83 if data.is_null() {
84 None
85 } else {
86 Some(&*(data as *const T))
87 }
88 }
89 }
90
91 #[corresponds(X509_STORE_CTX_get_error)]
93 pub fn verify_result(&self) -> X509VerifyResult {
94 unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
95 }
96
97 pub fn init<F, T>(
113 &mut self,
114 trust: &store::X509StoreRef,
115 cert: &X509Ref,
116 cert_chain: &StackRef<X509>,
117 with_context: F,
118 ) -> Result<T, ErrorStack>
119 where
120 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
121 {
122 struct Cleanup<'a>(&'a mut X509StoreContextRef);
123
124 impl Drop for Cleanup<'_> {
125 fn drop(&mut self) {
126 unsafe {
127 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
128 }
129 }
130 }
131
132 unsafe {
133 cvt(ffi::X509_STORE_CTX_init(
134 self.as_ptr(),
135 trust.as_ptr(),
136 cert.as_ptr(),
137 cert_chain.as_ptr(),
138 ))?;
139
140 let cleanup = Cleanup(self);
141 with_context(cleanup.0)
142 }
143 }
144
145 #[corresponds(X509_STORE_CTX_get0_param)]
147 pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
148 unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) }
149 }
150
151 #[corresponds(X509_verify_cert)]
158 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
159 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
160 }
161
162 #[corresponds(X509_STORE_CTX_set_error)]
164 pub fn set_error(&mut self, result: X509VerifyResult) {
165 unsafe {
166 ffi::X509_STORE_CTX_set_error(
167 self.as_ptr(),
168 result
169 .err()
170 .as_ref()
171 .map_or(ffi::X509_V_OK, X509VerifyError::as_raw),
172 );
173 }
174 }
175
176 #[corresponds(X509_STORE_CTX_get_current_cert)]
179 pub fn current_cert(&self) -> Option<&X509Ref> {
180 unsafe {
181 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
182 if ptr.is_null() {
183 None
184 } else {
185 Some(X509Ref::from_ptr(ptr))
186 }
187 }
188 }
189
190 #[corresponds(X509_STORE_CTX_get_error_depth)]
195 pub fn error_depth(&self) -> u32 {
196 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
197 }
198
199 #[corresponds(X509_STORE_CTX_get0_chain)]
201 pub fn chain(&self) -> Option<&StackRef<X509>> {
202 unsafe {
203 let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
204
205 if chain.is_null() {
206 None
207 } else {
208 Some(StackRef::from_ptr(chain))
209 }
210 }
211 }
212}
213
214pub struct X509Builder(X509);
216
217impl X509Builder {
218 #[corresponds(X509_new)]
220 pub fn new() -> Result<X509Builder, ErrorStack> {
221 unsafe {
222 ffi::init();
223 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509::from_ptr(p)))
224 }
225 }
226
227 #[corresponds(X509_set1_notAfter)]
229 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
230 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
231 }
232
233 #[corresponds(X509_set1_notBefore)]
235 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
236 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
237 }
238
239 #[corresponds(X509_set_version)]
244 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
245 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
246 }
247
248 #[corresponds(X509_set_serialNumber)]
250 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
251 unsafe {
252 cvt(ffi::X509_set_serialNumber(
253 self.0.as_ptr(),
254 serial_number.as_ptr(),
255 ))
256 .map(|_| ())
257 }
258 }
259
260 #[corresponds(X509_set_issuer_name)]
262 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
263 unsafe {
264 cvt(ffi::X509_set_issuer_name(
265 self.0.as_ptr(),
266 issuer_name.as_ptr(),
267 ))
268 .map(|_| ())
269 }
270 }
271
272 #[corresponds(X509_set_subject_name)]
291 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
292 unsafe {
293 cvt(ffi::X509_set_subject_name(
294 self.0.as_ptr(),
295 subject_name.as_ptr(),
296 ))
297 .map(|_| ())
298 }
299 }
300
301 #[corresponds(X509_set_pubkey)]
303 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
304 where
305 T: HasPublic,
306 {
307 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
308 }
309
310 #[corresponds(X509V3_set_ctx)]
314 pub fn x509v3_context<'a>(
315 &'a self,
316 issuer: Option<&'a X509Ref>,
317 conf: Option<&'a ConfRef>,
318 ) -> X509v3Context<'a> {
319 unsafe {
320 let mut ctx = mem::zeroed();
321
322 let issuer = match issuer {
323 Some(issuer) => issuer.as_ptr(),
324 None => self.0.as_ptr(),
325 };
326 let subject = self.0.as_ptr();
327 ffi::X509V3_set_ctx(
328 &mut ctx,
329 issuer,
330 subject,
331 ptr::null_mut(),
332 ptr::null_mut(),
333 0,
334 );
335
336 if let Some(conf) = conf {
338 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
339 }
340
341 X509v3Context(ctx, PhantomData)
342 }
343 }
344
345 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
349 self.append_extension2(&extension)
350 }
351
352 #[corresponds(X509_add_ext)]
354 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
355 unsafe {
356 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
357 Ok(())
358 }
359 }
360
361 #[corresponds(X509_sign)]
363 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
364 where
365 T: HasPrivate,
366 {
367 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
368 }
369
370 pub fn build(self) -> X509 {
372 self.0
373 }
374}
375
376foreign_type_and_impl_send_sync! {
377 type CType = ffi::X509;
378 fn drop = ffi::X509_free;
379
380 pub struct X509;
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("issuer name must not be null")
391 }
392 }
393
394 #[corresponds(X509_subject_name_hash)]
396 pub fn subject_name_hash(&self) -> u32 {
397 unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 }
398 }
399
400 #[corresponds(X509_get_ext_d2i)]
402 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
403 unsafe {
404 let stack = ffi::X509_get_ext_d2i(
405 self.as_ptr(),
406 ffi::NID_subject_alt_name,
407 ptr::null_mut(),
408 ptr::null_mut(),
409 );
410 if stack.is_null() {
411 None
412 } else {
413 Some(Stack::from_ptr(stack as *mut _))
414 }
415 }
416 }
417
418 #[corresponds(X509_get_issuer_name)]
420 pub fn issuer_name(&self) -> &X509NameRef {
421 unsafe {
422 let name = ffi::X509_get_issuer_name(self.as_ptr());
423 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
424 }
425 }
426
427 #[corresponds(X509_get_ext_d2i)]
429 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
430 unsafe {
431 let stack = ffi::X509_get_ext_d2i(
432 self.as_ptr(),
433 ffi::NID_issuer_alt_name,
434 ptr::null_mut(),
435 ptr::null_mut(),
436 );
437 if stack.is_null() {
438 None
439 } else {
440 Some(Stack::from_ptr(stack as *mut _))
441 }
442 }
443 }
444
445 #[corresponds(X509_get0_subject_key_id)]
447 pub fn subject_key_id(&self) -> Option<&Asn1StringRef> {
448 unsafe {
449 let data = ffi::X509_get0_subject_key_id(self.as_ptr());
450 Asn1StringRef::from_const_ptr_opt(data)
451 }
452 }
453
454 #[corresponds(X509_get0_authority_key_id)]
456 pub fn authority_key_id(&self) -> Option<&Asn1StringRef> {
457 unsafe {
458 let data = ffi::X509_get0_authority_key_id(self.as_ptr());
459 Asn1StringRef::from_const_ptr_opt(data)
460 }
461 }
462
463 #[corresponds(X509_get_pubkey)]
464 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
465 unsafe {
466 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
467 Ok(PKey::from_ptr(pkey))
468 }
469 }
470
471 #[corresponds(X509_digest)]
473 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
474 unsafe {
475 let mut digest = DigestBytes {
476 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
477 len: ffi::EVP_MAX_MD_SIZE as usize,
478 };
479 let mut len = ffi::EVP_MAX_MD_SIZE.try_into().unwrap();
480 cvt(ffi::X509_digest(
481 self.as_ptr(),
482 hash_type.as_ptr(),
483 digest.buf.as_mut_ptr() as *mut _,
484 &mut len,
485 ))?;
486 digest.len = len as usize;
487
488 Ok(digest)
489 }
490 }
491
492 #[deprecated(since = "0.10.9", note = "renamed to digest")]
493 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
494 self.digest(hash_type).map(|b| b.to_vec())
495 }
496
497 #[corresponds(X509_getm_notAfter)]
499 pub fn not_after(&self) -> &Asn1TimeRef {
500 unsafe {
501 let date = X509_getm_notAfter(self.as_ptr());
502 assert!(!date.is_null());
503 Asn1TimeRef::from_ptr(date)
504 }
505 }
506
507 #[corresponds(X509_getm_notBefore)]
509 pub fn not_before(&self) -> &Asn1TimeRef {
510 unsafe {
511 let date = X509_getm_notBefore(self.as_ptr());
512 assert!(!date.is_null());
513 Asn1TimeRef::from_ptr(date)
514 }
515 }
516
517 #[corresponds(X509_get0_signature)]
519 pub fn signature(&self) -> &Asn1BitStringRef {
520 unsafe {
521 let mut signature = ptr::null();
522 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
523 assert!(!signature.is_null());
524 Asn1BitStringRef::from_ptr(signature as *mut _)
525 }
526 }
527
528 #[corresponds(X509_get0_signature)]
530 pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
531 unsafe {
532 let mut algor = ptr::null();
533 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
534 assert!(!algor.is_null());
535 X509AlgorithmRef::from_ptr(algor as *mut _)
536 }
537 }
538
539 #[corresponds(X509_get1_ocsp)]
542 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
543 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
544 }
545
546 #[corresponds(X509_check_issued)]
548 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
549 unsafe {
550 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
551 X509VerifyError::from_raw(r)
552 }
553 }
554
555 #[corresponds(X509_verify)]
562 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
563 where
564 T: HasPublic,
565 {
566 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
567 }
568
569 #[corresponds(X509_get_serialNumber)]
571 pub fn serial_number(&self) -> &Asn1IntegerRef {
572 unsafe {
573 let r = ffi::X509_get_serialNumber(self.as_ptr());
574 assert!(!r.is_null());
575 Asn1IntegerRef::from_ptr(r)
576 }
577 }
578
579 pub fn check_host(&self, host: &str) -> Result<bool, ErrorStack> {
580 unsafe {
581 cvt_n(ffi::X509_check_host(
582 self.as_ptr(),
583 host.as_ptr() as _,
584 host.len(),
585 0,
586 std::ptr::null_mut(),
587 ))
588 .map(|n| n == 1)
589 }
590 }
591
592 to_pem! {
593 #[corresponds(PEM_write_bio_X509)]
597 to_pem,
598 ffi::PEM_write_bio_X509
599 }
600
601 to_der! {
602 #[corresponds(i2d_X509)]
604 to_der,
605 ffi::i2d_X509
606 }
607}
608
609impl ToOwned for X509Ref {
610 type Owned = X509;
611
612 fn to_owned(&self) -> X509 {
613 unsafe {
614 X509_up_ref(self.as_ptr());
615 X509::from_ptr(self.as_ptr())
616 }
617 }
618}
619
620impl X509 {
621 pub fn builder() -> Result<X509Builder, ErrorStack> {
623 X509Builder::new()
624 }
625
626 from_pem! {
627 #[corresponds(PEM_read_bio_X509)]
631 from_pem,
632 X509,
633 ffi::PEM_read_bio_X509
634 }
635
636 from_der! {
637 #[corresponds(d2i_X509)]
639 from_der,
640 X509,
641 ffi::d2i_X509,
642 ::libc::c_long
643 }
644
645 #[corresponds(PEM_read_bio_X509)]
647 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
648 unsafe {
649 ffi::init();
650 let bio = MemBioSlice::new(pem)?;
651
652 let mut certs = vec![];
653 loop {
654 let r =
655 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
656 if r.is_null() {
657 let err = ffi::ERR_peek_last_error();
658
659 if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM.0.try_into().unwrap()
660 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
661 {
662 ffi::ERR_clear_error();
663 break;
664 }
665
666 return Err(ErrorStack::get());
667 } else {
668 certs.push(X509::from_ptr(r));
669 }
670 }
671
672 Ok(certs)
673 }
674 }
675}
676
677impl Clone for X509 {
678 fn clone(&self) -> X509 {
679 X509Ref::to_owned(self)
680 }
681}
682
683impl fmt::Debug for X509 {
684 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
685 let serial = match &self.serial_number().to_bn() {
686 Ok(bn) => match bn.to_hex_str() {
687 Ok(hex) => hex.to_string(),
688 Err(_) => "".to_string(),
689 },
690 Err(_) => "".to_string(),
691 };
692 let mut debug_struct = formatter.debug_struct("X509");
693 debug_struct.field("serial_number", &serial);
694 debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
695 debug_struct.field("issuer", &self.issuer_name());
696 debug_struct.field("subject", &self.subject_name());
697 if let Some(subject_alt_names) = &self.subject_alt_names() {
698 debug_struct.field("subject_alt_names", subject_alt_names);
699 }
700 debug_struct.field("not_before", &self.not_before());
701 debug_struct.field("not_after", &self.not_after());
702
703 if let Ok(public_key) = &self.public_key() {
704 debug_struct.field("public_key", public_key);
705 };
706 debug_struct.finish()
709 }
710}
711
712impl AsRef<X509Ref> for X509Ref {
713 fn as_ref(&self) -> &X509Ref {
714 self
715 }
716}
717
718impl Stackable for X509 {
719 type StackType = ffi::stack_st_X509;
720}
721
722pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
724
725impl X509v3Context<'_> {
726 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
727 &self.0 as *const _ as *mut _
728 }
729}
730
731foreign_type_and_impl_send_sync! {
732 type CType = ffi::X509_EXTENSION;
733 fn drop = ffi::X509_EXTENSION_free;
734
735 pub struct X509Extension;
737}
738
739impl Stackable for X509Extension {
740 type StackType = ffi::stack_st_X509_EXTENSION;
741}
742
743impl X509Extension {
744 pub fn new(
755 conf: Option<&ConfRef>,
756 context: Option<&X509v3Context>,
757 name: &str,
758 value: &str,
759 ) -> Result<X509Extension, ErrorStack> {
760 let name = CString::new(name).unwrap();
761 let value = CString::new(value).unwrap();
762 let mut ctx;
763 unsafe {
764 ffi::init();
765 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
766 let context_ptr = match context {
767 Some(c) => c.as_ptr(),
768 None => {
769 ctx = mem::zeroed();
770
771 ffi::X509V3_set_ctx(
772 &mut ctx,
773 ptr::null_mut(),
774 ptr::null_mut(),
775 ptr::null_mut(),
776 ptr::null_mut(),
777 0,
778 );
779 &mut ctx
780 }
781 };
782 let name = name.as_ptr() as *mut _;
783 let value = value.as_ptr() as *mut _;
784
785 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value))
786 .map(|p| X509Extension::from_ptr(p))
787 }
788 }
789
790 pub fn new_nid(
801 conf: Option<&ConfRef>,
802 context: Option<&X509v3Context>,
803 name: Nid,
804 value: &str,
805 ) -> Result<X509Extension, ErrorStack> {
806 let value = CString::new(value).unwrap();
807 let mut ctx;
808 unsafe {
809 ffi::init();
810 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
811 let context_ptr = match context {
812 Some(c) => c.as_ptr(),
813 None => {
814 ctx = mem::zeroed();
815
816 ffi::X509V3_set_ctx(
817 &mut ctx,
818 ptr::null_mut(),
819 ptr::null_mut(),
820 ptr::null_mut(),
821 ptr::null_mut(),
822 0,
823 );
824 &mut ctx
825 }
826 };
827 let name = name.as_raw();
828 let value = value.as_ptr() as *mut _;
829
830 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value))
831 .map(|p| X509Extension::from_ptr(p))
832 }
833 }
834
835 pub(crate) unsafe fn new_internal(
836 nid: Nid,
837 critical: bool,
838 value: *mut c_void,
839 ) -> Result<X509Extension, ErrorStack> {
840 ffi::init();
841 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value))
842 .map(|p| X509Extension::from_ptr(p))
843 }
844}
845
846impl X509ExtensionRef {
847 to_der! {
848 to_der,
850 ffi::i2d_X509_EXTENSION
851 }
852}
853
854pub struct X509NameBuilder(X509Name);
856
857impl X509NameBuilder {
858 pub fn new() -> Result<X509NameBuilder, ErrorStack> {
860 unsafe {
861 ffi::init();
862 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name::from_ptr(p)))
863 }
864 }
865
866 #[corresponds(X509_NAME_add_entry_by_txt)]
868 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
869 unsafe {
870 let field = CString::new(field).unwrap();
871 assert!(value.len() <= ValueLen::MAX as usize);
872 cvt(ffi::X509_NAME_add_entry_by_txt(
873 self.0.as_ptr(),
874 field.as_ptr() as *mut _,
875 ffi::MBSTRING_UTF8,
876 value.as_ptr(),
877 value.len() as ValueLen,
878 -1,
879 0,
880 ))
881 .map(|_| ())
882 }
883 }
884
885 #[corresponds(X509_NAME_add_entry_by_txt)]
887 pub fn append_entry_by_text_with_type(
888 &mut self,
889 field: &str,
890 value: &str,
891 ty: Asn1Type,
892 ) -> Result<(), ErrorStack> {
893 unsafe {
894 let field = CString::new(field).unwrap();
895 assert!(value.len() <= ValueLen::MAX as usize);
896 cvt(ffi::X509_NAME_add_entry_by_txt(
897 self.0.as_ptr(),
898 field.as_ptr() as *mut _,
899 ty.as_raw(),
900 value.as_ptr(),
901 value.len() as ValueLen,
902 -1,
903 0,
904 ))
905 .map(|_| ())
906 }
907 }
908
909 #[corresponds(X509_NAME_add_entry_by_NID)]
911 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
912 unsafe {
913 assert!(value.len() <= ValueLen::MAX as usize);
914 cvt(ffi::X509_NAME_add_entry_by_NID(
915 self.0.as_ptr(),
916 field.as_raw(),
917 ffi::MBSTRING_UTF8,
918 value.as_ptr() as *mut _,
919 value.len() as ValueLen,
920 -1,
921 0,
922 ))
923 .map(|_| ())
924 }
925 }
926
927 #[corresponds(X509_NAME_add_entry_by_NID)]
929 pub fn append_entry_by_nid_with_type(
930 &mut self,
931 field: Nid,
932 value: &str,
933 ty: Asn1Type,
934 ) -> Result<(), ErrorStack> {
935 unsafe {
936 assert!(value.len() <= ValueLen::MAX as usize);
937 cvt(ffi::X509_NAME_add_entry_by_NID(
938 self.0.as_ptr(),
939 field.as_raw(),
940 ty.as_raw(),
941 value.as_ptr() as *mut _,
942 value.len() as ValueLen,
943 -1,
944 0,
945 ))
946 .map(|_| ())
947 }
948 }
949
950 pub fn build(self) -> X509Name {
952 X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
956 }
957}
958
959type ValueLen = isize;
960
961foreign_type_and_impl_send_sync! {
962 type CType = ffi::X509_NAME;
963 fn drop = ffi::X509_NAME_free;
964
965 pub struct X509Name;
967}
968
969impl X509Name {
970 pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
972 X509NameBuilder::new()
973 }
974
975 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
979 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
980 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
981 }
982
983 from_der! {
984 #[corresponds(d2i_X509_NAME)]
986 from_der,
987 X509Name,
988 ffi::d2i_X509_NAME,
989 ::libc::c_long
990 }
991}
992
993impl Stackable for X509Name {
994 type StackType = ffi::stack_st_X509_NAME;
995}
996
997impl X509NameRef {
998 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1000 X509NameEntries {
1001 name: self,
1002 nid: Some(nid),
1003 loc: -1,
1004 }
1005 }
1006
1007 pub fn entries(&self) -> X509NameEntries<'_> {
1009 X509NameEntries {
1010 name: self,
1011 nid: None,
1012 loc: -1,
1013 }
1014 }
1015
1016 #[corresponds(X509_NAME_print_ex)]
1020 pub fn print_ex(&self, flags: i32) -> Option<String> {
1021 unsafe {
1022 let bio = MemBio::new().ok()?;
1023 ffi::X509_NAME_print_ex(bio.as_ptr(), self.as_ptr(), 0, flags as _);
1024 let buf = bio.get_buf().to_vec();
1025 let res = String::from_utf8(buf);
1026 res.ok()
1027 }
1028 }
1029
1030 to_der! {
1031 #[corresponds(i2d_X509_NAME)]
1033 to_der,
1034 ffi::i2d_X509_NAME
1035 }
1036}
1037
1038impl fmt::Debug for X509NameRef {
1039 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1040 formatter.debug_list().entries(self.entries()).finish()
1041 }
1042}
1043
1044pub struct X509NameEntries<'a> {
1046 name: &'a X509NameRef,
1047 nid: Option<Nid>,
1048 loc: c_int,
1049}
1050
1051impl<'a> Iterator for X509NameEntries<'a> {
1052 type Item = &'a X509NameEntryRef;
1053
1054 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1055 unsafe {
1056 match self.nid {
1057 Some(nid) => {
1058 self.loc =
1060 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1061 if self.loc == -1 {
1062 return None;
1063 }
1064 }
1065 None => {
1066 self.loc += 1;
1068 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1069 return None;
1070 }
1071 }
1072 }
1073
1074 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1075 assert!(!entry.is_null());
1076
1077 Some(X509NameEntryRef::from_ptr(entry))
1078 }
1079 }
1080}
1081
1082foreign_type_and_impl_send_sync! {
1083 type CType = ffi::X509_NAME_ENTRY;
1084 fn drop = ffi::X509_NAME_ENTRY_free;
1085
1086 pub struct X509NameEntry;
1088}
1089
1090impl X509NameEntryRef {
1091 #[corresponds(X509_NAME_ENTRY_get_data)]
1093 pub fn data(&self) -> &Asn1StringRef {
1094 unsafe {
1095 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1096 Asn1StringRef::from_ptr(data)
1097 }
1098 }
1099
1100 #[corresponds(X509_NAME_ENTRY_get_object)]
1103 pub fn object(&self) -> &Asn1ObjectRef {
1104 unsafe {
1105 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1106 Asn1ObjectRef::from_ptr(object)
1107 }
1108 }
1109}
1110
1111impl fmt::Debug for X509NameEntryRef {
1112 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1113 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1114 }
1115}
1116
1117pub struct X509ReqBuilder(X509Req);
1119
1120impl X509ReqBuilder {
1121 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1127 unsafe {
1128 ffi::init();
1129 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req::from_ptr(p)))
1130 }
1131 }
1132
1133 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1139 unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
1140 }
1141
1142 #[corresponds(X509_REQ_set_subject_name)]
1144 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1145 unsafe {
1146 cvt(ffi::X509_REQ_set_subject_name(
1147 self.0.as_ptr(),
1148 subject_name.as_ptr(),
1149 ))
1150 .map(|_| ())
1151 }
1152 }
1153
1154 #[corresponds(X509_REQ_set_pubkey)]
1156 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1157 where
1158 T: HasPublic,
1159 {
1160 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1161 }
1162
1163 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1166 unsafe {
1167 let mut ctx = mem::zeroed();
1168
1169 ffi::X509V3_set_ctx(
1170 &mut ctx,
1171 ptr::null_mut(),
1172 ptr::null_mut(),
1173 self.0.as_ptr(),
1174 ptr::null_mut(),
1175 0,
1176 );
1177
1178 if let Some(conf) = conf {
1180 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1181 }
1182
1183 X509v3Context(ctx, PhantomData)
1184 }
1185 }
1186
1187 pub fn add_extensions(
1189 &mut self,
1190 extensions: &StackRef<X509Extension>,
1191 ) -> Result<(), ErrorStack> {
1192 unsafe {
1193 cvt(ffi::X509_REQ_add_extensions(
1194 self.0.as_ptr(),
1195 extensions.as_ptr(),
1196 ))
1197 .map(|_| ())
1198 }
1199 }
1200
1201 #[corresponds(X509_REQ_sign)]
1203 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1204 where
1205 T: HasPrivate,
1206 {
1207 unsafe {
1208 cvt(ffi::X509_REQ_sign(
1209 self.0.as_ptr(),
1210 key.as_ptr(),
1211 hash.as_ptr(),
1212 ))
1213 .map(|_| ())
1214 }
1215 }
1216
1217 pub fn build(self) -> X509Req {
1219 self.0
1220 }
1221}
1222
1223foreign_type_and_impl_send_sync! {
1224 type CType = ffi::X509_REQ;
1225 fn drop = ffi::X509_REQ_free;
1226
1227 pub struct X509Req;
1229}
1230
1231impl X509Req {
1232 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1234 X509ReqBuilder::new()
1235 }
1236
1237 from_pem! {
1238 #[corresponds(PEM_read_bio_X509_REQ)]
1242 from_pem,
1243 X509Req,
1244 ffi::PEM_read_bio_X509_REQ
1245 }
1246
1247 from_der! {
1248 #[corresponds(d2i_X509_REQ)]
1250 from_der,
1251 X509Req,
1252 ffi::d2i_X509_REQ,
1253 ::libc::c_long
1254 }
1255}
1256
1257impl X509ReqRef {
1258 to_pem! {
1259 #[corresponds(PEM_write_bio_X509_REQ)]
1263 to_pem,
1264 ffi::PEM_write_bio_X509_REQ
1265 }
1266
1267 to_der! {
1268 #[corresponds(i2d_X509_REQ)]
1270 to_der,
1271 ffi::i2d_X509_REQ
1272 }
1273
1274 #[corresponds(X509_REQ_get_version)]
1276 pub fn version(&self) -> i32 {
1277 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1278 }
1279
1280 #[corresponds(X509_REQ_get_subject_name)]
1282 pub fn subject_name(&self) -> &X509NameRef {
1283 unsafe {
1284 let name = X509_REQ_get_subject_name(self.as_ptr());
1285 assert!(!name.is_null());
1286 X509NameRef::from_ptr(name)
1287 }
1288 }
1289
1290 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1296 unsafe {
1297 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1298 Ok(PKey::from_ptr(key))
1299 }
1300 }
1301
1302 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1310 where
1311 T: HasPublic,
1312 {
1313 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1314 }
1315
1316 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1320 unsafe {
1321 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1322 Ok(Stack::from_ptr(extensions))
1323 }
1324 }
1325}
1326
1327pub type X509VerifyResult = Result<(), X509VerifyError>;
1329
1330#[derive(Copy, Clone, PartialEq, Eq)]
1331pub struct X509VerifyError(c_int);
1332
1333impl fmt::Debug for X509VerifyError {
1334 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1335 fmt.debug_struct("X509VerifyError")
1336 .field("code", &self.0)
1337 .field("error", &self.error_string())
1338 .finish()
1339 }
1340}
1341
1342impl fmt::Display for X509VerifyError {
1343 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1344 fmt.write_str(self.error_string())
1345 }
1346}
1347
1348impl Error for X509VerifyError {}
1349
1350impl X509VerifyError {
1351 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1358 if err == ffi::X509_V_OK {
1359 Ok(())
1360 } else {
1361 Err(X509VerifyError(err))
1362 }
1363 }
1364
1365 #[allow(clippy::trivially_copy_pass_by_ref)]
1367 pub fn as_raw(&self) -> c_int {
1368 self.0
1369 }
1370
1371 #[corresponds(X509_verify_cert_error_string)]
1373 #[allow(clippy::trivially_copy_pass_by_ref)]
1374 pub fn error_string(&self) -> &'static str {
1375 ffi::init();
1376
1377 unsafe {
1378 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1379 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1380 }
1381 }
1382}
1383
1384#[allow(missing_docs)] impl X509VerifyError {
1386 pub const UNSPECIFIED: Self = Self(ffi::X509_V_ERR_UNSPECIFIED);
1387 pub const UNABLE_TO_GET_ISSUER_CERT: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
1388 pub const UNABLE_TO_GET_CRL: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL);
1389 pub const UNABLE_TO_DECRYPT_CERT_SIGNATURE: Self =
1390 Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
1391 pub const UNABLE_TO_DECRYPT_CRL_SIGNATURE: Self =
1392 Self(ffi::X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
1393 pub const UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Self =
1394 Self(ffi::X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
1395 pub const CERT_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CERT_SIGNATURE_FAILURE);
1396 pub const CRL_SIGNATURE_FAILURE: Self = Self(ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE);
1397 pub const CERT_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CERT_NOT_YET_VALID);
1398 pub const CERT_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CERT_HAS_EXPIRED);
1399 pub const CRL_NOT_YET_VALID: Self = Self(ffi::X509_V_ERR_CRL_NOT_YET_VALID);
1400 pub const CRL_HAS_EXPIRED: Self = Self(ffi::X509_V_ERR_CRL_HAS_EXPIRED);
1401 pub const ERROR_IN_CERT_NOT_BEFORE_FIELD: Self =
1402 Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
1403 pub const ERROR_IN_CERT_NOT_AFTER_FIELD: Self =
1404 Self(ffi::X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
1405 pub const ERROR_IN_CRL_LAST_UPDATE_FIELD: Self =
1406 Self(ffi::X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
1407 pub const ERROR_IN_CRL_NEXT_UPDATE_FIELD: Self =
1408 Self(ffi::X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
1409 pub const OUT_OF_MEM: Self = Self(ffi::X509_V_ERR_OUT_OF_MEM);
1410 pub const DEPTH_ZERO_SELF_SIGNED_CERT: Self = Self(ffi::X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
1411 pub const SELF_SIGNED_CERT_IN_CHAIN: Self = Self(ffi::X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
1412 pub const UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Self =
1413 Self(ffi::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
1414 pub const UNABLE_TO_VERIFY_LEAF_SIGNATURE: Self =
1415 Self(ffi::X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
1416 pub const CERT_CHAIN_TOO_LONG: Self = Self(ffi::X509_V_ERR_CERT_CHAIN_TOO_LONG);
1417 pub const CERT_REVOKED: Self = Self(ffi::X509_V_ERR_CERT_REVOKED);
1418 pub const INVALID_CA: Self = Self(ffi::X509_V_ERR_INVALID_CA);
1419 pub const PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PATH_LENGTH_EXCEEDED);
1420 pub const INVALID_PURPOSE: Self = Self(ffi::X509_V_ERR_INVALID_PURPOSE);
1421 pub const CERT_UNTRUSTED: Self = Self(ffi::X509_V_ERR_CERT_UNTRUSTED);
1422 pub const CERT_REJECTED: Self = Self(ffi::X509_V_ERR_CERT_REJECTED);
1423 pub const SUBJECT_ISSUER_MISMATCH: Self = Self(ffi::X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
1424 pub const AKID_SKID_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_SKID_MISMATCH);
1425 pub const AKID_ISSUER_SERIAL_MISMATCH: Self = Self(ffi::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
1426 pub const KEYUSAGE_NO_CERTSIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
1427 pub const UNABLE_TO_GET_CRL_ISSUER: Self = Self(ffi::X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
1428 pub const UNHANDLED_CRITICAL_EXTENSION: Self =
1429 Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
1430 pub const KEYUSAGE_NO_CRL_SIGN: Self = Self(ffi::X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
1431 pub const UNHANDLED_CRITICAL_CRL_EXTENSION: Self =
1432 Self(ffi::X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
1433 pub const INVALID_NON_CA: Self = Self(ffi::X509_V_ERR_INVALID_NON_CA);
1434 pub const PROXY_PATH_LENGTH_EXCEEDED: Self = Self(ffi::X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
1435 pub const KEYUSAGE_NO_DIGITAL_SIGNATURE: Self =
1436 Self(ffi::X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
1437 pub const PROXY_CERTIFICATES_NOT_ALLOWED: Self =
1438 Self(ffi::X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
1439 pub const INVALID_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_EXTENSION);
1440 pub const INVALID_POLICY_EXTENSION: Self = Self(ffi::X509_V_ERR_INVALID_POLICY_EXTENSION);
1441 pub const NO_EXPLICIT_POLICY: Self = Self(ffi::X509_V_ERR_NO_EXPLICIT_POLICY);
1442 pub const DIFFERENT_CRL_SCOPE: Self = Self(ffi::X509_V_ERR_DIFFERENT_CRL_SCOPE);
1443 pub const UNSUPPORTED_EXTENSION_FEATURE: Self =
1444 Self(ffi::X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
1445 pub const UNNESTED_RESOURCE: Self = Self(ffi::X509_V_ERR_UNNESTED_RESOURCE);
1446 pub const PERMITTED_VIOLATION: Self = Self(ffi::X509_V_ERR_PERMITTED_VIOLATION);
1447 pub const EXCLUDED_VIOLATION: Self = Self(ffi::X509_V_ERR_EXCLUDED_VIOLATION);
1448 pub const SUBTREE_MINMAX: Self = Self(ffi::X509_V_ERR_SUBTREE_MINMAX);
1449 pub const APPLICATION_VERIFICATION: Self = Self(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1450 pub const UNSUPPORTED_CONSTRAINT_TYPE: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
1451 pub const UNSUPPORTED_CONSTRAINT_SYNTAX: Self =
1452 Self(ffi::X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
1453 pub const UNSUPPORTED_NAME_SYNTAX: Self = Self(ffi::X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
1454 pub const CRL_PATH_VALIDATION_ERROR: Self = Self(ffi::X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
1455 pub const HOSTNAME_MISMATCH: Self = Self(ffi::X509_V_ERR_HOSTNAME_MISMATCH);
1456 pub const EMAIL_MISMATCH: Self = Self(ffi::X509_V_ERR_EMAIL_MISMATCH);
1457 pub const IP_ADDRESS_MISMATCH: Self = Self(ffi::X509_V_ERR_IP_ADDRESS_MISMATCH);
1458 pub const INVALID_CALL: Self = Self(ffi::X509_V_ERR_INVALID_CALL);
1459 pub const STORE_LOOKUP: Self = Self(ffi::X509_V_ERR_STORE_LOOKUP);
1460 pub const NAME_CONSTRAINTS_WITHOUT_SANS: Self =
1461 Self(ffi::X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS);
1462}
1463
1464foreign_type_and_impl_send_sync! {
1465 type CType = ffi::GENERAL_NAME;
1466 fn drop = ffi::GENERAL_NAME_free;
1467
1468 pub struct GeneralName;
1470}
1471
1472impl GeneralName {
1473 unsafe fn new(
1474 type_: c_int,
1475 asn1_type: Asn1Type,
1476 value: &[u8],
1477 ) -> Result<GeneralName, ErrorStack> {
1478 ffi::init();
1479 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
1480 (*gn.as_ptr()).type_ = type_;
1481 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
1482 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
1483
1484 (*gn.as_ptr()).d.ptr = s.cast();
1485
1486 Ok(gn)
1487 }
1488
1489 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
1490 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
1491 }
1492
1493 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
1494 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
1495 }
1496
1497 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
1498 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
1499 }
1500
1501 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
1502 match ip {
1503 IpAddr::V4(addr) => unsafe {
1504 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1505 },
1506 IpAddr::V6(addr) => unsafe {
1507 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
1508 },
1509 }
1510 }
1511
1512 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
1513 unsafe {
1514 ffi::init();
1515 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
1516 (*gn).type_ = ffi::GEN_RID;
1517 (*gn).d.registeredID = oid.into_ptr();
1518
1519 Ok(GeneralName::from_ptr(gn))
1520 }
1521 }
1522}
1523
1524impl GeneralNameRef {
1525 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
1526 unsafe {
1527 if (*self.as_ptr()).type_ != ffi_type {
1528 return None;
1529 }
1530
1531 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
1532 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
1533
1534 let slice = slice::from_raw_parts(ptr, len as usize);
1535 str::from_utf8(slice).ok()
1539 }
1540 }
1541
1542 pub fn email(&self) -> Option<&str> {
1544 self.ia5_string(ffi::GEN_EMAIL)
1545 }
1546
1547 pub fn dnsname(&self) -> Option<&str> {
1549 self.ia5_string(ffi::GEN_DNS)
1550 }
1551
1552 pub fn uri(&self) -> Option<&str> {
1554 self.ia5_string(ffi::GEN_URI)
1555 }
1556
1557 pub fn ipaddress(&self) -> Option<&[u8]> {
1559 unsafe {
1560 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
1561 return None;
1562 }
1563
1564 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
1565 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
1566
1567 Some(slice::from_raw_parts(ptr, len as usize))
1568 }
1569 }
1570}
1571
1572impl fmt::Debug for GeneralNameRef {
1573 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1574 if let Some(email) = self.email() {
1575 formatter.write_str(email)
1576 } else if let Some(dnsname) = self.dnsname() {
1577 formatter.write_str(dnsname)
1578 } else if let Some(uri) = self.uri() {
1579 formatter.write_str(uri)
1580 } else if let Some(ipaddress) = self.ipaddress() {
1581 let result = String::from_utf8_lossy(ipaddress);
1582 formatter.write_str(&result)
1583 } else {
1584 formatter.write_str("(empty)")
1585 }
1586 }
1587}
1588
1589impl Stackable for GeneralName {
1590 type StackType = ffi::stack_st_GENERAL_NAME;
1591}
1592
1593foreign_type_and_impl_send_sync! {
1594 type CType = ffi::X509_ALGOR;
1595 fn drop = ffi::X509_ALGOR_free;
1596
1597 pub struct X509Algorithm;
1599}
1600
1601impl X509AlgorithmRef {
1602 pub fn object(&self) -> &Asn1ObjectRef {
1604 unsafe {
1605 let mut oid = ptr::null();
1606 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
1607 assert!(!oid.is_null());
1608 Asn1ObjectRef::from_ptr(oid as *mut _)
1609 }
1610 }
1611}
1612
1613foreign_type_and_impl_send_sync! {
1614 type CType = ffi::X509_OBJECT;
1615 fn drop = X509_OBJECT_free;
1616
1617 pub struct X509Object;
1619}
1620
1621impl X509ObjectRef {
1622 pub fn x509(&self) -> Option<&X509Ref> {
1623 unsafe {
1624 let ptr = X509_OBJECT_get0_X509(self.as_ptr());
1625 if ptr.is_null() {
1626 None
1627 } else {
1628 Some(X509Ref::from_ptr(ptr))
1629 }
1630 }
1631 }
1632}
1633
1634impl Stackable for X509Object {
1635 type StackType = ffi::stack_st_X509_OBJECT;
1636}
1637
1638use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
1639
1640use crate::ffi::{
1641 ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
1642 X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
1643};
1644
1645use crate::ffi::X509_OBJECT_get0_X509;
1646
1647#[allow(bad_style)]
1648unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
1649 ffi::X509_OBJECT_free_contents(x);
1650 ffi::OPENSSL_free(x as *mut libc::c_void);
1651}