Initial commit

This commit is contained in:
nora 2023-09-07 21:25:03 +02:00
commit 46a1ec0a16
9 changed files with 412 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

82
Cargo.lock generated Normal file
View file

@ -0,0 +1,82 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "tls"
version = "0.1.0"
dependencies = [
"byteorder",
"rand",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "tls"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
byteorder = "1.4.3"
rand = "0.8.5"

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# transport layer security
except with probably a lot less of that security part. lots of transport and lots of layers though.

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1692799911,
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1693985761,
"narHash": "sha256-K5b+7j7Tt3+AqbWkcw+wMeqOAWyCD1MH26FPZyWXpdo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0bffda19b8af722f8069d09d8b6a24594c80b352",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

43
flake.nix Normal file
View file

@ -0,0 +1,43 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
llvmPackages_16.clang
llvmPackages_16.bintools
llvmPackages_16.libllvm
rustup
pkg-config
sqlite
# openssl Explicitly no openssl!
];
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add glibc, clang, glib and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
(builtins.map (a: ''-I"${a}/include"'') [
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
''-I${pkgs.glib.out}/lib/glib-2.0/include/''
];
packages = (with pkgs; [
]);
};
});
}

65
src/lib.rs Normal file
View file

@ -0,0 +1,65 @@
pub mod proto;
use std::{
io::{self, Read},
net::{TcpStream, ToSocketAddrs},
};
type Result<T, E = Error> = std::result::Result<T, E>;
pub struct ClientConnection {}
impl ClientConnection {
pub fn establish(host: impl ToSocketAddrs) -> Result<Self> {
let _setup = ClientSetupConnection::establish(host)?;
todo!()
}
}
struct ClientSetupConnection {}
impl ClientSetupConnection {
fn establish(host: impl ToSocketAddrs) -> Result<Self> {
let mut stream = TcpStream::connect(host)?;
let handshake = proto::Handshake::ClientHello {
legacy_version: proto::LEGACY_VERSION,
random: rand::random(),
legacy_session_id: 0,
cipher_suites: [0; 2],
legacy_compressions_methods: 0,
extensions: 0,
};
proto::write_handshake(&mut stream, handshake)?;
let res = proto::read_handshake(&mut stream)?;
dbg!(res);
todo!()
}
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
}
#[derive(Debug)]
pub enum ErrorKind {
InvalidHandshake(u8),
Io(io::Error),
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self {
kind: ErrorKind::Io(value),
}
}
}
impl From<ErrorKind> for Error {
fn from(value: ErrorKind) -> Self {
Self { kind: value }
}
}

4
src/main.rs Normal file
View file

@ -0,0 +1,4 @@
// An example program that makes a shitty HTTP/1.1 request.
fn main() {
tls::ClientConnection::establish(("nilstrieb.dev", 443)).unwrap();
}

143
src/proto.rs Normal file
View file

@ -0,0 +1,143 @@
use std::io::{self, Read, Write};
use byteorder::{BigEndian as B, ReadBytesExt, WriteBytesExt};
use crate::ErrorKind;
// https://datatracker.ietf.org/doc/html/rfc8446#section-4
macro_rules! handshake {
($(#[$meta:meta])* pub enum Handshake {
$(
$KindName:ident {
$(
$field_name:ident : $field_ty:ty,
)*
} = $discriminant:expr,
)*
}) => {
$(#[$meta])*
pub enum Handshake {
$(
$KindName {
$(
$field_name: $field_ty,
)*
},
)*
}
impl Handshake {
fn write(self, w: &mut impl Write) -> io::Result<()> {
match self {
$(
Self::$KindName {
$( $field_name, )*
} => {
$(
Value::write($field_name, &mut *w)?;
)*
Ok(())
}
)*
}
}
fn read(r: &mut impl Read) -> crate::Result<Self> {
let kind = r.read_u8()?;
match kind {
$(
$discriminant => {
let ( $( $field_name ),* ) = ($( { discard!($field_name); Value::read(&mut *r)? } ),*);
Ok(Self::$KindName {
$(
$field_name,
)*
})
},
)*
_ => Err(ErrorKind::InvalidHandshake(kind).into()),
}
}
}
};
}
handshake! {
#[derive(Debug, Clone, Copy)]
pub enum Handshake {
// https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2
ClientHello {
legacy_version: u16,
random: [u8; 32],
legacy_session_id: u8,
cipher_suites: [u8; 2],
legacy_compressions_methods: u8,
extensions: u16,
} = 1,
ServerHello {} = 2,
NewSessionTicket {} = 4,
EndOfEarlyData {} = 5,
EncryptedExtensions {} = 8,
Certificate {} = 11,
CertificateRequest {} = 13,
CertificateVerify {} = 15,
Finished {} = 20,
KeyUpdate {} = 24,
MessageHash {} = 254,
}
}
pub const LEGACY_VERSION: u16 = 0x0303; // TLS v1.2
pub fn write_handshake<W: Write>(w: &mut W, handshake: Handshake) -> io::Result<()> {
handshake.write(w)
}
pub fn read_handshake<R: Read>(r: &mut R) -> crate::Result<Handshake> {
Handshake::read(r)
}
trait Value: Sized + Copy {
fn write<W: io::Write>(self, w: W) -> io::Result<()>;
fn read<R: io::Read>(r: R) -> io::Result<Self>;
}
impl<V: Value, const N: usize> Value for [V; N] {
fn write<W: io::Write>(self, mut w: W) -> io::Result<()> {
self.into_iter().map(|v| Value::write(v, &mut w)).collect()
}
fn read<R: io::Read>(mut r: R) -> io::Result<Self> {
// ugly :(
let mut values = [None; N];
for i in 0..N {
let value = V::read(&mut r)?;
values[i] = Some(value);
}
Ok(values.map(Option::unwrap))
}
}
impl Value for u8 {
fn write<W: io::Write>(self, mut w: W) -> io::Result<()> {
w.write_u8(self)
}
fn read<R: io::Read>(mut r: R) -> io::Result<Self> {
r.read_u8()
}
}
impl Value for u16 {
fn write<W: io::Write>(self, mut w: W) -> io::Result<()> {
w.write_u16::<B>(self)
}
fn read<R: io::Read>(mut r: R) -> io::Result<Self> {
r.read_u16::<B>()
}
}
macro_rules! discard {
($($tt:tt)*) => {};
}
use discard;