mirror of
https://github.com/Noratrieb/tls.git
synced 2026-01-14 16:45:02 +01:00
Initial commit
This commit is contained in:
commit
46a1ec0a16
9 changed files with 412 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
82
Cargo.lock
generated
Normal file
82
Cargo.lock
generated
Normal 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
10
Cargo.toml
Normal 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
3
README.md
Normal 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
61
flake.lock
generated
Normal 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
43
flake.nix
Normal 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
65
src/lib.rs
Normal 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
4
src/main.rs
Normal 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
143
src/proto.rs
Normal 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;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue