1use cfg_if::cfg_if;
11use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
12use libc::{c_int, c_long, 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
43#[cfg(any(ossl102, boringssl, libressl261, awslc))]
44pub mod verify;
45
46pub mod extension;
47pub mod store;
48
49#[cfg(test)]
50mod tests;
51
52pub unsafe trait ExtensionType {
58 const NID: Nid;
59 type Output: ForeignType;
60}
61
62foreign_type_and_impl_send_sync! {
63 type CType = ffi::X509_STORE_CTX;
64 fn drop = ffi::X509_STORE_CTX_free;
65
66 pub struct X509StoreContext;
68
69 pub struct X509StoreContextRef;
71}
72
73impl X509StoreContext {
74 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
77 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
78 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
79 }
80
81 #[corresponds(X509_STORE_CTX_new)]
83 pub fn new() -> Result<X509StoreContext, ErrorStack> {
84 unsafe {
85 ffi::init();
86 cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext)
87 }
88 }
89}
90
91impl X509StoreContextRef {
92 #[corresponds(X509_STORE_CTX_get_ex_data)]
94 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
95 unsafe {
96 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
97 if data.is_null() {
98 None
99 } else {
100 Some(&*(data as *const T))
101 }
102 }
103 }
104
105 #[corresponds(X509_STORE_CTX_get_error)]
107 pub fn error(&self) -> X509VerifyResult {
108 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
109 }
110
111 pub fn init<F, T>(
127 &mut self,
128 trust: &store::X509StoreRef,
129 cert: &X509Ref,
130 cert_chain: &StackRef<X509>,
131 with_context: F,
132 ) -> Result<T, ErrorStack>
133 where
134 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
135 {
136 struct Cleanup<'a>(&'a mut X509StoreContextRef);
137
138 impl Drop for Cleanup<'_> {
139 fn drop(&mut self) {
140 unsafe {
141 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
142 }
143 }
144 }
145
146 unsafe {
147 cvt(ffi::X509_STORE_CTX_init(
148 self.as_ptr(),
149 trust.as_ptr(),
150 cert.as_ptr(),
151 cert_chain.as_ptr(),
152 ))?;
153
154 let cleanup = Cleanup(self);
155 with_context(cleanup.0)
156 }
157 }
158
159 #[corresponds(X509_verify_cert)]
166 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
167 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
168 }
169
170 #[corresponds(X509_STORE_CTX_set_error)]
172 pub fn set_error(&mut self, result: X509VerifyResult) {
173 unsafe {
174 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
175 }
176 }
177
178 #[corresponds(X509_STORE_CTX_get_current_cert)]
181 pub fn current_cert(&self) -> Option<&X509Ref> {
182 unsafe {
183 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
184 X509Ref::from_const_ptr_opt(ptr)
185 }
186 }
187
188 #[corresponds(X509_STORE_CTX_get_error_depth)]
193 pub fn error_depth(&self) -> u32 {
194 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
195 }
196
197 #[corresponds(X509_STORE_CTX_get0_chain)]
199 pub fn chain(&self) -> Option<&StackRef<X509>> {
200 unsafe {
201 let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
202
203 if chain.is_null() {
204 None
205 } else {
206 Some(StackRef::from_ptr(chain))
207 }
208 }
209 }
210}
211
212pub struct X509Builder(X509);
214
215impl X509Builder {
216 #[corresponds(X509_new)]
218 pub fn new() -> Result<X509Builder, ErrorStack> {
219 unsafe {
220 ffi::init();
221 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
222 }
223 }
224
225 #[corresponds(X509_set1_notAfter)]
227 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
228 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
229 }
230
231 #[corresponds(X509_set1_notBefore)]
233 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
234 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
235 }
236
237 #[corresponds(X509_set_version)]
242 #[allow(clippy::useless_conversion)]
243 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
244 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
245 }
246
247 #[corresponds(X509_set_serialNumber)]
249 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
250 unsafe {
251 cvt(ffi::X509_set_serialNumber(
252 self.0.as_ptr(),
253 serial_number.as_ptr(),
254 ))
255 .map(|_| ())
256 }
257 }
258
259 #[corresponds(X509_set_issuer_name)]
261 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
262 unsafe {
263 cvt(ffi::X509_set_issuer_name(
264 self.0.as_ptr(),
265 issuer_name.as_ptr(),
266 ))
267 .map(|_| ())
268 }
269 }
270
271 #[corresponds(X509_set_subject_name)]
290 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
291 unsafe {
292 cvt(ffi::X509_set_subject_name(
293 self.0.as_ptr(),
294 subject_name.as_ptr(),
295 ))
296 .map(|_| ())
297 }
298 }
299
300 #[corresponds(X509_set_pubkey)]
302 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
303 where
304 T: HasPublic,
305 {
306 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
307 }
308
309 #[corresponds(X509V3_set_ctx)]
313 pub fn x509v3_context<'a>(
314 &'a self,
315 issuer: Option<&'a X509Ref>,
316 conf: Option<&'a ConfRef>,
317 ) -> X509v3Context<'a> {
318 unsafe {
319 let mut ctx = mem::zeroed();
320
321 let issuer = match issuer {
322 Some(issuer) => issuer.as_ptr(),
323 None => self.0.as_ptr(),
324 };
325 let subject = self.0.as_ptr();
326 ffi::X509V3_set_ctx(
327 &mut ctx,
328 issuer,
329 subject,
330 ptr::null_mut(),
331 ptr::null_mut(),
332 0,
333 );
334
335 if let Some(conf) = conf {
337 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
338 }
339
340 X509v3Context(ctx, PhantomData)
341 }
342 }
343
344 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
348 self.append_extension2(&extension)
349 }
350
351 #[corresponds(X509_add_ext)]
353 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
354 unsafe {
355 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
356 Ok(())
357 }
358 }
359
360 #[corresponds(X509_sign)]
362 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
363 where
364 T: HasPrivate,
365 {
366 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
367 }
368
369 pub fn build(self) -> X509 {
371 self.0
372 }
373}
374
375foreign_type_and_impl_send_sync! {
376 type CType = ffi::X509;
377 fn drop = ffi::X509_free;
378
379 pub struct X509;
381 pub struct X509Ref;
383}
384
385impl X509Ref {
386 #[corresponds(X509_get_subject_name)]
388 pub fn subject_name(&self) -> &X509NameRef {
389 unsafe {
390 let name = ffi::X509_get_subject_name(self.as_ptr());
391 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
392 }
393 }
394
395 #[corresponds(X509_subject_name_hash)]
397 pub fn subject_name_hash(&self) -> u32 {
398 #[allow(clippy::unnecessary_cast)]
399 unsafe {
400 ffi::X509_subject_name_hash(self.as_ptr()) as u32
401 }
402 }
403
404 #[corresponds(X509_get_issuer_name)]
406 pub fn issuer_name(&self) -> &X509NameRef {
407 unsafe {
408 let name = ffi::X509_get_issuer_name(self.as_ptr());
409 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
410 }
411 }
412
413 #[corresponds(X509_issuer_name_hash)]
415 pub fn issuer_name_hash(&self) -> u32 {
416 #[allow(clippy::unnecessary_cast)]
417 unsafe {
418 ffi::X509_issuer_name_hash(self.as_ptr()) as u32
419 }
420 }
421
422 #[corresponds(X509_get_ext_d2i)]
424 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
425 unsafe {
426 let stack = ffi::X509_get_ext_d2i(
427 self.as_ptr(),
428 ffi::NID_subject_alt_name,
429 ptr::null_mut(),
430 ptr::null_mut(),
431 );
432 Stack::from_ptr_opt(stack as *mut _)
433 }
434 }
435
436 #[corresponds(X509_get_ext_d2i)]
438 pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> {
439 unsafe {
440 let stack = ffi::X509_get_ext_d2i(
441 self.as_ptr(),
442 ffi::NID_crl_distribution_points,
443 ptr::null_mut(),
444 ptr::null_mut(),
445 );
446 Stack::from_ptr_opt(stack as *mut _)
447 }
448 }
449
450 #[corresponds(X509_get_ext_d2i)]
452 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
453 unsafe {
454 let stack = ffi::X509_get_ext_d2i(
455 self.as_ptr(),
456 ffi::NID_issuer_alt_name,
457 ptr::null_mut(),
458 ptr::null_mut(),
459 );
460 Stack::from_ptr_opt(stack as *mut _)
461 }
462 }
463
464 #[corresponds(X509_get_ext_d2i)]
468 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
469 unsafe {
470 let stack = ffi::X509_get_ext_d2i(
471 self.as_ptr(),
472 ffi::NID_info_access,
473 ptr::null_mut(),
474 ptr::null_mut(),
475 );
476 Stack::from_ptr_opt(stack as *mut _)
477 }
478 }
479
480 #[corresponds(X509_get_pathlen)]
482 #[cfg(any(ossl110, boringssl, awslc))]
483 pub fn pathlen(&self) -> Option<u32> {
484 let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
485 u32::try_from(v).ok()
486 }
487
488 #[corresponds(X509_get0_subject_key_id)]
490 #[cfg(any(ossl110, boringssl, awslc))]
491 pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
492 unsafe {
493 let data = ffi::X509_get0_subject_key_id(self.as_ptr());
494 Asn1OctetStringRef::from_const_ptr_opt(data)
495 }
496 }
497
498 #[corresponds(X509_get0_authority_key_id)]
500 #[cfg(any(ossl110, boringssl, awslc))]
501 pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
502 unsafe {
503 let data = ffi::X509_get0_authority_key_id(self.as_ptr());
504 Asn1OctetStringRef::from_const_ptr_opt(data)
505 }
506 }
507
508 #[corresponds(X509_get0_authority_issuer)]
510 #[cfg(ossl111d)]
511 pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
512 unsafe {
513 let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
514 StackRef::from_const_ptr_opt(stack)
515 }
516 }
517
518 #[corresponds(X509_get0_authority_serial)]
520 #[cfg(ossl111d)]
521 pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
522 unsafe {
523 let r = ffi::X509_get0_authority_serial(self.as_ptr());
524 Asn1IntegerRef::from_const_ptr_opt(r)
525 }
526 }
527
528 #[corresponds(X509_get_pubkey)]
529 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
530 unsafe {
531 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
532 Ok(PKey::from_ptr(pkey))
533 }
534 }
535
536 #[corresponds(X509_digest)]
538 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
539 unsafe {
540 let mut digest = DigestBytes {
541 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
542 len: ffi::EVP_MAX_MD_SIZE as usize,
543 };
544 let mut len = ffi::EVP_MAX_MD_SIZE as c_uint;
545 cvt(ffi::X509_digest(
546 self.as_ptr(),
547 hash_type.as_ptr(),
548 digest.buf.as_mut_ptr() as *mut _,
549 &mut len,
550 ))?;
551 digest.len = len as usize;
552
553 Ok(digest)
554 }
555 }
556
557 #[deprecated(since = "0.10.9", note = "renamed to digest")]
558 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
559 self.digest(hash_type).map(|b| b.to_vec())
560 }
561
562 #[corresponds(X509_getm_notAfter)]
564 pub fn not_after(&self) -> &Asn1TimeRef {
565 unsafe {
566 let date = X509_getm_notAfter(self.as_ptr());
567 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
568 }
569 }
570
571 #[corresponds(X509_getm_notBefore)]
573 pub fn not_before(&self) -> &Asn1TimeRef {
574 unsafe {
575 let date = X509_getm_notBefore(self.as_ptr());
576 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
577 }
578 }
579
580 #[corresponds(X509_get0_signature)]
582 pub fn signature(&self) -> &Asn1BitStringRef {
583 unsafe {
584 let mut signature = ptr::null();
585 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
586 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
587 }
588 }
589
590 #[corresponds(X509_get0_signature)]
592 pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
593 unsafe {
594 let mut algor = ptr::null();
595 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
596 X509AlgorithmRef::from_const_ptr_opt(algor)
597 .expect("signature algorithm must not be null")
598 }
599 }
600
601 #[corresponds(X509_get1_ocsp)]
604 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
605 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
606 }
607
608 #[corresponds(X509_check_issued)]
610 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
611 unsafe {
612 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
613 X509VerifyResult::from_raw(r)
614 }
615 }
616
617 #[corresponds(X509_get_version)]
622 #[cfg(ossl110)]
623 #[allow(clippy::unnecessary_cast)]
624 pub fn version(&self) -> i32 {
625 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
626 }
627
628 #[corresponds(X509_verify)]
635 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
636 where
637 T: HasPublic,
638 {
639 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
640 }
641
642 #[corresponds(X509_get_serialNumber)]
644 pub fn serial_number(&self) -> &Asn1IntegerRef {
645 unsafe {
646 let r = ffi::X509_get_serialNumber(self.as_ptr());
647 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
648 }
649 }
650
651 #[corresponds(X509_alias_get0)]
657 pub fn alias(&self) -> Option<&[u8]> {
658 unsafe {
659 let mut len = 0;
660 let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len);
661 if ptr.is_null() {
662 None
663 } else {
664 Some(util::from_raw_parts(ptr, len as usize))
665 }
666 }
667 }
668
669 to_pem! {
670 #[corresponds(PEM_write_bio_X509)]
674 to_pem,
675 ffi::PEM_write_bio_X509
676 }
677
678 to_der! {
679 #[corresponds(i2d_X509)]
681 to_der,
682 ffi::i2d_X509
683 }
684
685 to_pem! {
686 #[corresponds(X509_print)]
688 to_text,
689 ffi::X509_print
690 }
691}
692
693impl ToOwned for X509Ref {
694 type Owned = X509;
695
696 fn to_owned(&self) -> X509 {
697 unsafe {
698 X509_up_ref(self.as_ptr());
699 X509::from_ptr(self.as_ptr())
700 }
701 }
702}
703
704impl Ord for X509Ref {
705 fn cmp(&self, other: &Self) -> cmp::Ordering {
706 let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
709 cmp.cmp(&0)
710 }
711}
712
713impl PartialOrd for X509Ref {
714 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
715 Some(self.cmp(other))
716 }
717}
718
719impl PartialOrd<X509> for X509Ref {
720 fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
721 <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
722 }
723}
724
725impl PartialEq for X509Ref {
726 fn eq(&self, other: &Self) -> bool {
727 self.cmp(other) == cmp::Ordering::Equal
728 }
729}
730
731impl PartialEq<X509> for X509Ref {
732 fn eq(&self, other: &X509) -> bool {
733 <X509Ref as PartialEq<X509Ref>>::eq(self, other)
734 }
735}
736
737impl Eq for X509Ref {}
738
739impl X509 {
740 pub fn builder() -> Result<X509Builder, ErrorStack> {
742 X509Builder::new()
743 }
744
745 from_pem! {
746 #[corresponds(PEM_read_bio_X509)]
750 from_pem,
751 X509,
752 ffi::PEM_read_bio_X509
753 }
754
755 from_der! {
756 #[corresponds(d2i_X509)]
758 from_der,
759 X509,
760 ffi::d2i_X509
761 }
762
763 #[corresponds(PEM_read_bio_X509)]
765 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
766 unsafe {
767 ffi::init();
768 let bio = MemBioSlice::new(pem)?;
769
770 let mut certs = vec![];
771 loop {
772 let r =
773 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
774 if r.is_null() {
775 let e = ErrorStack::get();
776
777 if let Some(err) = e.errors().last() {
778 if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int
779 && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int
780 {
781 break;
782 }
783 }
784
785 return Err(e);
786 } else {
787 certs.push(X509(r));
788 }
789 }
790
791 Ok(certs)
792 }
793 }
794}
795
796impl Clone for X509 {
797 fn clone(&self) -> X509 {
798 X509Ref::to_owned(self)
799 }
800}
801
802impl fmt::Debug for X509 {
803 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
804 let serial = match &self.serial_number().to_bn() {
805 Ok(bn) => match bn.to_hex_str() {
806 Ok(hex) => hex.to_string(),
807 Err(_) => "".to_string(),
808 },
809 Err(_) => "".to_string(),
810 };
811 let mut debug_struct = formatter.debug_struct("X509");
812 debug_struct.field("serial_number", &serial);
813 debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
814 debug_struct.field("issuer", &self.issuer_name());
815 debug_struct.field("subject", &self.subject_name());
816 if let Some(subject_alt_names) = &self.subject_alt_names() {
817 debug_struct.field("subject_alt_names", subject_alt_names);
818 }
819 debug_struct.field("not_before", &self.not_before());
820 debug_struct.field("not_after", &self.not_after());
821
822 if let Ok(public_key) = &self.public_key() {
823 debug_struct.field("public_key", public_key);
824 };
825 debug_struct.finish()
828 }
829}
830
831impl AsRef<X509Ref> for X509Ref {
832 fn as_ref(&self) -> &X509Ref {
833 self
834 }
835}
836
837impl Stackable for X509 {
838 type StackType = ffi::stack_st_X509;
839}
840
841impl Ord for X509 {
842 fn cmp(&self, other: &Self) -> cmp::Ordering {
843 X509Ref::cmp(self, other)
844 }
845}
846
847impl PartialOrd for X509 {
848 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
849 Some(self.cmp(other))
850 }
851}
852
853impl PartialOrd<X509Ref> for X509 {
854 fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
855 X509Ref::partial_cmp(self, other)
856 }
857}
858
859impl PartialEq for X509 {
860 fn eq(&self, other: &Self) -> bool {
861 X509Ref::eq(self, other)
862 }
863}
864
865impl PartialEq<X509Ref> for X509 {
866 fn eq(&self, other: &X509Ref) -> bool {
867 X509Ref::eq(self, other)
868 }
869}
870
871impl Eq for X509 {}
872
873pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
875
876impl X509v3Context<'_> {
877 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
878 &self.0 as *const _ as *mut _
879 }
880}
881
882foreign_type_and_impl_send_sync! {
883 type CType = ffi::X509_EXTENSION;
884 fn drop = ffi::X509_EXTENSION_free;
885
886 pub struct X509Extension;
888 pub struct X509ExtensionRef;
890}
891
892impl Stackable for X509Extension {
893 type StackType = ffi::stack_st_X509_EXTENSION;
894}
895
896impl X509Extension {
897 #[deprecated(
911 note = "Use x509::extension types or new_from_der instead",
912 since = "0.10.51"
913 )]
914 pub fn new(
915 conf: Option<&ConfRef>,
916 context: Option<&X509v3Context<'_>>,
917 name: &str,
918 value: &str,
919 ) -> Result<X509Extension, ErrorStack> {
920 let name = CString::new(name).unwrap();
921 let value = CString::new(value).unwrap();
922 let mut ctx;
923 unsafe {
924 ffi::init();
925 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
926 let context_ptr = match context {
927 Some(c) => c.as_ptr(),
928 None => {
929 ctx = mem::zeroed();
930
931 ffi::X509V3_set_ctx(
932 &mut ctx,
933 ptr::null_mut(),
934 ptr::null_mut(),
935 ptr::null_mut(),
936 ptr::null_mut(),
937 0,
938 );
939 &mut ctx
940 }
941 };
942 let name = name.as_ptr() as *mut _;
943 let value = value.as_ptr() as *mut _;
944
945 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
946 }
947 }
948
949 #[deprecated(
963 note = "Use x509::extension types or new_from_der instead",
964 since = "0.10.51"
965 )]
966 pub fn new_nid(
967 conf: Option<&ConfRef>,
968 context: Option<&X509v3Context<'_>>,
969 name: Nid,
970 value: &str,
971 ) -> Result<X509Extension, ErrorStack> {
972 let value = CString::new(value).unwrap();
973 let mut ctx;
974 unsafe {
975 ffi::init();
976 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
977 let context_ptr = match context {
978 Some(c) => c.as_ptr(),
979 None => {
980 ctx = mem::zeroed();
981
982 ffi::X509V3_set_ctx(
983 &mut ctx,
984 ptr::null_mut(),
985 ptr::null_mut(),
986 ptr::null_mut(),
987 ptr::null_mut(),
988 0,
989 );
990 &mut ctx
991 }
992 };
993 let name = name.as_raw();
994 let value = value.as_ptr() as *mut _;
995
996 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
997 }
998 }
999
1000 pub fn new_from_der(
1010 oid: &Asn1ObjectRef,
1011 critical: bool,
1012 der_contents: &Asn1OctetStringRef,
1013 ) -> Result<X509Extension, ErrorStack> {
1014 unsafe {
1015 cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1016 ptr::null_mut(),
1017 oid.as_ptr(),
1018 critical as _,
1019 der_contents.as_ptr(),
1020 ))
1021 .map(X509Extension)
1022 }
1023 }
1024
1025 pub(crate) unsafe fn new_internal(
1026 nid: Nid,
1027 critical: bool,
1028 value: *mut c_void,
1029 ) -> Result<X509Extension, ErrorStack> {
1030 ffi::init();
1031 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1032 }
1033
1034 #[cfg(not(libressl390))]
1040 #[corresponds(X509V3_EXT_add_alias)]
1041 #[deprecated(
1042 note = "Use x509::extension types or new_from_der and then this is not necessary",
1043 since = "0.10.51"
1044 )]
1045 pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1046 ffi::init();
1047 cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1048 }
1049}
1050
1051impl X509ExtensionRef {
1052 to_der! {
1053 #[corresponds(i2d_X509_EXTENSION)]
1055 to_der,
1056 ffi::i2d_X509_EXTENSION
1057 }
1058}
1059
1060pub struct X509NameBuilder(X509Name);
1062
1063impl X509NameBuilder {
1064 pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1066 unsafe {
1067 ffi::init();
1068 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1069 }
1070 }
1071
1072 #[corresponds(X509_NAME_add_entry)]
1074 #[cfg(any(ossl101, libressl350))]
1075 pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1076 unsafe {
1077 cvt(ffi::X509_NAME_add_entry(
1078 self.0.as_ptr(),
1079 ne.as_ptr(),
1080 -1,
1081 0,
1082 ))
1083 .map(|_| ())
1084 }
1085 }
1086
1087 #[corresponds(X509_NAME_add_entry_by_txt)]
1089 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1090 unsafe {
1091 let field = CString::new(field).unwrap();
1092 assert!(value.len() <= crate::SLenType::MAX as usize);
1093 cvt(ffi::X509_NAME_add_entry_by_txt(
1094 self.0.as_ptr(),
1095 field.as_ptr() as *mut _,
1096 ffi::MBSTRING_UTF8,
1097 value.as_ptr(),
1098 value.len() as crate::SLenType,
1099 -1,
1100 0,
1101 ))
1102 .map(|_| ())
1103 }
1104 }
1105
1106 #[corresponds(X509_NAME_add_entry_by_txt)]
1108 pub fn append_entry_by_text_with_type(
1109 &mut self,
1110 field: &str,
1111 value: &str,
1112 ty: Asn1Type,
1113 ) -> Result<(), ErrorStack> {
1114 unsafe {
1115 let field = CString::new(field).unwrap();
1116 assert!(value.len() <= crate::SLenType::MAX as usize);
1117 cvt(ffi::X509_NAME_add_entry_by_txt(
1118 self.0.as_ptr(),
1119 field.as_ptr() as *mut _,
1120 ty.as_raw(),
1121 value.as_ptr(),
1122 value.len() as crate::SLenType,
1123 -1,
1124 0,
1125 ))
1126 .map(|_| ())
1127 }
1128 }
1129
1130 #[corresponds(X509_NAME_add_entry_by_NID)]
1132 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1133 unsafe {
1134 assert!(value.len() <= crate::SLenType::MAX as usize);
1135 cvt(ffi::X509_NAME_add_entry_by_NID(
1136 self.0.as_ptr(),
1137 field.as_raw(),
1138 ffi::MBSTRING_UTF8,
1139 value.as_ptr() as *mut _,
1140 value.len() as crate::SLenType,
1141 -1,
1142 0,
1143 ))
1144 .map(|_| ())
1145 }
1146 }
1147
1148 #[corresponds(X509_NAME_add_entry_by_NID)]
1150 pub fn append_entry_by_nid_with_type(
1151 &mut self,
1152 field: Nid,
1153 value: &str,
1154 ty: Asn1Type,
1155 ) -> Result<(), ErrorStack> {
1156 unsafe {
1157 assert!(value.len() <= crate::SLenType::MAX as usize);
1158 cvt(ffi::X509_NAME_add_entry_by_NID(
1159 self.0.as_ptr(),
1160 field.as_raw(),
1161 ty.as_raw(),
1162 value.as_ptr() as *mut _,
1163 value.len() as crate::SLenType,
1164 -1,
1165 0,
1166 ))
1167 .map(|_| ())
1168 }
1169 }
1170
1171 pub fn build(self) -> X509Name {
1173 X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1177 }
1178}
1179
1180foreign_type_and_impl_send_sync! {
1181 type CType = ffi::X509_NAME;
1182 fn drop = ffi::X509_NAME_free;
1183
1184 pub struct X509Name;
1186 pub struct X509NameRef;
1188}
1189
1190impl X509Name {
1191 pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1193 X509NameBuilder::new()
1194 }
1195
1196 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1200 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1201 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1202 }
1203
1204 from_der! {
1205 from_der,
1211 X509Name,
1212 ffi::d2i_X509_NAME
1213 }
1214}
1215
1216impl Stackable for X509Name {
1217 type StackType = ffi::stack_st_X509_NAME;
1218}
1219
1220impl X509NameRef {
1221 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1223 X509NameEntries {
1224 name: self,
1225 nid: Some(nid),
1226 loc: -1,
1227 }
1228 }
1229
1230 pub fn entries(&self) -> X509NameEntries<'_> {
1232 X509NameEntries {
1233 name: self,
1234 nid: None,
1235 loc: -1,
1236 }
1237 }
1238
1239 #[corresponds(X509_NAME_cmp)]
1246 pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1247 let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1248 if cfg!(ossl300) && cmp == -2 {
1249 return Err(ErrorStack::get());
1250 }
1251 Ok(cmp.cmp(&0))
1252 }
1253
1254 #[corresponds(X509_NAME_dup)]
1256 #[cfg(any(boringssl, ossl110, libressl270, awslc))]
1257 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1258 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1259 }
1260
1261 to_der! {
1262 to_der,
1268 ffi::i2d_X509_NAME
1269 }
1270}
1271
1272impl fmt::Debug for X509NameRef {
1273 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1274 formatter.debug_list().entries(self.entries()).finish()
1275 }
1276}
1277
1278pub struct X509NameEntries<'a> {
1280 name: &'a X509NameRef,
1281 nid: Option<Nid>,
1282 loc: c_int,
1283}
1284
1285impl<'a> Iterator for X509NameEntries<'a> {
1286 type Item = &'a X509NameEntryRef;
1287
1288 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1289 unsafe {
1290 match self.nid {
1291 Some(nid) => {
1292 self.loc =
1294 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1295 if self.loc == -1 {
1296 return None;
1297 }
1298 }
1299 None => {
1300 self.loc += 1;
1302 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1303 return None;
1304 }
1305 }
1306 }
1307
1308 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1309
1310 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1311 }
1312 }
1313}
1314
1315foreign_type_and_impl_send_sync! {
1316 type CType = ffi::X509_NAME_ENTRY;
1317 fn drop = ffi::X509_NAME_ENTRY_free;
1318
1319 pub struct X509NameEntry;
1321 pub struct X509NameEntryRef;
1323}
1324
1325impl X509NameEntryRef {
1326 #[corresponds(X509_NAME_ENTRY_get_data)]
1328 pub fn data(&self) -> &Asn1StringRef {
1329 unsafe {
1330 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1331 Asn1StringRef::from_ptr(data)
1332 }
1333 }
1334
1335 #[corresponds(X509_NAME_ENTRY_get_object)]
1338 pub fn object(&self) -> &Asn1ObjectRef {
1339 unsafe {
1340 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1341 Asn1ObjectRef::from_ptr(object)
1342 }
1343 }
1344}
1345
1346impl fmt::Debug for X509NameEntryRef {
1347 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1348 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1349 }
1350}
1351
1352pub struct X509ReqBuilder(X509Req);
1354
1355impl X509ReqBuilder {
1356 #[corresponds(X509_REQ_new)]
1358 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1359 unsafe {
1360 ffi::init();
1361 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1362 }
1363 }
1364
1365 #[corresponds(X509_REQ_set_version)]
1367 #[allow(clippy::useless_conversion)]
1368 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1369 unsafe {
1370 cvt(ffi::X509_REQ_set_version(
1371 self.0.as_ptr(),
1372 version as c_long,
1373 ))
1374 .map(|_| ())
1375 }
1376 }
1377
1378 #[corresponds(X509_REQ_set_subject_name)]
1380 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1381 unsafe {
1382 cvt(ffi::X509_REQ_set_subject_name(
1383 self.0.as_ptr(),
1384 subject_name.as_ptr(),
1385 ))
1386 .map(|_| ())
1387 }
1388 }
1389
1390 #[corresponds(X509_REQ_set_pubkey)]
1392 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1393 where
1394 T: HasPublic,
1395 {
1396 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1397 }
1398
1399 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1402 unsafe {
1403 let mut ctx = mem::zeroed();
1404
1405 ffi::X509V3_set_ctx(
1406 &mut ctx,
1407 ptr::null_mut(),
1408 ptr::null_mut(),
1409 self.0.as_ptr(),
1410 ptr::null_mut(),
1411 0,
1412 );
1413
1414 if let Some(conf) = conf {
1416 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1417 }
1418
1419 X509v3Context(ctx, PhantomData)
1420 }
1421 }
1422
1423 pub fn add_extensions(
1425 &mut self,
1426 extensions: &StackRef<X509Extension>,
1427 ) -> Result<(), ErrorStack> {
1428 unsafe {
1429 cvt(ffi::X509_REQ_add_extensions(
1430 self.0.as_ptr(),
1431 extensions.as_ptr(),
1432 ))
1433 .map(|_| ())
1434 }
1435 }
1436
1437 #[corresponds(X509_REQ_sign)]
1439 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1440 where
1441 T: HasPrivate,
1442 {
1443 unsafe {
1444 cvt(ffi::X509_REQ_sign(
1445 self.0.as_ptr(),
1446 key.as_ptr(),
1447 hash.as_ptr(),
1448 ))
1449 .map(|_| ())
1450 }
1451 }
1452
1453 pub fn build(self) -> X509Req {
1455 self.0
1456 }
1457}
1458
1459foreign_type_and_impl_send_sync! {
1460 type CType = ffi::X509_REQ;
1461 fn drop = ffi::X509_REQ_free;
1462
1463 pub struct X509Req;
1465 pub struct X509ReqRef;
1467}
1468
1469impl X509Req {
1470 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1472 X509ReqBuilder::new()
1473 }
1474
1475 from_pem! {
1476 from_pem,
1484 X509Req,
1485 ffi::PEM_read_bio_X509_REQ
1486 }
1487
1488 from_der! {
1489 from_der,
1495 X509Req,
1496 ffi::d2i_X509_REQ
1497 }
1498}
1499
1500impl X509ReqRef {
1501 to_pem! {
1502 to_pem,
1510 ffi::PEM_write_bio_X509_REQ
1511 }
1512
1513 to_der! {
1514 to_der,
1520 ffi::i2d_X509_REQ
1521 }
1522
1523 to_pem! {
1524 #[corresponds(X509_Req_print)]
1526 to_text,
1527 ffi::X509_REQ_print
1528 }
1529
1530 #[corresponds(X509_REQ_get_version)]
1532 #[allow(clippy::unnecessary_cast)]
1533 pub fn version(&self) -> i32 {
1534 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1535 }
1536
1537 #[corresponds(X509_REQ_get_subject_name)]
1539 pub fn subject_name(&self) -> &X509NameRef {
1540 unsafe {
1541 let name = X509_REQ_get_subject_name(self.as_ptr());
1542 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1543 }
1544 }
1545
1546 #[corresponds(X509_REQ_get_pubkey)]
1548 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1549 unsafe {
1550 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1551 Ok(PKey::from_ptr(key))
1552 }
1553 }
1554
1555 #[corresponds(X509_REQ_verify)]
1559 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1560 where
1561 T: HasPublic,
1562 {
1563 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1564 }
1565
1566 #[corresponds(X509_REQ_get_extensions)]
1568 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1569 unsafe {
1570 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1571 Ok(Stack::from_ptr(extensions))
1572 }
1573 }
1574}
1575
1576#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1578pub struct CrlReason(c_int);
1579
1580#[allow(missing_docs)] impl CrlReason {
1582 pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1583 pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1584 pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1585 pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1586 pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1587 pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1588 pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1589 pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1590 pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1591 pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1592
1593 pub const fn from_raw(value: c_int) -> Self {
1595 CrlReason(value)
1596 }
1597
1598 pub const fn as_raw(&self) -> c_int {
1600 self.0
1601 }
1602}
1603
1604foreign_type_and_impl_send_sync! {
1605 type CType = ffi::X509_REVOKED;
1606 fn drop = ffi::X509_REVOKED_free;
1607
1608 pub struct X509Revoked;
1610 pub struct X509RevokedRef;
1612}
1613
1614impl Stackable for X509Revoked {
1615 type StackType = ffi::stack_st_X509_REVOKED;
1616}
1617
1618impl X509Revoked {
1619 from_der! {
1620 #[corresponds(d2i_X509_REVOKED)]
1622 from_der,
1623 X509Revoked,
1624 ffi::d2i_X509_REVOKED
1625 }
1626}
1627
1628impl X509RevokedRef {
1629 to_der! {
1630 #[corresponds(d2i_X509_REVOKED)]
1632 to_der,
1633 ffi::i2d_X509_REVOKED
1634 }
1635
1636 #[corresponds(X509_NAME_dup)]
1638 #[cfg(any(boringssl, ossl110, libressl270, awslc))]
1639 pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1640 unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1641 }
1642
1643 #[corresponds(X509_REVOKED_get0_revocationDate)]
1645 pub fn revocation_date(&self) -> &Asn1TimeRef {
1646 unsafe {
1647 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1648 assert!(!r.is_null());
1649 Asn1TimeRef::from_ptr(r as *mut _)
1650 }
1651 }
1652
1653 #[corresponds(X509_REVOKED_get0_serialNumber)]
1655 pub fn serial_number(&self) -> &Asn1IntegerRef {
1656 unsafe {
1657 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1658 assert!(!r.is_null());
1659 Asn1IntegerRef::from_ptr(r as *mut _)
1660 }
1661 }
1662
1663 #[corresponds(X509_REVOKED_get_ext_d2i)]
1667 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1668 let mut critical = -1;
1669 let out = unsafe {
1670 let ext = ffi::X509_REVOKED_get_ext_d2i(
1672 self.as_ptr(),
1673 T::NID.as_raw(),
1674 &mut critical as *mut _,
1675 ptr::null_mut(),
1676 );
1677 T::Output::from_ptr_opt(ext as *mut _)
1680 };
1681 match (critical, out) {
1682 (0, Some(out)) => Ok(Some((false, out))),
1683 (1, Some(out)) => Ok(Some((true, out))),
1684 (-1 | -2, _) => Ok(None),
1686 (0 | 1, None) => Err(ErrorStack::get()),
1689 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1690 }
1691 }
1692}
1693
1694pub enum ReasonCode {}
1697
1698unsafe impl ExtensionType for ReasonCode {
1701 const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1702
1703 type Output = Asn1Enumerated;
1704}
1705
1706pub enum CertificateIssuer {}
1709
1710unsafe impl ExtensionType for CertificateIssuer {
1713 const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1714
1715 type Output = Stack<GeneralName>;
1716}
1717
1718pub enum AuthorityInformationAccess {}
1720
1721unsafe impl ExtensionType for AuthorityInformationAccess {
1724 const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1725
1726 type Output = Stack<AccessDescription>;
1727}
1728
1729foreign_type_and_impl_send_sync! {
1730 type CType = ffi::X509_CRL;
1731 fn drop = ffi::X509_CRL_free;
1732
1733 pub struct X509Crl;
1735 pub struct X509CrlRef;
1737}
1738
1739pub enum CrlStatus<'a> {
1745 NotRevoked,
1747 Revoked(&'a X509RevokedRef),
1749 RemoveFromCrl(&'a X509RevokedRef),
1754}
1755
1756impl<'a> CrlStatus<'a> {
1757 unsafe fn from_ffi_status(
1762 status: c_int,
1763 revoked_entry: *mut ffi::X509_REVOKED,
1764 ) -> CrlStatus<'a> {
1765 match status {
1766 0 => CrlStatus::NotRevoked,
1767 1 => {
1768 assert!(!revoked_entry.is_null());
1769 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1770 }
1771 2 => {
1772 assert!(!revoked_entry.is_null());
1773 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1774 }
1775 _ => unreachable!(
1776 "{}",
1777 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1778 ),
1779 }
1780 }
1781}
1782
1783impl X509Crl {
1784 from_pem! {
1785 #[corresponds(PEM_read_bio_X509_CRL)]
1789 from_pem,
1790 X509Crl,
1791 ffi::PEM_read_bio_X509_CRL
1792 }
1793
1794 from_der! {
1795 #[corresponds(d2i_X509_CRL)]
1797 from_der,
1798 X509Crl,
1799 ffi::d2i_X509_CRL
1800 }
1801}
1802
1803impl X509CrlRef {
1804 to_pem! {
1805 #[corresponds(PEM_write_bio_X509_CRL)]
1809 to_pem,
1810 ffi::PEM_write_bio_X509_CRL
1811 }
1812
1813 to_der! {
1814 #[corresponds(i2d_X509_CRL)]
1816 to_der,
1817 ffi::i2d_X509_CRL
1818 }
1819
1820 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
1822 unsafe {
1823 let revoked = X509_CRL_get_REVOKED(self.as_ptr());
1824 if revoked.is_null() {
1825 None
1826 } else {
1827 Some(StackRef::from_ptr(revoked))
1828 }
1829 }
1830 }
1831
1832 #[corresponds(X509_CRL_get0_lastUpdate)]
1834 pub fn last_update(&self) -> &Asn1TimeRef {
1835 unsafe {
1836 let date = X509_CRL_get0_lastUpdate(self.as_ptr());
1837 assert!(!date.is_null());
1838 Asn1TimeRef::from_ptr(date as *mut _)
1839 }
1840 }
1841
1842 #[corresponds(X509_CRL_get0_nextUpdate)]
1846 pub fn next_update(&self) -> Option<&Asn1TimeRef> {
1847 unsafe {
1848 let date = X509_CRL_get0_nextUpdate(self.as_ptr());
1849 Asn1TimeRef::from_const_ptr_opt(date)
1850 }
1851 }
1852
1853 #[corresponds(X509_CRL_get0_by_serial)]
1855 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
1856 unsafe {
1857 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1858 let status =
1859 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
1860 CrlStatus::from_ffi_status(status, ret)
1861 }
1862 }
1863
1864 #[corresponds(X509_CRL_get0_by_cert)]
1866 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
1867 unsafe {
1868 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1869 let status =
1870 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
1871 CrlStatus::from_ffi_status(status, ret)
1872 }
1873 }
1874
1875 #[corresponds(X509_CRL_get_issuer)]
1877 pub fn issuer_name(&self) -> &X509NameRef {
1878 unsafe {
1879 let name = X509_CRL_get_issuer(self.as_ptr());
1880 assert!(!name.is_null());
1881 X509NameRef::from_ptr(name)
1882 }
1883 }
1884
1885 #[corresponds(X509_CRL_verify)]
1892 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1893 where
1894 T: HasPublic,
1895 {
1896 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1897 }
1898
1899 #[corresponds(X509_CRL_get_ext_d2i)]
1903 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1904 let mut critical = -1;
1905 let out = unsafe {
1906 let ext = ffi::X509_CRL_get_ext_d2i(
1908 self.as_ptr(),
1909 T::NID.as_raw(),
1910 &mut critical as *mut _,
1911 ptr::null_mut(),
1912 );
1913 T::Output::from_ptr_opt(ext as *mut _)
1916 };
1917 match (critical, out) {
1918 (0, Some(out)) => Ok(Some((false, out))),
1919 (1, Some(out)) => Ok(Some((true, out))),
1920 (-1 | -2, _) => Ok(None),
1922 (0 | 1, None) => Err(ErrorStack::get()),
1925 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1926 }
1927 }
1928}
1929
1930#[derive(Copy, Clone, PartialEq, Eq)]
1932pub struct X509VerifyResult(c_int);
1933
1934impl fmt::Debug for X509VerifyResult {
1935 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1936 fmt.debug_struct("X509VerifyResult")
1937 .field("code", &self.0)
1938 .field("error", &self.error_string())
1939 .finish()
1940 }
1941}
1942
1943impl fmt::Display for X509VerifyResult {
1944 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1945 fmt.write_str(self.error_string())
1946 }
1947}
1948
1949impl Error for X509VerifyResult {}
1950
1951impl X509VerifyResult {
1952 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
1959 X509VerifyResult(err)
1960 }
1961
1962 #[allow(clippy::trivially_copy_pass_by_ref)]
1964 pub fn as_raw(&self) -> c_int {
1965 self.0
1966 }
1967
1968 #[corresponds(X509_verify_cert_error_string)]
1970 #[allow(clippy::trivially_copy_pass_by_ref)]
1971 pub fn error_string(&self) -> &'static str {
1972 ffi::init();
1973
1974 unsafe {
1975 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
1976 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1977 }
1978 }
1979
1980 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
1982 pub const APPLICATION_VERIFICATION: X509VerifyResult =
1984 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
1985}
1986
1987foreign_type_and_impl_send_sync! {
1988 type CType = ffi::GENERAL_NAME;
1989 fn drop = ffi::GENERAL_NAME_free;
1990
1991 pub struct GeneralName;
1993 pub struct GeneralNameRef;
1995}
1996
1997impl GeneralName {
1998 unsafe fn new(
1999 type_: c_int,
2000 asn1_type: Asn1Type,
2001 value: &[u8],
2002 ) -> Result<GeneralName, ErrorStack> {
2003 ffi::init();
2004 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2005 (*gn.as_ptr()).type_ = type_;
2006 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2007 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2008
2009 #[cfg(any(boringssl, awslc))]
2010 {
2011 (*gn.as_ptr()).d.ptr = s.cast();
2012 }
2013 #[cfg(not(any(boringssl, awslc)))]
2014 {
2015 (*gn.as_ptr()).d = s.cast();
2016 }
2017
2018 Ok(gn)
2019 }
2020
2021 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2022 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2023 }
2024
2025 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2026 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2027 }
2028
2029 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2030 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2031 }
2032
2033 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2034 match ip {
2035 IpAddr::V4(addr) => unsafe {
2036 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2037 },
2038 IpAddr::V6(addr) => unsafe {
2039 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2040 },
2041 }
2042 }
2043
2044 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2045 unsafe {
2046 ffi::init();
2047 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2048 (*gn).type_ = ffi::GEN_RID;
2049
2050 #[cfg(any(boringssl, awslc))]
2051 {
2052 (*gn).d.registeredID = oid.as_ptr();
2053 }
2054 #[cfg(not(any(boringssl, awslc)))]
2055 {
2056 (*gn).d = oid.as_ptr().cast();
2057 }
2058
2059 mem::forget(oid);
2060
2061 Ok(GeneralName::from_ptr(gn))
2062 }
2063 }
2064
2065 pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2066 unsafe {
2067 ffi::init();
2068
2069 let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2070 ptr::null_mut(),
2071 &mut value.as_ptr().cast(),
2072 value.len().try_into().unwrap(),
2073 ))?;
2074
2075 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2076 (*gn).type_ = ffi::GEN_OTHERNAME;
2077
2078 if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2079 gn,
2080 oid.as_ptr().cast(),
2081 typ,
2082 )) {
2083 ffi::GENERAL_NAME_free(gn);
2084 return Err(e);
2085 }
2086
2087 mem::forget(oid);
2088
2089 Ok(GeneralName::from_ptr(gn))
2090 }
2091 }
2092}
2093
2094impl GeneralNameRef {
2095 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2096 unsafe {
2097 if (*self.as_ptr()).type_ != ffi_type {
2098 return None;
2099 }
2100
2101 #[cfg(any(boringssl, awslc))]
2102 let d = (*self.as_ptr()).d.ptr;
2103 #[cfg(not(any(boringssl, awslc)))]
2104 let d = (*self.as_ptr()).d;
2105
2106 let ptr = ASN1_STRING_get0_data(d as *mut _);
2107 let len = ffi::ASN1_STRING_length(d as *mut _);
2108
2109 #[allow(clippy::unnecessary_cast)]
2110 let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2111 str::from_utf8(slice).ok()
2115 }
2116 }
2117
2118 pub fn email(&self) -> Option<&str> {
2120 self.ia5_string(ffi::GEN_EMAIL)
2121 }
2122
2123 pub fn directory_name(&self) -> Option<&X509NameRef> {
2125 unsafe {
2126 if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2127 return None;
2128 }
2129
2130 #[cfg(any(boringssl, awslc))]
2131 let d = (*self.as_ptr()).d.ptr;
2132 #[cfg(not(any(boringssl, awslc)))]
2133 let d = (*self.as_ptr()).d;
2134
2135 Some(X509NameRef::from_const_ptr(d as *const _))
2136 }
2137 }
2138
2139 pub fn dnsname(&self) -> Option<&str> {
2141 self.ia5_string(ffi::GEN_DNS)
2142 }
2143
2144 pub fn uri(&self) -> Option<&str> {
2146 self.ia5_string(ffi::GEN_URI)
2147 }
2148
2149 pub fn ipaddress(&self) -> Option<&[u8]> {
2151 unsafe {
2152 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2153 return None;
2154 }
2155 #[cfg(any(boringssl, awslc))]
2156 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2157 #[cfg(not(any(boringssl, awslc)))]
2158 let d = (*self.as_ptr()).d;
2159
2160 let ptr = ASN1_STRING_get0_data(d as *mut _);
2161 let len = ffi::ASN1_STRING_length(d as *mut _);
2162
2163 #[allow(clippy::unnecessary_cast)]
2164 Some(util::from_raw_parts(ptr as *const u8, len as usize))
2165 }
2166 }
2167}
2168
2169impl fmt::Debug for GeneralNameRef {
2170 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2171 if let Some(email) = self.email() {
2172 formatter.write_str(email)
2173 } else if let Some(dnsname) = self.dnsname() {
2174 formatter.write_str(dnsname)
2175 } else if let Some(uri) = self.uri() {
2176 formatter.write_str(uri)
2177 } else if let Some(ipaddress) = self.ipaddress() {
2178 let address = <[u8; 16]>::try_from(ipaddress)
2179 .map(IpAddr::from)
2180 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2181 match address {
2182 Ok(a) => fmt::Debug::fmt(&a, formatter),
2183 Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2184 }
2185 } else {
2186 formatter.write_str("(empty)")
2187 }
2188 }
2189}
2190
2191impl Stackable for GeneralName {
2192 type StackType = ffi::stack_st_GENERAL_NAME;
2193}
2194
2195foreign_type_and_impl_send_sync! {
2196 type CType = ffi::DIST_POINT;
2197 fn drop = ffi::DIST_POINT_free;
2198
2199 pub struct DistPoint;
2201 pub struct DistPointRef;
2203}
2204
2205impl DistPointRef {
2206 pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2208 unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2209 }
2210}
2211
2212foreign_type_and_impl_send_sync! {
2213 type CType = ffi::DIST_POINT_NAME;
2214 fn drop = ffi::DIST_POINT_NAME_free;
2215
2216 pub struct DistPointName;
2218 pub struct DistPointNameRef;
2220}
2221
2222impl DistPointNameRef {
2223 pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2225 unsafe {
2226 if (*self.as_ptr()).type_ != 0 {
2227 return None;
2228 }
2229 StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2230 }
2231 }
2232}
2233
2234impl Stackable for DistPoint {
2235 type StackType = ffi::stack_st_DIST_POINT;
2236}
2237
2238foreign_type_and_impl_send_sync! {
2239 type CType = ffi::ACCESS_DESCRIPTION;
2240 fn drop = ffi::ACCESS_DESCRIPTION_free;
2241
2242 pub struct AccessDescription;
2244 pub struct AccessDescriptionRef;
2246}
2247
2248impl AccessDescriptionRef {
2249 pub fn method(&self) -> &Asn1ObjectRef {
2251 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2252 }
2253
2254 pub fn location(&self) -> &GeneralNameRef {
2256 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2257 }
2258}
2259
2260impl Stackable for AccessDescription {
2261 type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2262}
2263
2264foreign_type_and_impl_send_sync! {
2265 type CType = ffi::X509_ALGOR;
2266 fn drop = ffi::X509_ALGOR_free;
2267
2268 pub struct X509Algorithm;
2270 pub struct X509AlgorithmRef;
2272}
2273
2274impl X509AlgorithmRef {
2275 pub fn object(&self) -> &Asn1ObjectRef {
2277 unsafe {
2278 let mut oid = ptr::null();
2279 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2280 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2281 }
2282 }
2283}
2284
2285foreign_type_and_impl_send_sync! {
2286 type CType = ffi::X509_OBJECT;
2287 fn drop = X509_OBJECT_free;
2288
2289 pub struct X509Object;
2291 pub struct X509ObjectRef;
2293}
2294
2295impl X509ObjectRef {
2296 pub fn x509(&self) -> Option<&X509Ref> {
2297 unsafe {
2298 let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2299 X509Ref::from_const_ptr_opt(ptr)
2300 }
2301 }
2302}
2303
2304impl Stackable for X509Object {
2305 type StackType = ffi::stack_st_X509_OBJECT;
2306}
2307
2308cfg_if! {
2309 if #[cfg(any(boringssl, ossl110, libressl273, awslc))] {
2310 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2311 } else {
2312 #[allow(bad_style)]
2313 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2314 (*(*(*x).cert_info).validity).notAfter
2315 }
2316
2317 #[allow(bad_style)]
2318 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2319 (*(*(*x).cert_info).validity).notBefore
2320 }
2321
2322 #[allow(bad_style)]
2323 unsafe fn X509_up_ref(x: *mut ffi::X509) {
2324 ffi::CRYPTO_add_lock(
2325 &mut (*x).references,
2326 1,
2327 ffi::CRYPTO_LOCK_X509,
2328 "mod.rs\0".as_ptr() as *const _,
2329 line!() as c_int,
2330 );
2331 }
2332
2333 #[allow(bad_style)]
2334 unsafe fn X509_get0_signature(
2335 psig: *mut *const ffi::ASN1_BIT_STRING,
2336 palg: *mut *const ffi::X509_ALGOR,
2337 x: *const ffi::X509,
2338 ) {
2339 if !psig.is_null() {
2340 *psig = (*x).signature;
2341 }
2342 if !palg.is_null() {
2343 *palg = (*x).sig_alg;
2344 }
2345 }
2346 }
2347}
2348
2349cfg_if! {
2350 if #[cfg(any(boringssl, ossl110, libressl350, awslc))] {
2351 use ffi::{
2352 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2353 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2354 };
2355 } else {
2356 use ffi::{
2357 ASN1_STRING_data as ASN1_STRING_get0_data,
2358 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2359 X509_set_notAfter as X509_set1_notAfter,
2360 X509_set_notBefore as X509_set1_notBefore,
2361 };
2362
2363 #[allow(bad_style)]
2364 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2365 ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2366 }
2367
2368 #[allow(bad_style)]
2369 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2370 (*(*x).req_info).subject
2371 }
2372
2373 #[allow(bad_style)]
2374 unsafe fn X509_ALGOR_get0(
2375 paobj: *mut *const ffi::ASN1_OBJECT,
2376 pptype: *mut c_int,
2377 pval: *mut *mut ::libc::c_void,
2378 alg: *const ffi::X509_ALGOR,
2379 ) {
2380 if !paobj.is_null() {
2381 *paobj = (*alg).algorithm;
2382 }
2383 assert!(pptype.is_null());
2384 assert!(pval.is_null());
2385 }
2386 }
2387}
2388
2389cfg_if! {
2390 if #[cfg(any(ossl110, boringssl, libressl270, awslc))] {
2391 use ffi::X509_OBJECT_get0_X509;
2392 } else {
2393 #[allow(bad_style)]
2394 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2395 if (*x).type_ == ffi::X509_LU_X509 {
2396 (*x).data.x509
2397 } else {
2398 ptr::null_mut()
2399 }
2400 }
2401 }
2402}
2403
2404cfg_if! {
2405 if #[cfg(any(ossl110, libressl350, boringssl, awslc))] {
2406 use ffi::X509_OBJECT_free;
2407 } else {
2408 #[allow(bad_style)]
2409 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2410 ffi::X509_OBJECT_free_contents(x);
2411 ffi::CRYPTO_free(x as *mut libc::c_void);
2412 }
2413 }
2414}
2415
2416cfg_if! {
2417 if #[cfg(any(ossl110, libressl350, boringssl, awslc))] {
2418 use ffi::{
2419 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2420 X509_CRL_get_REVOKED,
2421 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2422 };
2423 } else {
2424 #[allow(bad_style)]
2425 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2426 (*(*x).crl).lastUpdate
2427 }
2428 #[allow(bad_style)]
2429 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2430 (*(*x).crl).nextUpdate
2431 }
2432 #[allow(bad_style)]
2433 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2434 (*(*x).crl).issuer
2435 }
2436 #[allow(bad_style)]
2437 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2438 (*(*x).crl).revoked
2439 }
2440 #[allow(bad_style)]
2441 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2442 (*x).serialNumber
2443 }
2444 #[allow(bad_style)]
2445 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2446 (*x).revocationDate
2447 }
2448 }
2449}
2450
2451#[derive(Copy, Clone, PartialEq, Eq)]
2452pub struct X509PurposeId(c_int);
2453
2454impl X509PurposeId {
2455 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2456 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2457 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2458 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2459 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2460 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2461 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2462 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2463 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2464 #[cfg(ossl320)]
2465 pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2466
2467 pub fn from_raw(id: c_int) -> Self {
2469 X509PurposeId(id)
2470 }
2471
2472 pub fn as_raw(&self) -> c_int {
2474 self.0
2475 }
2476}
2477
2478pub struct X509PurposeRef(Opaque);
2480
2481impl ForeignTypeRef for X509PurposeRef {
2483 type CType = ffi::X509_PURPOSE;
2484}
2485
2486impl X509PurposeRef {
2487 #[allow(clippy::unnecessary_cast)]
2501 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2502 unsafe {
2503 let sname = CString::new(sname).unwrap();
2504 cfg_if! {
2505 if #[cfg(any(ossl110, libressl280, boringssl, awslc))] {
2506 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2507 } else {
2508 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2509 }
2510 }
2511 Ok(purpose)
2512 }
2513 }
2514 #[corresponds(X509_PURPOSE_get0)]
2517 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2518 unsafe {
2519 let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2520 Ok(X509PurposeRef::from_const_ptr(ptr))
2521 }
2522 }
2523
2524 pub fn purpose(&self) -> X509PurposeId {
2535 unsafe {
2536 cfg_if! {
2537 if #[cfg(any(ossl110, libressl280, boringssl, awslc))] {
2538 let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2539 } else {
2540 let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2541 }
2542 }
2543 X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2544 }
2545 }
2546}