diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 8c7f7b1a4cb833bbf2f50e6726561b4330e6062c..43c92f1ff473420ab05416fe5ec368c2933b6974 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -67,12 +67,16 @@ foreign_type_and_impl_send_sync! { impl fmt::Display for Asn1GeneralizedTimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { - let mem_bio = MemBio::new()?; - cvt(ffi::ASN1_GENERALIZEDTIME_print( - mem_bio.as_ptr(), - self.as_ptr(), - ))?; - write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + match MemBio::new() { + Err(_) => f.write_str(""), + Ok(mem_bio) => match cvt(ffi::ASN1_GENERALIZEDTIME_print( + mem_bio.as_ptr(), + self.as_ptr(), + )) { + Err(_) => f.write_str(""), + Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), + }, + } } } } @@ -207,13 +211,23 @@ impl<'a> PartialOrd for &'a Asn1TimeRef { impl fmt::Display for Asn1TimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { - let mem_bio = MemBio::new()?; - cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()))?; - write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + match MemBio::new() { + Err(_) => f.write_str("error"), + Ok(mem_bio) => match cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr())) { + Err(_) => f.write_str("error"), + Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), + }, + } } } } +impl fmt::Debug for Asn1TimeRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.to_string()) + } +} + impl Asn1Time { fn new() -> Result { ffi::init(); @@ -389,6 +403,15 @@ impl Asn1StringRef { } } +impl fmt::Debug for Asn1StringRef { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.as_utf8() { + Ok(openssl_string) => openssl_string.fmt(fmt), + Err(_) => fmt.write_str("error"), + } + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_INTEGER; fn drop = ffi::ASN1_INTEGER_free; @@ -527,12 +550,20 @@ impl fmt::Display for Asn1ObjectRef { self.as_ptr(), 0, ); - let s = str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)?; - fmt.write_str(s) + match str::from_utf8(&buf[..len as usize]) { + Err(_) => fmt.write_str("error"), + Ok(s) => fmt.write_str(s), + } } } } +impl fmt::Debug for Asn1ObjectRef { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.to_string().as_str()) + } +} + cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::ASN1_STRING_get0_data; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 2dfa95c6d9e7846b4f0a0e20254c1c86dd4ec7e8..7af13c09034e1da79d5660d8e5cb0ce43c4929b2 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -49,6 +49,7 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use std::ffi::CString; +use std::fmt; use std::mem; use std::ptr; @@ -286,6 +287,27 @@ where } } +impl fmt::Debug for PKey { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let alg = match self.id() { + Id::RSA => "RSA", + Id::HMAC => "HMAC", + Id::DSA => "DSA", + Id::DH => "DH", + Id::EC => "EC", + #[cfg(ossl111)] + Id::ED25519 => "Ed25519", + #[cfg(ossl111)] + Id::ED448 => "Ed448", + _ => "unknown", + }; + fmt.debug_struct("public_key") + .field("algorithm", &alg) + .finish() + // TODO: Print details for each specific type of key + } +} + impl Clone for PKey { fn clone(&self) -> PKey { PKeyRef::to_owned(self) diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index fc2eafae20a8c784d8eb109853372b67dcc14195..985426d335c645c809369297c82620e8ae4054c3 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -3,6 +3,7 @@ use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; +use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; @@ -43,6 +44,15 @@ pub struct Stack(*mut T::StackType); unsafe impl Send for Stack {} unsafe impl Sync for Stack {} +impl fmt::Debug for Stack +where + T: Stackable, + T::Ref: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_list().entries(self).finish() + } +} impl Drop for Stack { fn drop(&mut self) { unsafe { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 02063d0ecb265829a9bfa1db379e12eb6b45ee41..047102bd19ab0bb3537bd70c148d9be6a2792c37 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -671,6 +671,35 @@ impl Clone for X509 { } } +impl fmt::Debug for X509 { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let serial = match &self.serial_number().to_bn() { + Ok(bn) => match bn.to_hex_str() { + Ok(hex) => hex.to_string(), + Err(_) => "".to_string(), + }, + Err(_) => "".to_string(), + }; + let mut debug_struct = formatter.debug_struct("X509"); + debug_struct.field("serial_number", &serial); + debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); + debug_struct.field("issuer", &self.issuer_name()); + debug_struct.field("subject", &self.subject_name()); + if let Some(subject_alt_names) = &self.subject_alt_names() { + debug_struct.field("subject_alt_names", subject_alt_names); + } + debug_struct.field("not_before", &self.not_before()); + debug_struct.field("not_after", &self.not_after()); + + if let Ok(public_key) = &self.public_key() { + debug_struct.field("public_key", public_key); + }; + // TODO: Print extensions once they are supported on the X509 struct. + + debug_struct.finish() + } +} + impl AsRef for X509Ref { fn as_ref(&self) -> &X509Ref { self @@ -867,6 +896,12 @@ impl X509NameRef { } } +impl fmt::Debug for X509NameRef { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.debug_list().entries(self.entries()).finish() + } +} + /// A type to destructure and examine an `X509Name`. pub struct X509NameEntries<'a> { name: &'a X509NameRef, @@ -942,6 +977,12 @@ impl X509NameEntryRef { } } +impl fmt::Debug for X509NameEntryRef { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) + } +} + /// A builder used to construct an `X509Req`. pub struct X509ReqBuilder(X509Req); @@ -1298,6 +1339,25 @@ impl GeneralNameRef { } } +impl fmt::Debug for GeneralNameRef { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if let Some(email) = self.email() { + return formatter.write_str(email); + } + if let Some(dnsname) = self.dnsname() { + return formatter.write_str(dnsname); + } + if let Some(uri) = self.uri() { + return formatter.write_str(uri); + } + if let Some(ipaddress) = self.ipaddress() { + let result = String::from_utf8_lossy(ipaddress); + return formatter.write_str(&result); + } + Ok(()) + } +} + impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index a6baf45ddab39d4c40ddeb42a189459e3d89acd3..8db82fa545c967c0984f2aa741fb585af084f6a6 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -31,6 +31,34 @@ fn test_cert_loading() { assert_eq!(hash_vec, &*fingerprint); } +#[test] +fn test_debug() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let debugged = format!("{:#?}", cert); + let expected = r#"X509 { + serial_number: "8771F7BDEE982FA5", + signature_algorithm: sha256WithRSAEncryption, + issuer: [ + countryName = "AU", + stateOrProvinceName = "Some-State", + organizationName = "Internet Widgits Pty Ltd", + ], + subject: [ + countryName = "AU", + stateOrProvinceName = "Some-State", + organizationName = "Internet Widgits Pty Ltd", + commonName = "foobar.com", + ], + not_before: Aug 14 17:00:03 2016 GMT, + not_after: Aug 12 17:00:03 2026 GMT, + public_key: public_key { + algorithm: "RSA", + }, +}"#; + assert_eq!(expected, debugged); +} + #[test] fn test_cert_issue_validity() { let cert = include_bytes!("../../test/cert.pem");