tls: expose peer certificate
Fixes #326.
diff --git a/src/lib.rs b/src/lib.rs
index c944b98..8086d57 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2549,6 +2549,11 @@
self.handshake.alpn_protocol()
}
+ /// Returns the peer's leaf certificate (if any) as a DER-encoded buffer.
+ pub fn peer_cert(&self) -> Option<Vec<u8>> {
+ self.handshake.peer_cert()
+ }
+
/// Returns true if the connection handshake is complete.
pub fn is_established(&self) -> bool {
self.handshake_completed
@@ -4942,6 +4947,21 @@
Err(Error::CongestionControl)
);
}
+
+ #[test]
+ fn peer_cert() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ match pipe.client.peer_cert() {
+ Some(c) => assert_eq!(c.len(), 919),
+
+ None => panic!("missing server certificate"),
+ }
+ }
}
pub use crate::packet::Header;
diff --git a/src/tls.rs b/src/tls.rs
index ab7118c..004b259 100644
--- a/src/tls.rs
+++ b/src/tls.rs
@@ -79,7 +79,6 @@
#[allow(non_camel_case_types)]
#[repr(transparent)]
-#[cfg(windows)]
struct X509(c_void);
#[repr(C)]
@@ -446,6 +445,31 @@
Some(sigalg.to_string())
}
+ pub fn peer_cert(&self) -> Option<Vec<u8>> {
+ let peer_cert = unsafe {
+ let mut out: *mut libc::c_uchar = ptr::null_mut();
+
+ let x509 = SSL_get_peer_certificate(self.as_ptr());
+ if x509.is_null() {
+ return None;
+ }
+
+ let out_len = i2d_X509(x509, &mut out);
+ if out_len <= 0 {
+ return None;
+ }
+
+ let der = slice::from_raw_parts(out, out_len as usize);
+ let der = der.to_vec();
+
+ OPENSSL_free(out as *mut c_void);
+
+ der
+ };
+
+ Some(peer_cert)
+ }
+
pub fn is_resumed(&self) -> bool {
unsafe { SSL_session_reused(self.as_ptr()) == 1 }
}
@@ -866,6 +890,8 @@
sigalg: u16, include_curve: i32,
) -> *const c_char;
+ fn SSL_get_peer_certificate(ssl: *mut SSL) -> *const X509;
+
fn SSL_set_min_proto_version(ssl: *mut SSL, version: u16);
fn SSL_set_max_proto_version(ssl: *mut SSL, version: u16);
@@ -923,8 +949,13 @@
#[cfg(windows)]
fn d2i_X509(px: *mut X509, input: *const *const u8, len: c_int) -> *mut X509;
+ fn i2d_X509(px: *const X509, out: *mut *mut u8) -> c_int;
+
// ERR
fn ERR_peek_error() -> c_uint;
fn ERR_error_string_n(err: c_uint, buf: *const u8, len: usize);
+
+ // OPENSSL
+ fn OPENSSL_free(ptr: *mut c_void);
}