More blips of work, including CA certificate generation

This commit is contained in:
Olivier 'reivilibre' 2022-01-17 08:41:08 +00:00
parent 95a9f56f64
commit eb55bf4cf3
12 changed files with 309 additions and 51 deletions

95
Cargo.lock generated
View File

@ -71,7 +71,7 @@ dependencies = [
"anyhow",
"bare-metrics-core",
"crossbeam-channel",
"dashmap",
"dashmap 4.0.2",
"fxhash",
"hdrhistogram",
"log",
@ -293,6 +293,47 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "dashmap"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b799062aaf67eb976af3bdca031ee6f846d2f0a5710ddbb0d2efee33f3cc4760"
dependencies = [
"cfg-if 1.0.0",
"num_cpus",
"parking_lot 0.11.2",
]
[[package]]
name = "data-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "der-oid-macro"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c73af209b6a5dc8ca7cbaba720732304792cddc933cfea3d74509c2b1ef2f436"
dependencies = [
"num-bigint",
"num-traits",
"syn",
]
[[package]]
name = "der-parser"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9807efb310ce4ea172924f3a69d82f9fd6c9c3a19336344591153e665b31c43e"
dependencies = [
"der-oid-macro",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "ed25519"
version = "1.3.0"
@ -748,6 +789,17 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -777,6 +829,15 @@ dependencies = [
"libc",
]
[[package]]
name = "oid-registry"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe554cb2393bc784fd678c82c84cc0599c31ceadc7f03a594911f822cb8d1815"
dependencies = [
"der-parser",
]
[[package]]
name = "olivefs"
version = "0.1.0"
@ -789,7 +850,6 @@ dependencies = [
"libc",
"log",
"quinn",
"rcgen",
"serde",
"serde_bare",
"sodiumoxide",
@ -821,10 +881,13 @@ version = "0.1.0"
dependencies = [
"anyhow",
"bare-metrics-recorder",
"clap",
"dashmap 5.0.0",
"env_logger",
"futures-util",
"log",
"quinn",
"rcgen",
"rustls",
"serde",
"serde_bare",
@ -1115,6 +1178,7 @@ dependencies = [
"chrono",
"pem",
"ring",
"x509-parser",
"yasna",
]
@ -1174,6 +1238,15 @@ dependencies = [
"semver",
]
[[package]]
name = "rusticata-macros"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c52377bb2288aa522a0c8208947fada1e0c76397f108cc08f57efe6077b50d"
dependencies = [
"nom",
]
[[package]]
name = "rustls"
version = "0.20.2"
@ -1888,6 +1961,24 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "x509-parser"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffc90836a84cb72e6934137b1504d0cae304ef5d83904beb0c8d773bbfe256ed"
dependencies = [
"base64",
"chrono",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"ring",
"rusticata-macros",
"thiserror",
]
[[package]]
name = "yasna"
version = "0.4.0"

View File

@ -29,7 +29,6 @@ quinn = { version = "0.8.0", features = [] }
# Compression and Encryption
zstd = "0.9.2+zstd.1.5.1"
sodiumoxide = "0.2.7"
rcgen = "0.8.14"
# Filesystem
fuser = "0.10.0"

View File

@ -1,16 +1,26 @@
use fuser::{
Filesystem, KernelConfig, ReplyAttr, ReplyBmap, ReplyCreate, ReplyData,
ReplyDirectory, ReplyDirectoryPlus, ReplyEmpty, ReplyEntry, ReplyIoctl, ReplyLock, ReplyLseek,
ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow,
};
use libc::{ENOSYS, EPERM};
use log::{debug, warn};
use std::ffi::OsStr;
use std::os::raw::c_int;
use std::path::Path;
use std::time::SystemTime;
use fuser::{Filesystem, KernelConfig, ReplyAttr, ReplyBmap, ReplyCreate, ReplyData, ReplyDirectory, ReplyDirectoryPlus, ReplyEmpty, ReplyEntry, ReplyIoctl, ReplyLock, ReplyLseek, ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow};
use libc::{ENOSYS, EPERM};
use log::{warn, debug, info};
use std::time::{Duration, SystemTime};
pub mod encryption;
pub const ROOT_INODE: u64 = 0x01;
pub struct OliveFilesystemSettings {}
// TODO support multiple filesystems per FUSE fs so that operations between multiple of them
// can be made efficient.
pub struct OliveFilesystem {
pub settings: OliveFilesystemSettings,
}
impl Filesystem for OliveFilesystem {
@ -18,6 +28,7 @@ impl Filesystem for OliveFilesystem {
/// Called before any other filesystem method.
/// The kernel module connection can be configured using the KernelConfig object
fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> {
// TODO config has some interesting values.
Ok(())
}
@ -31,6 +42,29 @@ impl Filesystem for OliveFilesystem {
"[Not Implemented] lookup(parent: {:#x?}, name {:?})",
parent, name
);
let _ttl = Duration::from_secs(5);
// let file_attr = FileAttr {
// ino: 0,
// size: 0,
// blocks: 0,
// atime: (),
// mtime: (),
// ctime: (),
// crtime: (),
// kind: FileType::NamedPipe,
// perm: 0,
// nlink: 0,
// uid: 0,
// gid: 0,
// rdev: 0,
// blksize: 0,
// flags: 0
// };
// TODO reply.entry(&ttl, )
reply.error(ENOSYS);
}
@ -690,4 +724,4 @@ impl Filesystem for OliveFilesystem {
debug!("[Not Implemented] getxtimes(ino: {:#x?})", ino);
reply.error(ENOSYS);
}
}
}

View File

@ -1,10 +1,5 @@
// TODO Trait needed to provide encryption
pub trait EncryptionProvider {
}
pub trait EncryptionProvider {}
// No encryption
impl EncryptionProvider for () {
}
impl EncryptionProvider for () {}

View File

@ -1,18 +1,17 @@
use std::path::{Path, PathBuf};
use crate::filesystem::OliveFilesystem;
use crate::filesystem::{OliveFilesystem, OliveFilesystemSettings};
use clap::Parser;
use env_logger::Env;
use std::path::{PathBuf};
pub mod filesystem;
pub mod requester;
#[derive(Parser)]
pub enum OlivefsCommands {
Mount {
configuration_file: PathBuf,
mount_at: PathBuf
}
mount_at: PathBuf,
},
}
fn main() {
@ -23,9 +22,12 @@ fn main() {
let command: OlivefsCommands = OlivefsCommands::parse();
match command {
OlivefsCommands::Mount { configuration_file, mount_at } => {
OlivefsCommands::Mount {
configuration_file: _,
mount_at,
} => {
let fs = OliveFilesystem {
settings: OliveFilesystemSettings {},
};
//fuser::MountOption::
fuser::mount2(fs, mount_at, &[]).unwrap();

View File

@ -1,28 +1,31 @@
use quinn::{Endpoint};
use std::net::SocketAddr;
use std::str::FromStr;
use quinn::{Connection, Endpoint, EndpointConfig};
use tokio::sync::mpsc;
pub struct Requester {
}
pub struct Requester {}
pub struct RequesterInternal {
rx: mpsc::Receiver<()>,
connection: quinn::Connection
connection: quinn::Connection,
}
impl RequesterInternal {
//pub async fn connect()
pub async fn send(&mut self) -> anyhow::Result<()> {
// TODO use with_roots and only use the desired CA! ...
let x = quinn::ClientConfig::with_native_roots();
let _x = quinn::ClientConfig::with_native_roots();
let ep = Endpoint::client(SocketAddr::from_str("0.0.0.0:0").unwrap()).unwrap();
let conn = ep.connect(SocketAddr::from_str("127.0.0.1:5051").unwrap(), "blah").unwrap().await.unwrap();
let conn = ep
.connect(SocketAddr::from_str("127.0.0.1:5051").unwrap(), "blah")
.unwrap()
.await
.unwrap();
// conn.bi_streams and uni_streams are streams needed to listen out for new streams from the server.
// conn.datagrams is similar but for unreliable datagrams
let bi = conn.connection.open_bi().await?;
let _bi = conn.connection.open_bi().await?;
Ok(())
}
}
}

View File

@ -1,4 +1,3 @@
pub mod messages;
pub mod networking;

View File

@ -1,6 +1,8 @@
use std::fmt::Debug;
use serde::{Serialize, Deserialize};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::fs::FileType;
use std::time::SystemTime;
pub const COMMON_VERSION: &'static str = env!("CARGO_PKG_VERSION");
@ -22,20 +24,16 @@ impl HelloMessage {
pub fn new(software_version: String) -> HelloMessage {
HelloMessage {
protocol_version: COMMON_VERSION.to_string(),
software_version
software_version,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Sent by the client on any data stream.
pub enum DataCommand {
pub enum DataCommand {}
}
pub trait DataResponseBase: Serialize + DeserializeOwned + Debug + Clone + 'static {
}
pub trait DataResponseBase: Serialize + DeserializeOwned + Debug + Clone + 'static {}
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Sent by the server in response to a DataCommand on the same data stream.
@ -50,3 +48,38 @@ pub enum DataResponse<R: DataResponseBase> {
message: String,
},
}
/// Copy of fuser's FileAttr. Used to describe a file.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct FileMetadata {
/// Inode number
pub ino: u64,
/// Size in bytes
pub size: u64,
/// Size in blocks
pub blocks: u64,
/// Time of last access
pub atime: SystemTime,
/// Time of last modification
pub mtime: SystemTime,
/// Time of last change
pub ctime: SystemTime,
// /// Time of creation (macOS only)
// pub crtime: SystemTime,
/// Kind of file (directory, file, pipe, etc)
pub kind: FileType,
/// Permissions
pub perm: u16,
/// Number of hard links
pub nlink: u32,
/// User id
pub uid: u32,
/// Group id
pub gid: u32,
/// Rdev
pub rdev: u32,
/// Block size
pub blksize: u32,
// /// Flags (macOS only, see chflags(2))
// pub flags: u32,
}

View File

@ -1,8 +1,9 @@
use quinn::{ReadExactError, RecvStream};
use serde::de::DeserializeOwned;
pub async fn read_control_message<M: DeserializeOwned>(recv_stream: &mut RecvStream) -> anyhow::Result<Option<M>> {
pub async fn read_control_message<M: DeserializeOwned>(
recv_stream: &mut RecvStream,
) -> anyhow::Result<Option<M>> {
let mut u16_buf = [0u8; 2];
if let Err(err) = recv_stream.read_exact(&mut u16_buf).await {
return if err == ReadExactError::FinishedEarly {
@ -16,7 +17,9 @@ pub async fn read_control_message<M: DeserializeOwned>(recv_stream: &mut RecvStr
let mut control_message_bytes: Vec<u8> = vec![0u8; control_message_length];
recv_stream.read_exact(&mut control_message_bytes[..]).await?;
recv_stream
.read_exact(&mut control_message_bytes[..])
.await?;
Ok(todo!())
}
}

View File

@ -17,15 +17,18 @@ tracing-futures = { version = "0.2.5", features = ["tokio"] }
# Asynchronous
tokio = { version = "1.15.0", features = ["full"] }
futures-util = "0.3.19"
dashmap = "5.0.0"
# Serialisation
serde = { version = "1.0.133", features = ["derive"] }
serde_bare = "0.5.0"
toml = "0.5.8"
clap = { version = "3.0.7", features = ["derive"] }
# Networking
quinn = { version = "0.8.0", features = [] }
rustls = "0.20.2"
# Compression and Encryption
zstd = "0.9.2+zstd.1.5.1"
rustls = "0.20.2"
rcgen = { version = "0.8.14", features = ["pem", "x509-parser"] }

View File

@ -1,11 +1,95 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc;
use anyhow::anyhow;
use clap::Parser;
use futures_util::StreamExt;
use quinn::Endpoint;
use rcgen::{BasicConstraints, Certificate, CertificateParams, IsCa, KeyPair};
use rustls::internal::msgs::codec::Codec;
use std::io::Read;
use std::net::SocketAddr;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use std::thread::yield_now;
use tokio::fs::File;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
pub mod server;
#[derive(clap::Parser)]
pub enum Command {
Serve {},
/// Generates a certificate
GenerateCertificate {
/// The certificate authority directory
ca_dir: PathBuf,
/// Name of the client or server to generate a certificate for
name: String,
},
}
pub async fn write_file(path: &Path, content: &str) -> anyhow::Result<()> {
let mut file = File::create(path).await?;
file.write_all(content.as_bytes()).await?;
Ok(())
}
pub async fn read_file(path: &Path) -> anyhow::Result<String> {
let mut file = File::open(path).await?;
let mut string = String::new();
file.read_to_string(&mut string).await?;
Ok(string)
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let command: Command = Command::parse();
match command {
Command::Serve { .. } => {}
Command::GenerateCertificate { ca_dir, name } => {
let ca_key_path = ca_dir.join("ca.key");
let ca_cert_path = ca_dir.join("ca.pem");
if !ca_key_path.exists() {
// Generate a CA first
let mut ca_params = CertificateParams::new(Vec::with_capacity(0));
ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
// TODO don't hard code a date :-).
ca_params.not_after = rcgen::date_time_ymd(2042, 1, 1);
let ca_cert = Certificate::from_params(ca_params)?;
let cert_pem = ca_cert.serialize_pem()?;
let key_pem = ca_cert.serialize_private_key_pem();
write_file(&ca_key_path, &key_pem).await?;
write_file(&ca_cert_path, &cert_pem).await?;
}
let ca_key_pem = read_file(&ca_key_path).await?;
let ca_cert_pem = read_file(&ca_cert_path).await?;
let ca_keypair = KeyPair::from_pem(&ca_key_pem)?;
let ca_cert = Certificate::from_params(CertificateParams::from_ca_cert_pem(
&ca_cert_pem,
ca_keypair,
)?)?;
let mut cert_params = CertificateParams::new(vec![name.clone()]);
// TODO don't hard code a date :-).
cert_params.not_after = rcgen::date_time_ymd(2042, 1, 1);
let leaf_cert = Certificate::from_params(cert_params)?;
write_file(
&ca_dir.join(format!("{}.key", &name)),
&leaf_cert.serialize_private_key_pem(),
)
.await?;
write_file(
&ca_dir.join(format!("{}.pem", &name)),
&leaf_cert.serialize_pem_with_signer(&ca_cert)?,
)
.await?;
}
}
println!("Hello, world!");
//let x = quinn::ServerConfig::with_native_roots();
@ -15,7 +99,8 @@ async fn main() -> anyhow::Result<()> {
.with_single_cert(todo!(), todo!())?;
let crypto = Arc::new(crypto);
let x = quinn::ServerConfig::with_crypto(crypto);
let (ep, mut incoming) = Endpoint::server(x, SocketAddr::from_str("127.0.0.1:5051").unwrap()).unwrap();
let (ep, mut incoming) =
Endpoint::server(x, SocketAddr::from_str("127.0.0.1:5051").unwrap()).unwrap();
loop {
let next = incoming.next().await;

11
olivefsd/src/server.rs Normal file
View File

@ -0,0 +1,11 @@
use dashmap::DashMap;
use std::sync::Arc;
pub struct FileDescriptor {}
pub struct InodeInfo {}
pub struct ServerHandle {
pub inode_map: Arc<DashMap<u32, InodeInfo>>,
pub file_descriptors: Arc<DashMap<u32, FileDescriptor>>,
}