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 #[cfg(any(boringssl, ossl110, libressl, awslc))]
1349 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1350 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1351 }
1352
1353 to_der! {
1354 to_der,
1360 ffi::i2d_X509_NAME
1361 }
1362
1363 digest! {
1364 digest,
1370 ffi::X509_NAME_digest
1371 }
1372}
1373
1374impl fmt::Debug for X509NameRef {
1375 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1376 formatter.debug_list().entries(self.entries()).finish()
1377 }
1378}
1379
1380pub struct X509NameEntries<'a> {
1382 name: &'a X509NameRef,
1383 nid: Option<Nid>,
1384 loc: c_int,
1385}
1386
1387impl<'a> Iterator for X509NameEntries<'a> {
1388 type Item = &'a X509NameEntryRef;
1389
1390 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1391 unsafe {
1392 match self.nid {
1393 Some(nid) => {
1394 self.loc =
1396 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1397 if self.loc == -1 {
1398 return None;
1399 }
1400 }
1401 None => {
1402 self.loc += 1;
1404 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1405 return None;
1406 }
1407 }
1408 }
1409
1410 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1411
1412 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1413 }
1414 }
1415}
1416
1417foreign_type_and_impl_send_sync! {
1418 type CType = ffi::X509_NAME_ENTRY;
1419 fn drop = ffi::X509_NAME_ENTRY_free;
1420
1421 pub struct X509NameEntry;
1423 pub struct X509NameEntryRef;
1425}
1426
1427impl X509NameEntryRef {
1428 #[corresponds(X509_NAME_ENTRY_get_data)]
1430 pub fn data(&self) -> &Asn1StringRef {
1431 unsafe {
1432 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1433 Asn1StringRef::from_ptr(data)
1434 }
1435 }
1436
1437 #[corresponds(X509_NAME_ENTRY_get_object)]
1440 pub fn object(&self) -> &Asn1ObjectRef {
1441 unsafe {
1442 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1443 Asn1ObjectRef::from_ptr(object)
1444 }
1445 }
1446}
1447
1448impl fmt::Debug for X509NameEntryRef {
1449 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1450 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1451 }
1452}
1453
1454foreign_type_and_impl_send_sync! {
1455 type CType = ffi::X509_PUBKEY;
1456 fn drop = ffi::X509_PUBKEY_free;
1457
1458 pub struct X509Pubkey;
1460 pub struct X509PubkeyRef;
1462}
1463
1464impl X509Pubkey {
1465 from_der! {
1466 from_der,
1472 X509Pubkey,
1473 ffi::d2i_X509_PUBKEY
1474 }
1475
1476 pub fn from_pubkey<T>(key: &PKeyRef<T>) -> Result<Self, ErrorStack>
1482 where
1483 T: HasPublic,
1484 {
1485 let mut p = ptr::null_mut();
1486 unsafe {
1487 cvt(ffi::X509_PUBKEY_set(&mut p as *mut _, key.as_ptr()))?;
1488 }
1489 Ok(X509Pubkey(p))
1490 }
1491}
1492
1493impl X509PubkeyRef {
1494 #[corresponds(X509_PUBKEY_dup)]
1496 #[cfg(ossl300)]
1497 pub fn to_owned(&self) -> Result<X509Pubkey, ErrorStack> {
1498 unsafe { cvt_p(ffi::X509_PUBKEY_dup(self.as_ptr())).map(|n| X509Pubkey::from_ptr(n)) }
1499 }
1500
1501 to_der! {
1502 to_der,
1508 ffi::i2d_X509_PUBKEY
1509 }
1510
1511 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1517 unsafe {
1518 let key = cvt_p(ffi::X509_PUBKEY_get(self.as_ptr()))?;
1519 Ok(PKey::from_ptr(key))
1520 }
1521 }
1522
1523 pub fn encoded_bytes(&self) -> Result<&[u8], ErrorStack> {
1529 unsafe {
1530 let mut pk = ptr::null_mut() as *const c_uchar;
1531 let mut pkt_len: c_int = 0;
1532 cvt(ffi::X509_PUBKEY_get0_param(
1533 ptr::null_mut(),
1534 &mut pk as *mut _,
1535 &mut pkt_len as *mut _,
1536 ptr::null_mut(),
1537 self.as_ptr(),
1538 ))?;
1539
1540 Ok(util::from_raw_parts(pk, pkt_len as usize))
1541 }
1542 }
1543}
1544
1545pub struct X509ReqBuilder(X509Req);
1547
1548impl X509ReqBuilder {
1549 #[corresponds(X509_REQ_new)]
1551 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1552 unsafe {
1553 ffi::init();
1554 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1555 }
1556 }
1557
1558 #[corresponds(X509_REQ_set_version)]
1560 #[allow(clippy::useless_conversion)]
1561 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1562 unsafe {
1563 cvt(ffi::X509_REQ_set_version(
1564 self.0.as_ptr(),
1565 version as c_long,
1566 ))
1567 .map(|_| ())
1568 }
1569 }
1570
1571 #[corresponds(X509_REQ_set_subject_name)]
1573 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1574 unsafe {
1575 cvt(ffi::X509_REQ_set_subject_name(
1576 self.0.as_ptr(),
1577 subject_name.as_ptr(),
1578 ))
1579 .map(|_| ())
1580 }
1581 }
1582
1583 #[corresponds(X509_REQ_set_pubkey)]
1585 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1586 where
1587 T: HasPublic,
1588 {
1589 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1590 }
1591
1592 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1595 unsafe {
1596 let mut ctx = mem::zeroed();
1597
1598 ffi::X509V3_set_ctx(
1599 &mut ctx,
1600 ptr::null_mut(),
1601 ptr::null_mut(),
1602 self.0.as_ptr(),
1603 ptr::null_mut(),
1604 0,
1605 );
1606
1607 if let Some(conf) = conf {
1609 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1610 }
1611
1612 X509v3Context(ctx, PhantomData)
1613 }
1614 }
1615
1616 pub fn add_extensions(
1618 &mut self,
1619 extensions: &StackRef<X509Extension>,
1620 ) -> Result<(), ErrorStack> {
1621 unsafe {
1622 cvt(ffi::X509_REQ_add_extensions(
1623 self.0.as_ptr(),
1624 extensions.as_ptr(),
1625 ))
1626 .map(|_| ())
1627 }
1628 }
1629
1630 #[corresponds(X509_REQ_sign)]
1632 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1633 where
1634 T: HasPrivate,
1635 {
1636 unsafe {
1637 cvt(ffi::X509_REQ_sign(
1638 self.0.as_ptr(),
1639 key.as_ptr(),
1640 hash.as_ptr(),
1641 ))
1642 .map(|_| ())
1643 }
1644 }
1645
1646 pub fn build(self) -> X509Req {
1648 self.0
1649 }
1650}
1651
1652foreign_type_and_impl_send_sync! {
1653 type CType = ffi::X509_REQ;
1654 fn drop = ffi::X509_REQ_free;
1655
1656 pub struct X509Req;
1658 pub struct X509ReqRef;
1660}
1661
1662impl X509Req {
1663 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1665 X509ReqBuilder::new()
1666 }
1667
1668 from_pem! {
1669 from_pem,
1677 X509Req,
1678 ffi::PEM_read_bio_X509_REQ
1679 }
1680
1681 from_der! {
1682 from_der,
1688 X509Req,
1689 ffi::d2i_X509_REQ
1690 }
1691}
1692
1693impl X509ReqRef {
1694 to_pem! {
1695 to_pem,
1703 ffi::PEM_write_bio_X509_REQ
1704 }
1705
1706 to_der! {
1707 to_der,
1713 ffi::i2d_X509_REQ
1714 }
1715
1716 to_pem! {
1717 #[corresponds(X509_Req_print)]
1719 to_text,
1720 ffi::X509_REQ_print
1721 }
1722
1723 digest! {
1724 digest,
1730 ffi::X509_REQ_digest
1731 }
1732
1733 #[corresponds(X509_REQ_get_version)]
1735 #[allow(clippy::unnecessary_cast)]
1736 pub fn version(&self) -> i32 {
1737 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1738 }
1739
1740 #[corresponds(X509_REQ_get_subject_name)]
1742 pub fn subject_name(&self) -> &X509NameRef {
1743 unsafe {
1744 let name = X509_REQ_get_subject_name(self.as_ptr());
1745 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1746 }
1747 }
1748
1749 #[corresponds(X509_REQ_get_pubkey)]
1751 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1752 unsafe {
1753 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1754 Ok(PKey::from_ptr(key))
1755 }
1756 }
1757
1758 #[cfg(ossl110)]
1764 pub fn x509_pubkey(&self) -> Result<&X509PubkeyRef, ErrorStack> {
1765 unsafe {
1766 let key = cvt_p(ffi::X509_REQ_get_X509_PUBKEY(self.as_ptr()))?;
1767 Ok(X509PubkeyRef::from_ptr(key))
1768 }
1769 }
1770
1771 #[corresponds(X509_REQ_verify)]
1775 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1776 where
1777 T: HasPublic,
1778 {
1779 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1780 }
1781
1782 #[corresponds(X509_REQ_get_extensions)]
1784 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1785 unsafe {
1786 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1787 Ok(Stack::from_ptr(extensions))
1788 }
1789 }
1790}
1791
1792#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1794pub struct CrlReason(c_int);
1795
1796#[allow(missing_docs)] impl CrlReason {
1798 pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1799 pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1800 pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1801 pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1802 pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1803 pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1804 pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1805 pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1806 pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1807 pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1808
1809 pub const fn from_raw(value: c_int) -> Self {
1811 CrlReason(value)
1812 }
1813
1814 pub const fn as_raw(&self) -> c_int {
1816 self.0
1817 }
1818}
1819
1820foreign_type_and_impl_send_sync! {
1821 type CType = ffi::X509_REVOKED;
1822 fn drop = ffi::X509_REVOKED_free;
1823
1824 pub struct X509Revoked;
1826 pub struct X509RevokedRef;
1828}
1829
1830impl Stackable for X509Revoked {
1831 type StackType = ffi::stack_st_X509_REVOKED;
1832}
1833
1834impl X509Revoked {
1835 from_der! {
1836 #[corresponds(d2i_X509_REVOKED)]
1838 from_der,
1839 X509Revoked,
1840 ffi::d2i_X509_REVOKED
1841 }
1842}
1843
1844impl X509RevokedRef {
1845 to_der! {
1846 #[corresponds(d2i_X509_REVOKED)]
1848 to_der,
1849 ffi::i2d_X509_REVOKED
1850 }
1851
1852 #[corresponds(X509_NAME_dup)]
1854 #[cfg(any(boringssl, ossl110, libressl, awslc))]
1855 pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1856 unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1857 }
1858
1859 #[corresponds(X509_REVOKED_get0_revocationDate)]
1861 pub fn revocation_date(&self) -> &Asn1TimeRef {
1862 unsafe {
1863 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1864 assert!(!r.is_null());
1865 Asn1TimeRef::from_ptr(r as *mut _)
1866 }
1867 }
1868
1869 #[corresponds(X509_REVOKED_get0_serialNumber)]
1871 pub fn serial_number(&self) -> &Asn1IntegerRef {
1872 unsafe {
1873 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1874 assert!(!r.is_null());
1875 Asn1IntegerRef::from_ptr(r as *mut _)
1876 }
1877 }
1878
1879 #[corresponds(X509_REVOKED_get_ext_d2i)]
1883 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1884 let mut critical = -1;
1885 let out = unsafe {
1886 let ext = ffi::X509_REVOKED_get_ext_d2i(
1888 self.as_ptr(),
1889 T::NID.as_raw(),
1890 &mut critical as *mut _,
1891 ptr::null_mut(),
1892 );
1893 T::Output::from_ptr_opt(ext as *mut _)
1896 };
1897 match (critical, out) {
1898 (0, Some(out)) => Ok(Some((false, out))),
1899 (1, Some(out)) => Ok(Some((true, out))),
1900 (-1 | -2, _) => Ok(None),
1902 (0 | 1, None) => Err(ErrorStack::get()),
1905 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1906 }
1907 }
1908}
1909
1910pub enum ReasonCode {}
1913
1914unsafe impl ExtensionType for ReasonCode {
1917 const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1918
1919 type Output = Asn1Enumerated;
1920}
1921
1922pub enum CertificateIssuer {}
1925
1926unsafe impl ExtensionType for CertificateIssuer {
1929 const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1930
1931 type Output = Stack<GeneralName>;
1932}
1933
1934pub enum AuthorityInformationAccess {}
1936
1937unsafe impl ExtensionType for AuthorityInformationAccess {
1940 const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1941
1942 type Output = Stack<AccessDescription>;
1943}
1944
1945foreign_type_and_impl_send_sync! {
1946 type CType = ffi::X509_CRL;
1947 fn drop = ffi::X509_CRL_free;
1948
1949 pub struct X509Crl;
1951 pub struct X509CrlRef;
1953}
1954
1955pub enum CrlStatus<'a> {
1961 NotRevoked,
1963 Revoked(&'a X509RevokedRef),
1965 RemoveFromCrl(&'a X509RevokedRef),
1970}
1971
1972impl<'a> CrlStatus<'a> {
1973 unsafe fn from_ffi_status(
1978 status: c_int,
1979 revoked_entry: *mut ffi::X509_REVOKED,
1980 ) -> CrlStatus<'a> {
1981 match status {
1982 0 => CrlStatus::NotRevoked,
1983 1 => {
1984 assert!(!revoked_entry.is_null());
1985 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1986 }
1987 2 => {
1988 assert!(!revoked_entry.is_null());
1989 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1990 }
1991 _ => unreachable!(
1992 "{}",
1993 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1994 ),
1995 }
1996 }
1997}
1998
1999impl X509Crl {
2000 from_pem! {
2001 #[corresponds(PEM_read_bio_X509_CRL)]
2005 from_pem,
2006 X509Crl,
2007 ffi::PEM_read_bio_X509_CRL
2008 }
2009
2010 from_der! {
2011 #[corresponds(d2i_X509_CRL)]
2013 from_der,
2014 X509Crl,
2015 ffi::d2i_X509_CRL
2016 }
2017}
2018
2019impl X509CrlRef {
2020 to_pem! {
2021 #[corresponds(PEM_write_bio_X509_CRL)]
2025 to_pem,
2026 ffi::PEM_write_bio_X509_CRL
2027 }
2028
2029 to_der! {
2030 #[corresponds(i2d_X509_CRL)]
2032 to_der,
2033 ffi::i2d_X509_CRL
2034 }
2035
2036 digest! {
2037 digest,
2043 ffi::X509_CRL_digest
2044 }
2045
2046 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
2048 unsafe {
2049 let revoked = X509_CRL_get_REVOKED(self.as_ptr());
2050 if revoked.is_null() {
2051 None
2052 } else {
2053 Some(StackRef::from_ptr(revoked))
2054 }
2055 }
2056 }
2057
2058 #[corresponds(X509_CRL_get0_lastUpdate)]
2060 pub fn last_update(&self) -> &Asn1TimeRef {
2061 unsafe {
2062 let date = X509_CRL_get0_lastUpdate(self.as_ptr());
2063 assert!(!date.is_null());
2064 Asn1TimeRef::from_ptr(date as *mut _)
2065 }
2066 }
2067
2068 #[corresponds(X509_CRL_get0_nextUpdate)]
2072 pub fn next_update(&self) -> Option<&Asn1TimeRef> {
2073 unsafe {
2074 let date = X509_CRL_get0_nextUpdate(self.as_ptr());
2075 Asn1TimeRef::from_const_ptr_opt(date)
2076 }
2077 }
2078
2079 #[corresponds(X509_CRL_get0_by_serial)]
2081 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
2082 unsafe {
2083 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2084 let status =
2085 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
2086 CrlStatus::from_ffi_status(status, ret)
2087 }
2088 }
2089
2090 #[corresponds(X509_CRL_get0_by_cert)]
2092 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
2093 unsafe {
2094 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
2095 let status =
2096 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
2097 CrlStatus::from_ffi_status(status, ret)
2098 }
2099 }
2100
2101 #[corresponds(X509_CRL_get_issuer)]
2103 pub fn issuer_name(&self) -> &X509NameRef {
2104 unsafe {
2105 let name = X509_CRL_get_issuer(self.as_ptr());
2106 assert!(!name.is_null());
2107 X509NameRef::from_ptr(name)
2108 }
2109 }
2110
2111 #[corresponds(X509_CRL_verify)]
2118 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
2119 where
2120 T: HasPublic,
2121 {
2122 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
2123 }
2124
2125 #[corresponds(X509_CRL_get_ext_d2i)]
2129 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
2130 let mut critical = -1;
2131 let out = unsafe {
2132 let ext = ffi::X509_CRL_get_ext_d2i(
2134 self.as_ptr(),
2135 T::NID.as_raw(),
2136 &mut critical as *mut _,
2137 ptr::null_mut(),
2138 );
2139 T::Output::from_ptr_opt(ext as *mut _)
2142 };
2143 match (critical, out) {
2144 (0, Some(out)) => Ok(Some((false, out))),
2145 (1, Some(out)) => Ok(Some((true, out))),
2146 (-1 | -2, _) => Ok(None),
2148 (0 | 1, None) => Err(ErrorStack::get()),
2151 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
2152 }
2153 }
2154}
2155
2156#[derive(Copy, Clone, PartialEq, Eq)]
2158pub struct X509VerifyResult(c_int);
2159
2160impl fmt::Debug for X509VerifyResult {
2161 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2162 fmt.debug_struct("X509VerifyResult")
2163 .field("code", &self.0)
2164 .field("error", &self.error_string())
2165 .finish()
2166 }
2167}
2168
2169impl fmt::Display for X509VerifyResult {
2170 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2171 fmt.write_str(self.error_string())
2172 }
2173}
2174
2175impl Error for X509VerifyResult {}
2176
2177impl X509VerifyResult {
2178 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
2185 X509VerifyResult(err)
2186 }
2187
2188 #[allow(clippy::trivially_copy_pass_by_ref)]
2190 pub fn as_raw(&self) -> c_int {
2191 self.0
2192 }
2193
2194 #[corresponds(X509_verify_cert_error_string)]
2196 #[allow(clippy::trivially_copy_pass_by_ref)]
2197 pub fn error_string(&self) -> &'static str {
2198 ffi::init();
2199
2200 unsafe {
2201 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
2202 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
2203 }
2204 }
2205
2206 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
2208 pub const APPLICATION_VERIFICATION: X509VerifyResult =
2210 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
2211}
2212
2213foreign_type_and_impl_send_sync! {
2214 type CType = ffi::GENERAL_NAME;
2215 fn drop = ffi::GENERAL_NAME_free;
2216
2217 pub struct GeneralName;
2219 pub struct GeneralNameRef;
2221}
2222
2223impl GeneralName {
2224 unsafe fn new(
2225 type_: c_int,
2226 asn1_type: Asn1Type,
2227 value: &[u8],
2228 ) -> Result<GeneralName, ErrorStack> {
2229 ffi::init();
2230 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2231 (*gn.as_ptr()).type_ = type_;
2232 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2233 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2234
2235 #[cfg(any(boringssl, awslc))]
2236 {
2237 (*gn.as_ptr()).d.ptr = s.cast();
2238 }
2239 #[cfg(not(any(boringssl, awslc)))]
2240 {
2241 (*gn.as_ptr()).d = s.cast();
2242 }
2243
2244 Ok(gn)
2245 }
2246
2247 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2248 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2249 }
2250
2251 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2252 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2253 }
2254
2255 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2256 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2257 }
2258
2259 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2260 match ip {
2261 IpAddr::V4(addr) => unsafe {
2262 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2263 },
2264 IpAddr::V6(addr) => unsafe {
2265 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2266 },
2267 }
2268 }
2269
2270 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2271 unsafe {
2272 ffi::init();
2273 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2274 (*gn).type_ = ffi::GEN_RID;
2275
2276 #[cfg(any(boringssl, awslc))]
2277 {
2278 (*gn).d.registeredID = oid.as_ptr();
2279 }
2280 #[cfg(not(any(boringssl, awslc)))]
2281 {
2282 (*gn).d = oid.as_ptr().cast();
2283 }
2284
2285 mem::forget(oid);
2286
2287 Ok(GeneralName::from_ptr(gn))
2288 }
2289 }
2290
2291 pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2292 unsafe {
2293 ffi::init();
2294
2295 let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2296 ptr::null_mut(),
2297 &mut value.as_ptr().cast(),
2298 value.len().try_into().unwrap(),
2299 ))?;
2300
2301 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2302 (*gn).type_ = ffi::GEN_OTHERNAME;
2303
2304 if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2305 gn,
2306 oid.as_ptr().cast(),
2307 typ,
2308 )) {
2309 ffi::GENERAL_NAME_free(gn);
2310 return Err(e);
2311 }
2312
2313 mem::forget(oid);
2314
2315 Ok(GeneralName::from_ptr(gn))
2316 }
2317 }
2318}
2319
2320impl GeneralNameRef {
2321 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2322 unsafe {
2323 if (*self.as_ptr()).type_ != ffi_type {
2324 return None;
2325 }
2326
2327 #[cfg(any(boringssl, awslc))]
2328 let d = (*self.as_ptr()).d.ptr;
2329 #[cfg(not(any(boringssl, awslc)))]
2330 let d = (*self.as_ptr()).d;
2331
2332 let ptr = ASN1_STRING_get0_data(d as *mut _);
2333 let len = ffi::ASN1_STRING_length(d as *mut _);
2334
2335 #[allow(clippy::unnecessary_cast)]
2336 let slice = util::from_raw_parts(ptr as *const u8, len as usize);
2337 str::from_utf8(slice).ok()
2341 }
2342 }
2343
2344 pub fn email(&self) -> Option<&str> {
2346 self.ia5_string(ffi::GEN_EMAIL)
2347 }
2348
2349 pub fn directory_name(&self) -> Option<&X509NameRef> {
2351 unsafe {
2352 if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2353 return None;
2354 }
2355
2356 #[cfg(any(boringssl, awslc))]
2357 let d = (*self.as_ptr()).d.ptr;
2358 #[cfg(not(any(boringssl, awslc)))]
2359 let d = (*self.as_ptr()).d;
2360
2361 Some(X509NameRef::from_const_ptr(d as *const _))
2362 }
2363 }
2364
2365 pub fn dnsname(&self) -> Option<&str> {
2367 self.ia5_string(ffi::GEN_DNS)
2368 }
2369
2370 pub fn uri(&self) -> Option<&str> {
2372 self.ia5_string(ffi::GEN_URI)
2373 }
2374
2375 pub fn ipaddress(&self) -> Option<&[u8]> {
2377 unsafe {
2378 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2379 return None;
2380 }
2381 #[cfg(any(boringssl, awslc))]
2382 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2383 #[cfg(not(any(boringssl, awslc)))]
2384 let d = (*self.as_ptr()).d;
2385
2386 let ptr = ASN1_STRING_get0_data(d as *mut _);
2387 let len = ffi::ASN1_STRING_length(d as *mut _);
2388
2389 #[allow(clippy::unnecessary_cast)]
2390 Some(util::from_raw_parts(ptr as *const u8, len as usize))
2391 }
2392 }
2393}
2394
2395impl fmt::Debug for GeneralNameRef {
2396 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2397 if let Some(email) = self.email() {
2398 formatter.write_str(email)
2399 } else if let Some(dnsname) = self.dnsname() {
2400 formatter.write_str(dnsname)
2401 } else if let Some(uri) = self.uri() {
2402 formatter.write_str(uri)
2403 } else if let Some(ipaddress) = self.ipaddress() {
2404 let address = <[u8; 16]>::try_from(ipaddress)
2405 .map(IpAddr::from)
2406 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from));
2407 match address {
2408 Ok(a) => fmt::Debug::fmt(&a, formatter),
2409 Err(_) => fmt::Debug::fmt(ipaddress, formatter),
2410 }
2411 } else {
2412 formatter.write_str("(empty)")
2413 }
2414 }
2415}
2416
2417impl Stackable for GeneralName {
2418 type StackType = ffi::stack_st_GENERAL_NAME;
2419}
2420
2421foreign_type_and_impl_send_sync! {
2422 type CType = ffi::DIST_POINT;
2423 fn drop = ffi::DIST_POINT_free;
2424
2425 pub struct DistPoint;
2427 pub struct DistPointRef;
2429}
2430
2431impl DistPointRef {
2432 pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2434 unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2435 }
2436}
2437
2438foreign_type_and_impl_send_sync! {
2439 type CType = ffi::DIST_POINT_NAME;
2440 fn drop = ffi::DIST_POINT_NAME_free;
2441
2442 pub struct DistPointName;
2444 pub struct DistPointNameRef;
2446}
2447
2448impl DistPointNameRef {
2449 pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2451 unsafe {
2452 if (*self.as_ptr()).type_ != 0 {
2453 return None;
2454 }
2455 StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2456 }
2457 }
2458}
2459
2460impl Stackable for DistPoint {
2461 type StackType = ffi::stack_st_DIST_POINT;
2462}
2463
2464foreign_type_and_impl_send_sync! {
2465 type CType = ffi::BASIC_CONSTRAINTS;
2466 fn drop = ffi::BASIC_CONSTRAINTS_free;
2467
2468 pub struct BasicConstraints;
2470 pub struct BasicConstraintsRef;
2472}
2473
2474impl BasicConstraintsRef {
2475 pub fn ca(&self) -> bool {
2476 unsafe { (*(self.as_ptr())).ca != 0 }
2477 }
2478
2479 pub fn pathlen(&self) -> Option<&Asn1IntegerRef> {
2480 if !self.ca() {
2481 return None;
2482 }
2483 unsafe {
2484 let data = (*(self.as_ptr())).pathlen;
2485 Asn1IntegerRef::from_const_ptr_opt(data as _)
2486 }
2487 }
2488}
2489
2490foreign_type_and_impl_send_sync! {
2491 type CType = ffi::ACCESS_DESCRIPTION;
2492 fn drop = ffi::ACCESS_DESCRIPTION_free;
2493
2494 pub struct AccessDescription;
2496 pub struct AccessDescriptionRef;
2498}
2499
2500impl AccessDescriptionRef {
2501 pub fn method(&self) -> &Asn1ObjectRef {
2503 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2504 }
2505
2506 pub fn location(&self) -> &GeneralNameRef {
2508 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2509 }
2510}
2511
2512impl Stackable for AccessDescription {
2513 type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2514}
2515
2516foreign_type_and_impl_send_sync! {
2517 type CType = ffi::X509_ALGOR;
2518 fn drop = ffi::X509_ALGOR_free;
2519
2520 pub struct X509Algorithm;
2522 pub struct X509AlgorithmRef;
2524}
2525
2526impl X509AlgorithmRef {
2527 pub fn object(&self) -> &Asn1ObjectRef {
2529 unsafe {
2530 let mut oid = ptr::null();
2531 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
2532 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null")
2533 }
2534 }
2535}
2536
2537foreign_type_and_impl_send_sync! {
2538 type CType = ffi::X509_OBJECT;
2539 fn drop = X509_OBJECT_free;
2540
2541 pub struct X509Object;
2543 pub struct X509ObjectRef;
2545}
2546
2547impl X509ObjectRef {
2548 pub fn x509(&self) -> Option<&X509Ref> {
2549 unsafe {
2550 let ptr = X509_OBJECT_get0_X509(self.as_ptr());
2551 X509Ref::from_const_ptr_opt(ptr)
2552 }
2553 }
2554}
2555
2556impl Stackable for X509Object {
2557 type StackType = ffi::stack_st_X509_OBJECT;
2558}
2559
2560cfg_if! {
2561 if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2562 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2563 } else {
2564 #[allow(bad_style)]
2565 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2566 (*(*(*x).cert_info).validity).notAfter
2567 }
2568
2569 #[allow(bad_style)]
2570 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2571 (*(*(*x).cert_info).validity).notBefore
2572 }
2573
2574 #[allow(bad_style)]
2575 unsafe fn X509_up_ref(x: *mut ffi::X509) {
2576 ffi::CRYPTO_add_lock(
2577 &mut (*x).references,
2578 1,
2579 ffi::CRYPTO_LOCK_X509,
2580 "mod.rs\0".as_ptr() as *const _,
2581 line!() as c_int,
2582 );
2583 }
2584
2585 #[allow(bad_style)]
2586 unsafe fn X509_get0_signature(
2587 psig: *mut *const ffi::ASN1_BIT_STRING,
2588 palg: *mut *const ffi::X509_ALGOR,
2589 x: *const ffi::X509,
2590 ) {
2591 if !psig.is_null() {
2592 *psig = (*x).signature;
2593 }
2594 if !palg.is_null() {
2595 *palg = (*x).sig_alg;
2596 }
2597 }
2598 }
2599}
2600
2601cfg_if! {
2602 if #[cfg(any(boringssl, ossl110, libressl, awslc))] {
2603 use ffi::{
2604 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2605 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2606 };
2607 } else {
2608 use ffi::{
2609 ASN1_STRING_data as ASN1_STRING_get0_data,
2610 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2611 X509_set_notAfter as X509_set1_notAfter,
2612 X509_set_notBefore as X509_set1_notBefore,
2613 };
2614
2615 #[allow(bad_style)]
2616 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2617 ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2618 }
2619
2620 #[allow(bad_style)]
2621 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2622 (*(*x).req_info).subject
2623 }
2624
2625 #[allow(bad_style)]
2626 unsafe fn X509_ALGOR_get0(
2627 paobj: *mut *const ffi::ASN1_OBJECT,
2628 pptype: *mut c_int,
2629 pval: *mut *mut ::libc::c_void,
2630 alg: *const ffi::X509_ALGOR,
2631 ) {
2632 if !paobj.is_null() {
2633 *paobj = (*alg).algorithm;
2634 }
2635 assert!(pptype.is_null());
2636 assert!(pval.is_null());
2637 }
2638 }
2639}
2640
2641cfg_if! {
2642 if #[cfg(any(ossl110, boringssl, libressl, awslc))] {
2643 use ffi::X509_OBJECT_get0_X509;
2644 } else {
2645 #[allow(bad_style)]
2646 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2647 if (*x).type_ == ffi::X509_LU_X509 {
2648 (*x).data.x509
2649 } else {
2650 ptr::null_mut()
2651 }
2652 }
2653 }
2654}
2655
2656cfg_if! {
2657 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2658 use ffi::X509_OBJECT_free;
2659 } else {
2660 #[allow(bad_style)]
2661 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2662 ffi::X509_OBJECT_free_contents(x);
2663 ffi::CRYPTO_free(x as *mut libc::c_void);
2664 }
2665 }
2666}
2667
2668cfg_if! {
2669 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2670 use ffi::{
2671 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2672 X509_CRL_get_REVOKED,
2673 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2674 };
2675 } else {
2676 #[allow(bad_style)]
2677 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2678 (*(*x).crl).lastUpdate
2679 }
2680 #[allow(bad_style)]
2681 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2682 (*(*x).crl).nextUpdate
2683 }
2684 #[allow(bad_style)]
2685 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2686 (*(*x).crl).issuer
2687 }
2688 #[allow(bad_style)]
2689 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2690 (*(*x).crl).revoked
2691 }
2692 #[allow(bad_style)]
2693 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2694 (*x).serialNumber
2695 }
2696 #[allow(bad_style)]
2697 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2698 (*x).revocationDate
2699 }
2700 }
2701}
2702
2703#[derive(Copy, Clone, PartialEq, Eq)]
2704pub struct X509PurposeId(c_int);
2705
2706impl X509PurposeId {
2707 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2708 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2709 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2710 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2711 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2712 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2713 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2714 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2715 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2716 #[cfg(ossl320)]
2717 pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2718
2719 pub fn from_raw(id: c_int) -> Self {
2721 X509PurposeId(id)
2722 }
2723
2724 pub fn as_raw(&self) -> c_int {
2726 self.0
2727 }
2728}
2729
2730pub struct X509PurposeRef(Opaque);
2732
2733impl ForeignTypeRef for X509PurposeRef {
2735 type CType = ffi::X509_PURPOSE;
2736}
2737
2738impl X509PurposeRef {
2739 #[allow(clippy::unnecessary_cast)]
2753 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2754 unsafe {
2755 let sname = CString::new(sname).unwrap();
2756 cfg_if! {
2757 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2758 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2759 } else {
2760 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2761 }
2762 }
2763 Ok(purpose)
2764 }
2765 }
2766 #[corresponds(X509_PURPOSE_get0)]
2769 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2770 unsafe {
2771 let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2772 Ok(X509PurposeRef::from_const_ptr(ptr))
2773 }
2774 }
2775
2776 pub fn purpose(&self) -> X509PurposeId {
2787 unsafe {
2788 cfg_if! {
2789 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
2790 let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2791 } else {
2792 let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2793 }
2794 }
2795 X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2796 }
2797 }
2798}