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