cc! certtool + fix ncpf/netcatpf
This commit is contained in:
parent
cbe8dee8a3
commit
f438935954
|
@ -1,12 +1,15 @@
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use inquire::{Confirm, Select, Text};
|
||||||
|
use libepf::ca_pool::load_ca_pool;
|
||||||
|
use libepf::pki::{
|
||||||
|
EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps, EpfPkiSerializable, EpfPrivateKey,
|
||||||
|
EpfPublicKey,
|
||||||
|
};
|
||||||
|
use rand::rngs::OsRng;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use clap::{Parser, Subcommand};
|
|
||||||
use inquire::{Confirm, Select, Text};
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use libepf::ca_pool::load_ca_pool;
|
|
||||||
use libepf::pki::{EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps, EpfPkiSerializable, EpfPrivateKey, EpfPublicKey};
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -22,31 +25,27 @@ enum Commands {
|
||||||
#[arg(short = 'p', long)]
|
#[arg(short = 'p', long)]
|
||||||
out_public_key: PathBuf,
|
out_public_key: PathBuf,
|
||||||
#[arg(short = 'k', long)]
|
#[arg(short = 'k', long)]
|
||||||
out_private_key: PathBuf
|
out_private_key: PathBuf,
|
||||||
},
|
},
|
||||||
/// Create a new **unsigned** certificate
|
/// Create a new **unsigned** certificate
|
||||||
CreateCertificate {
|
CreateCertificate {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
output: PathBuf,
|
output: PathBuf,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
public_key: PathBuf
|
public_key: PathBuf,
|
||||||
},
|
},
|
||||||
/// Dump information about the certificate
|
/// Dump information about the certificate
|
||||||
DumpCertificate {
|
DumpCertificate { cert: PathBuf },
|
||||||
cert: PathBuf
|
|
||||||
},
|
|
||||||
/// Verify the certificate
|
/// Verify the certificate
|
||||||
VerifyCertificate {
|
VerifyCertificate { cert: PathBuf },
|
||||||
cert: PathBuf
|
|
||||||
},
|
|
||||||
/// Sign the certificate using the given private key
|
/// Sign the certificate using the given private key
|
||||||
SignCertificate {
|
SignCertificate {
|
||||||
cert: PathBuf,
|
cert: PathBuf,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
key: PathBuf,
|
key: PathBuf,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
output: PathBuf
|
output: PathBuf,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -54,7 +53,10 @@ fn main() {
|
||||||
|
|
||||||
if let Some(subcommand) = args.command {
|
if let Some(subcommand) = args.command {
|
||||||
match subcommand {
|
match subcommand {
|
||||||
Commands::GenerateKeypair { out_private_key, out_public_key } => {
|
Commands::GenerateKeypair {
|
||||||
|
out_private_key,
|
||||||
|
out_public_key,
|
||||||
|
} => {
|
||||||
let private_key = EpfPrivateKey::generate(&mut OsRng);
|
let private_key = EpfPrivateKey::generate(&mut OsRng);
|
||||||
let public_key = private_key.verifying_key();
|
let public_key = private_key.verifying_key();
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ fn main() {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Commands::CreateCertificate { output, public_key } => {
|
Commands::CreateCertificate { output, public_key } => {
|
||||||
// load public key
|
// load public key
|
||||||
let public_key_pem = match fs::read(public_key) {
|
let public_key_pem = match fs::read(public_key) {
|
||||||
|
@ -114,8 +116,14 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let options = vec!["1 day", "1 week", "1 month", "6 months", "1 year", "2 years", "5 years", "10 years", "Forever"];
|
let options = vec![
|
||||||
let expires_in = match Select::new("How long should the certificate be valid for?", options).prompt() {
|
"1 day", "1 week", "1 month", "6 months", "1 year", "2 years", "5 years",
|
||||||
|
"10 years", "Forever",
|
||||||
|
];
|
||||||
|
let expires_in =
|
||||||
|
match Select::new("How long should the certificate be valid for?", options)
|
||||||
|
.prompt()
|
||||||
|
{
|
||||||
Ok(expires_in) => expires_in,
|
Ok(expires_in) => expires_in,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error with prompt: {}", e);
|
println!("Error with prompt: {}", e);
|
||||||
|
@ -132,10 +140,15 @@ fn main() {
|
||||||
"5 years" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 5,
|
"5 years" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 5,
|
||||||
"10 years" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 10,
|
"10 years" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 10,
|
||||||
"Forever" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 100000, // 100,000 years
|
"Forever" => 60 * 60 * 24 * 7 * 4 * 6 * 2 * 100000, // 100,000 years
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let add_claims = match Confirm::new("Would you like to add additional claims to the certificate?").with_default(false).prompt() {
|
let add_claims = match Confirm::new(
|
||||||
|
"Would you like to add additional claims to the certificate?",
|
||||||
|
)
|
||||||
|
.with_default(false)
|
||||||
|
.prompt()
|
||||||
|
{
|
||||||
Ok(ac) => ac,
|
Ok(ac) => ac,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error with prompt: {}", e);
|
println!("Error with prompt: {}", e);
|
||||||
|
@ -162,7 +175,12 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
claims.insert(name, value);
|
claims.insert(name, value);
|
||||||
let add_another = match Confirm::new("Would you like to add additional claims to the certificate?").with_default(true).prompt() {
|
let add_another = match Confirm::new(
|
||||||
|
"Would you like to add additional claims to the certificate?",
|
||||||
|
)
|
||||||
|
.with_default(true)
|
||||||
|
.prompt()
|
||||||
|
{
|
||||||
Ok(ac) => ac,
|
Ok(ac) => ac,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error with prompt: {}", e);
|
println!("Error with prompt: {}", e);
|
||||||
|
@ -178,8 +196,15 @@ fn main() {
|
||||||
let mut cert = EPFCertificate {
|
let mut cert = EPFCertificate {
|
||||||
details: EPFCertificateDetails {
|
details: EPFCertificateDetails {
|
||||||
name,
|
name,
|
||||||
not_before: SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs(),
|
not_before: SystemTime::now()
|
||||||
not_after: SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs() + expires_in,
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards")
|
||||||
|
.as_secs(),
|
||||||
|
not_after: SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards")
|
||||||
|
.as_secs()
|
||||||
|
+ expires_in,
|
||||||
public_key: public_key.to_bytes(),
|
public_key: public_key.to_bytes(),
|
||||||
issuer_public_key: [0u8; 32],
|
issuer_public_key: [0u8; 32],
|
||||||
claims,
|
claims,
|
||||||
|
@ -209,7 +234,7 @@ fn main() {
|
||||||
println!("Error saving certificate: {}", e);
|
println!("Error saving certificate: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Commands::DumpCertificate { cert } => {
|
Commands::DumpCertificate { cert } => {
|
||||||
// load cert
|
// load cert
|
||||||
let cert_pem = match fs::read(cert) {
|
let cert_pem = match fs::read(cert) {
|
||||||
|
@ -227,7 +252,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
println!("{}", cert);
|
println!("{}", cert);
|
||||||
},
|
}
|
||||||
Commands::SignCertificate { cert, key, output } => {
|
Commands::SignCertificate { cert, key, output } => {
|
||||||
// load cert
|
// load cert
|
||||||
let cert_pem = match fs::read(cert) {
|
let cert_pem = match fs::read(cert) {
|
||||||
|
@ -283,7 +308,7 @@ fn main() {
|
||||||
println!("Error saving certificate: {}", e);
|
println!("Error saving certificate: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Commands::VerifyCertificate { cert } => {
|
Commands::VerifyCertificate { cert } => {
|
||||||
// load cert
|
// load cert
|
||||||
let cert_pem = match fs::read(cert) {
|
let cert_pem = match fs::read(cert) {
|
||||||
|
@ -314,13 +339,13 @@ fn main() {
|
||||||
println!("Certificate valid but not trusted");
|
println!("Certificate valid but not trusted");
|
||||||
std::process::exit(3);
|
std::process::exit(3);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Certificate invalid: {}", e);
|
println!("Certificate invalid: {}", e);
|
||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("No subcommand specified. Run with -h/--help for help.");
|
println!("No subcommand specified. Run with -h/--help for help.");
|
||||||
|
|
|
@ -76,6 +76,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn ca_pool_error_display_test() {
|
pub fn ca_pool_error_display_test() {
|
||||||
println!("{}", EpfCaPoolLoaderError::CertDirDoesNotExist("".to_string()));
|
println!(
|
||||||
|
"{}",
|
||||||
|
EpfCaPoolLoaderError::CertDirDoesNotExist("".to_string())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,7 +38,12 @@ mod tests {
|
||||||
pub fn error_display_test() {
|
pub fn error_display_test() {
|
||||||
println!("{}", EpfHandshakeError::AlreadyTunnelled);
|
println!("{}", EpfHandshakeError::AlreadyTunnelled);
|
||||||
println!("{}", EpfHandshakeError::UnsupportedProtocolVersion(0));
|
println!("{}", EpfHandshakeError::UnsupportedProtocolVersion(0));
|
||||||
println!("{}", EpfHandshakeError::InvalidCertificate(EpfPkiCertificateValidationError::ValidAfterSigner));
|
println!(
|
||||||
|
"{}",
|
||||||
|
EpfHandshakeError::InvalidCertificate(
|
||||||
|
EpfPkiCertificateValidationError::ValidAfterSigner
|
||||||
|
)
|
||||||
|
);
|
||||||
println!("{}", EpfHandshakeError::UntrustedCertificate);
|
println!("{}", EpfHandshakeError::UntrustedCertificate);
|
||||||
println!("{}", EpfHandshakeError::EncryptionError);
|
println!("{}", EpfHandshakeError::EncryptionError);
|
||||||
println!("{}", EpfHandshakeError::MissingKeyProof);
|
println!("{}", EpfHandshakeError::MissingKeyProof);
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use crate::ca_pool::{EpfCaPool};
|
use crate::ca_pool::EpfCaPool;
|
||||||
use crate::danger_trace;
|
use crate::danger_trace;
|
||||||
use crate::error::EpfHandshakeError;
|
use crate::error::EpfHandshakeError;
|
||||||
use crate::pki::{
|
use crate::pki::{EPFCertificate, EpfPkiCertificateOps, EpfPrivateKey, EpfPublicKey};
|
||||||
EPFCertificate, EpfPkiCertificateOps, EpfPrivateKey, EpfPublicKey,
|
|
||||||
};
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
encode_packet, recv_packet, EpfApplicationData, EpfClientHello, EpfClientState, EpfFinished,
|
encode_packet, recv_packet, EpfApplicationData, EpfClientHello, EpfClientState, EpfFinished,
|
||||||
EpfMessage, EpfServerHello, EpfServerState, PACKET_APPLICATION_DATA, PACKET_CLIENT_HELLO,
|
EpfMessage, EpfServerHello, EpfServerState, PACKET_APPLICATION_DATA, PACKET_CLIENT_HELLO,
|
||||||
|
@ -12,8 +10,8 @@ use crate::protocol::{
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chacha20poly1305::aead::{Aead, Payload};
|
use chacha20poly1305::aead::{Aead, Payload};
|
||||||
use chacha20poly1305::{AeadCore, Key, KeyInit, XChaCha20Poly1305, XNonce};
|
use chacha20poly1305::{AeadCore, Key, KeyInit, XChaCha20Poly1305, XNonce};
|
||||||
use ed25519_dalek::{SigningKey};
|
use ed25519_dalek::SigningKey;
|
||||||
use log::{trace};
|
use log::trace;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -701,13 +699,13 @@ mod tests {
|
||||||
EpfServerHandshaker, EpfServerUpgradable, EpfServerUpgraded, EpfStreamOps,
|
EpfServerHandshaker, EpfServerUpgradable, EpfServerUpgraded, EpfStreamOps,
|
||||||
};
|
};
|
||||||
use crate::pki::{EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps};
|
use crate::pki::{EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps};
|
||||||
use ed25519_dalek::{SigningKey};
|
use ed25519_dalek::SigningKey;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
||||||
|
use serial_test::serial;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use serial_test::serial;
|
|
||||||
|
|
||||||
use tokio::join;
|
use tokio::join;
|
||||||
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
||||||
|
@ -856,11 +854,8 @@ mod tests {
|
||||||
|
|
||||||
cert_pool_2.insert(&server_cert);
|
cert_pool_2.insert(&server_cert);
|
||||||
|
|
||||||
let mut c: EpfClientUpgraded<TcpStream> = EpfClientUpgradable::upgrade(
|
let mut c: EpfClientUpgraded<TcpStream> =
|
||||||
c,
|
EpfClientUpgradable::upgrade(c, ClientAuthentication::Ephemeral).await;
|
||||||
ClientAuthentication::Ephemeral,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let mut s: EpfServerUpgraded<TcpStream> =
|
let mut s: EpfServerUpgraded<TcpStream> =
|
||||||
EpfServerUpgradable::upgrade(s, server_cert, server_private_key).await;
|
EpfServerUpgradable::upgrade(s, server_cert, server_private_key).await;
|
||||||
|
|
||||||
|
|
|
@ -646,7 +646,12 @@ mod tests {
|
||||||
|
|
||||||
let ca_pool = EpfCaPool::new();
|
let ca_pool = EpfCaPool::new();
|
||||||
|
|
||||||
assert!(matches!(fingerprint_does_not_match_cert.verify(&ca_pool).unwrap_err(), EpfPkiCertificateValidationError::FingerprintDoesNotMatch { .. }));
|
assert!(matches!(
|
||||||
|
fingerprint_does_not_match_cert
|
||||||
|
.verify(&ca_pool)
|
||||||
|
.unwrap_err(),
|
||||||
|
EpfPkiCertificateValidationError::FingerprintDoesNotMatch { .. }
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -680,7 +685,12 @@ mod tests {
|
||||||
|
|
||||||
let ca_pool = EpfCaPool::new();
|
let ca_pool = EpfCaPool::new();
|
||||||
|
|
||||||
assert!(matches!(fingerprint_does_not_match_cert.verify(&ca_pool).unwrap_err(), EpfPkiCertificateValidationError::InvalidSignature { .. }));
|
assert!(matches!(
|
||||||
|
fingerprint_does_not_match_cert
|
||||||
|
.verify(&ca_pool)
|
||||||
|
.unwrap_err(),
|
||||||
|
EpfPkiCertificateValidationError::InvalidSignature { .. }
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use std::error::Error;
|
use clap::Parser;
|
||||||
use std::io::{Write};
|
|
||||||
use std::net::{IpAddr, SocketAddr};
|
|
||||||
use clap::{Parser};
|
|
||||||
use tokio::io::AsyncReadExt;
|
|
||||||
use tokio::net::{TcpSocket};
|
|
||||||
use tokio::select;
|
|
||||||
use libepf::ca_pool::load_ca_pool;
|
use libepf::ca_pool::load_ca_pool;
|
||||||
use libepf::handshake_stream::{ClientAuthentication, EpfClientHandshaker, EpfClientUpgradable, EpfStreamOps};
|
use libepf::handshake_stream::{
|
||||||
|
ClientAuthentication, EpfClientHandshaker, EpfClientUpgradable, EpfStreamOps,
|
||||||
|
};
|
||||||
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
use tokio::net::TcpSocket;
|
||||||
|
use tokio::select;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
connect_ip: IpAddr,
|
connect_ip: IpAddr,
|
||||||
connect_port: u16
|
connect_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use std::error::Error;
|
use clap::Parser;
|
||||||
use std::{fs, io};
|
|
||||||
use std::io::{Write};
|
|
||||||
use std::net::{IpAddr, SocketAddr};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use clap::{Parser};
|
|
||||||
use tokio::io::AsyncReadExt;
|
|
||||||
use tokio::net::TcpListener;
|
|
||||||
use tokio::select;
|
|
||||||
use libepf::ca_pool::load_ca_pool;
|
use libepf::ca_pool::load_ca_pool;
|
||||||
use libepf::handshake_stream::{EpfServerHandshaker, EpfServerUpgradable, EpfStreamOps};
|
use libepf::handshake_stream::{EpfServerHandshaker, EpfServerUpgradable, EpfStreamOps};
|
||||||
use libepf::pki::{EPFCertificate, EpfPkiSerializable, EpfPrivateKey};
|
use libepf::pki::{EPFCertificate, EpfPkiSerializable, EpfPrivateKey};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs, io};
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use tokio::select;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
|
Loading…
Reference in New Issue