From eb30b7c2df2ceec202386dc98b9d61356c58ec1a Mon Sep 17 00:00:00 2001 From: Jay Date: Mon, 5 Aug 2024 17:05:55 +0900 Subject: [PATCH] Add: Server, Client - Client: No Verify Server Certificate --- src/bin/allow_any_cert_client.rs | 170 +++++++++++++++++++++++++++++++ src/main.rs | 84 +++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 src/bin/allow_any_cert_client.rs create mode 100644 src/main.rs diff --git a/src/bin/allow_any_cert_client.rs b/src/bin/allow_any_cert_client.rs new file mode 100644 index 0000000..40e5625 --- /dev/null +++ b/src/bin/allow_any_cert_client.rs @@ -0,0 +1,170 @@ +extern crate pretty_env_logger; +#[macro_use] +extern crate log; +use rustls::version::TLS13; +use rustls::RootCertStore; +use std::error::Error as StdError; +use std::io::{Read, Write}; +use std::sync::Arc; +use x509_parser::prelude::*; + +fn initialize_log() { + pretty_env_logger::formatted_timed_builder() + .format(|buf, record| { + // We are reusing `anstyle` but there are `anstyle-*` crates to adapt it to your + // preferred styling crate. + let mut level_style = buf.default_level_style(record.level()); + let arg_style = level_style.clone(); + let timestamp = buf.timestamp_micros(); + + writeln!( + buf, + "[{timestamp} {:6}] {:>30}:{:<5} - {}", + level_style.set_bold(true).value(record.level()), + record.file_static().unwrap(), + record.line().unwrap(), + arg_style.value(record.args()) + ) + }) + .format_timestamp_micros() + .filter_level(log::LevelFilter::Debug) + .init(); + + info!("Hi -"); +} + +// 모든 인증서를 신뢰하는 인증서 검증기 (모든 인증서 PASS) +#[derive(Debug)] +struct NoCertificateVerification; + +impl rustls::client::danger::ServerCertVerifier for NoCertificateVerification { + fn verify_tls12_signature( + &self, + _: &[u8], + _: &rustls::pki_types::CertificateDer<'_>, + _: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _: &[u8], + _: &rustls::pki_types::CertificateDer<'_>, + _: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) + } + + fn verify_server_cert( + &self, + end_entity: &rustls::pki_types::CertificateDer<'_>, + intermediates: &[rustls::pki_types::CertificateDer<'_>], + server_name: &rustls::pki_types::ServerName<'_>, + _: &[u8], + _: rustls::pki_types::UnixTime, + ) -> Result { + let ret_deserial = X509Certificate::from_der(&end_entity.iter().as_slice()); + let x509 = match ret_deserial { + Ok((_, x509)) => x509, + _ => panic!("wtf"), + }; + let cn = x509 + .subject() + .iter_common_name() + .next() + .and_then(|cn| cn.as_str().ok()).unwrap(); + info!( + "Server Cert: CN: {}, CA: {}, serverName : {:?}", + cn, + x509.is_ca(), + server_name + ); + + // end_entity + for (idx, ica) in intermediates.iter().enumerate() { + let ret_deserial = X509Certificate::from_der(&ica.iter().as_slice()); + let x509 = match ret_deserial { + Ok((_, x509)) => x509, + _ => continue, + }; + let cn = x509 + .subject() + .iter_common_name() + .next() + .and_then(|cn| cn.as_str().ok()); + let cn = match cn { + Some(name) => name, + _ => "", + }; + + info!("[{idx}] CN: {}, CA: {}", cn, x509.is_ca()); + } + info!("verify cert done"); + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + let mut ss = Vec::::new(); + ss.push(rustls::SignatureScheme::RSA_PKCS1_SHA1); + ss.push(rustls::SignatureScheme::ECDSA_SHA1_Legacy); + ss.push(rustls::SignatureScheme::RSA_PKCS1_SHA256); + ss.push(rustls::SignatureScheme::ECDSA_NISTP256_SHA256); + ss.push(rustls::SignatureScheme::RSA_PKCS1_SHA384); + ss.push(rustls::SignatureScheme::ECDSA_NISTP384_SHA384); + ss.push(rustls::SignatureScheme::RSA_PKCS1_SHA512); + ss.push(rustls::SignatureScheme::ECDSA_NISTP521_SHA512); + ss.push(rustls::SignatureScheme::RSA_PSS_SHA256); + ss.push(rustls::SignatureScheme::RSA_PSS_SHA384); + ss.push(rustls::SignatureScheme::RSA_PSS_SHA512); + ss.push(rustls::SignatureScheme::ED25519); + ss.push(rustls::SignatureScheme::ED448); + + ss + } +} + +fn main() -> Result<(), Box> { + initialize_log(); + + let mut config = rustls::ClientConfig::builder_with_protocol_versions(&[&TLS13]) + .with_root_certificates(RootCertStore::empty()) + .with_no_client_auth(); + { + // point + config + .dangerous() + .set_certificate_verifier(Arc::new(NoCertificateVerification)); + config.enable_early_data = false; + } + + let server_name = "scope.co.kr".try_into()?; + let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name)?; + let mut sock = std::net::TcpStream::connect("localhost:10080")?; + let mut tls_conn = rustls::Stream::new(&mut conn, &mut sock); + let mut rbuf : [u8; 1024] = [0; 1024]; + + let wstring = "Hello Rust!"; + let wsize = match tls_conn.write(wstring.as_bytes()) { + Ok(size) => size, + Err(ec) => { + error!("Write Error: {}", ec.kind().to_string()); + usize::MAX + }, + }; + info!("Send Data ({wsize}): {wstring}"); + + let rsize = match tls_conn.read(&mut rbuf) { + Ok(size) => size, + Err(ec) => { + error!("Read Error: {}", ec.kind().to_string()); + 0 + }, + }; + + let utf8string = String::from_utf8(rbuf[0..rsize].to_vec()).expect("could not encoded utf8"); + info!("Received message from Server ({rsize}): {utf8string}"); + + info!("Bye -"); + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fc8f7fd --- /dev/null +++ b/src/main.rs @@ -0,0 +1,84 @@ +extern crate pretty_env_logger; +#[macro_use] +extern crate log; +use std::env; +use std::error::Error as StdError; +use std::fs::File; +use std::io::{BufReader, Read, Write}; +use std::net::TcpListener; +use std::sync::Arc; + +fn initialize_log() { + pretty_env_logger::formatted_timed_builder() + .format(|buf, record| { + // We are reusing `anstyle` but there are `anstyle-*` crates to adapt it to your + // preferred styling crate. + let mut level_style = buf.default_level_style(record.level()); + let arg_style = level_style.clone(); + let timestamp = buf.timestamp_micros(); + + writeln!( + buf, + "[{timestamp} {:6}] {:>30}:{:<5} - {}", + level_style.set_bold(true).value(record.level()), + record.file_static().unwrap(), + record.line().unwrap(), + arg_style.value(record.args()) + ) + }) + .format_timestamp_micros() + .filter_level(log::LevelFilter::Debug) + .init(); + + info!("Hi -"); +} + +fn main() -> Result<(), Box> { + initialize_log(); + + let mut args = env::args(); + args.next(); + let cert_file = args.next().expect("missing certificate file argument"); + let private_key_file = args.next().expect("missing private key file argument"); + + let certs = rustls_pemfile::certs(&mut BufReader::new(&mut File::open(cert_file)?)) + .collect::, _>>()?; + let private_key = + rustls_pemfile::private_key(&mut BufReader::new(&mut File::open(private_key_file)?))? + .unwrap(); + let config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, private_key)?; + + let listener = TcpListener::bind(format!("[::]:{}", 10080)).unwrap(); + trace!("Bound TCP Server"); + + let mut rbuf = [0u8; 1024 * 64]; // 64kb + for r_tcp in listener.incoming() { + let mut stream = r_tcp.expect("Accept Failure"); + stream.set_nodelay(true).expect("Set no delay Failure"); + let mut tls_conn = + rustls::ServerConnection::new(Arc::new(config.clone())).expect("TLS Server Error"); + tls_conn.complete_io(&mut stream)?; + debug!("handshake done!?"); + + let rsize = match tls_conn.reader().read(&mut rbuf) { + Ok(size) => size, + Err(ec) => { + error!("Read Error: {}", ec.to_string()); + continue + } + }; + + let utf8string = String::from_utf8(rbuf[0..rsize].to_vec()).expect("could not encoded utf8"); + info!("Received message from client ({rsize}): {utf8string}"); + + tls_conn.writer().write_fmt(format_args!("Echo, Client say: {}", utf8string))?; + debug!("Send Data"); + tls_conn.complete_io(&mut stream)?; + // -> drop tls_conn + } + + info!("Bye -"); + Ok(()) +}