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