deeprox 0.1.0

TLS intercepting web proxy inspired by Burp Suite and Mitmproxy
Documentation
use openssl::{
	asn1::Asn1Time,
	bn::BigNum,
	hash::MessageDigest,
	pkcs12::Pkcs12,
	pkey::{PKey, PKeyRef, Private},
	rsa::Rsa,
	x509::{
		extension::{BasicConstraints, SubjectAlternativeName, SubjectKeyIdentifier},
		X509Builder, X509NameBuilder, X509Ref, X509,
	},
};

use rustls::{Certificate, PrivateKey};

use std::{
	fs::File,
	io::{Cursor, Read, Write},
	path::Path,
};

use crate::error::Error;

pub fn generate_keys() -> Result<PKey<Private>, Error> {
	let rsa = Rsa::generate(2048)?;
	let privkey = PKey::from_rsa(rsa)?;
	Ok(privkey)
}

pub fn make_ca_cert(privkey: &PKeyRef<Private>, serial: u32) -> Result<X509, Error> {
	let mut x509_name = X509NameBuilder::new()?;
	x509_name.append_entry_by_text("CN", "Proxy")?;
	let x509_name = x509_name.build();

	let x509_serial = {
		let bn = BigNum::from_u32(serial)?;
		bn.to_asn1_integer()?
	};

	let x509_not_before = Asn1Time::days_from_now(0)?;
	let x509_not_after = Asn1Time::days_from_now(365)?;

	let mut x509 = X509Builder::new()?;
	x509.set_version(2)?;
	x509.set_serial_number(&x509_serial)?;
	x509.set_subject_name(&x509_name)?;
	x509.set_issuer_name(&x509_name)?;
	x509.set_pubkey(&privkey)?;
	x509.set_not_before(&x509_not_before)?;
	x509.set_not_after(&x509_not_after)?;
	x509.append_extension(BasicConstraints::new().critical().ca().pathlen(0).build()?)?;
	x509.append_extension(SubjectKeyIdentifier::new().build(&x509.x509v3_context(None, None))?)?;
	x509.sign(&privkey, MessageDigest::sha256())?;
	let x509 = x509.build();
	Ok(x509)
}

pub fn save_cert(file: &Path, cert: &X509Ref) -> Result<(), Error> {
	let mut file = File::create(file)?;
	file.write_all(&cert.to_pem()?)?;
	Ok(())
}

pub fn load_cert(file: &Path) -> Result<X509, Error> {
	let mut file = File::open(file)?;
	let mut bytes = Vec::new();
	file.read_to_end(&mut bytes)?;
	let cert = X509::from_pem(&bytes)?;
	Ok(cert)
}

pub fn save_key(file: &Path, key: &PKeyRef<Private>) -> Result<(), Error> {
	let mut file = File::create(file)?;
	file.write_all(&key.private_key_to_pem_pkcs8()?)?;
	Ok(())
}

pub fn load_key(file: &Path) -> Result<PKey<Private>, Error> {
	let mut file = File::open(file)?;
	let mut bytes = Vec::new();
	file.read_to_end(&mut bytes)?;
	let key = PKey::private_key_from_pem(&bytes)?;
	Ok(key)
}

pub fn cert_cursor(cert: &X509Ref) -> Result<Cursor<Vec<u8>>, Error> {
	let buffer = cert.to_pem()?;
	Ok(Cursor::new(buffer))
}

pub fn key_cursor(key: &PKeyRef<Private>) -> Result<Cursor<Vec<u8>>, Error> {
	let buffer = key.private_key_to_pem_pkcs8()?;
	Ok(Cursor::new(buffer))
}

pub fn make_signed_cert(
	privkey: &PKeyRef<Private>,
	domain: &str,
	ca_privkey: &PKeyRef<Private>,
	ca_cert: &X509Ref,
	serial: u32,
) -> Result<X509, Error> {
	let mut x509_name = X509NameBuilder::new()?;
	x509_name.append_entry_by_text("CN", domain)?;
	let x509_name = x509_name.build();

	let x509_serial = {
		let bn = BigNum::from_u32(serial)?;
		bn.to_asn1_integer()?
	};

	let x509_not_before = Asn1Time::days_from_now(0)?;
	let x509_not_after = Asn1Time::days_from_now(365)?;

	let mut x509 = X509Builder::new()?;
	x509.set_version(2)?;
	x509.set_serial_number(&x509_serial)?;
	x509.set_subject_name(&x509_name)?;
	x509.set_issuer_name(ca_cert.subject_name())?;
	x509.set_pubkey(&privkey)?;
	x509.set_not_before(&x509_not_before)?;
	x509.set_not_after(&x509_not_after)?;
	x509.append_extension(
		SubjectAlternativeName::new()
			.dns(domain)
			.build(&x509.x509v3_context(Some(ca_cert), None))?,
	)?;
	x509.sign(&ca_privkey, MessageDigest::sha256())?;
	let x509 = x509.build();
	Ok(x509)
}

pub fn make_pkcs12(
	password: &str,
	name: &str,
	key: &PKeyRef<Private>,
	cert: &X509Ref,
) -> Result<Pkcs12, Error> {
	let pkcs12 = Pkcs12::builder().build(password, name, key, cert)?;
	Ok(pkcs12)
}

pub fn load_ca(key: &Path, cert: &Path) -> Result<(PKey<Private>, X509), Error> {
	let ca_privkey_ossl = load_key(key)?;
	let ca_cert_ossl = load_cert(cert)?;

	Ok((ca_privkey_ossl, ca_cert_ossl))
}

pub fn convert_to_rustls(
	privkey: &PKey<Private>,
	cert: &X509,
) -> Result<(Vec<PrivateKey>, Vec<Certificate>), Error> {
	let mut privkey_cursor = key_cursor(&privkey)?;
	let privkey_tls = rustls::internal::pemfile::pkcs8_private_keys(&mut privkey_cursor)
		.map_err(|_| Error::RustlsEmptyErr)?;
	let mut cert_cursor = cert_cursor(&cert)?;
	let cert_tls =
		rustls::internal::pemfile::certs(&mut cert_cursor).map_err(|_| Error::RustlsEmptyErr)?;
	Ok((privkey_tls, cert_tls))
}