From 898803bbe21f9ddb3aff39e0d283d3505db68d9d Mon Sep 17 00:00:00 2001 From: Alex Guzman Date: Tue, 19 Jun 2018 20:07:29 -0700 Subject: [PATCH] Markdown-ify README, add logo Summary: Makes the README markdown formatted and adds the logo on the top. :) Reviewed By: siyengar Differential Revision: D8465425 fbshipit-source-id: d15b4e7848f729da569f56e90b0f18e9bd461bc4 --- README | 31 ------------------------------- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ logo2x.png | Bin 0 -> 22717 bytes 3 files changed, 45 insertions(+), 31 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100644 logo2x.png diff --git a/README b/README deleted file mode 100644 index d74afb37d6d..00000000000 --- a/README +++ /dev/null @@ -1,31 +0,0 @@ -Fizz is a TLS 1.3 implementation. - -Fizz currently supports TLS 1.3 drafts 18-21. HelloRetryRequest, early data, -and client authentication are only supported on draft 19 and above. Each draft -also has a corresponding "fb" version. These match the draft versions except -for some minor record layer differences. - -Directories: - fizz/crypto: Cryptographic primitive implementations (most are wrapping - OpenSSL or libsodium) - fizz/record: TLS 1.3 record layer parsing - fizz/protocol: Common protocol code shared between client and server - fizz/client: Client protocol implementation - fizz/server: Server protocol implementation - -The core protocol implementations are in ClientProtocol and ServerProtocol. -FizzClientContext and FizzServerContext provide configuration options. -FizzClient and FizzServer (which both inherit from FizzBase) provide -applications with an interface to interact with the state machine. -FizzClient/FizzServer receives events from the application layer, invokes the -correct event handler, and invokes the application ActionVisitor to process the -actions. - -AsyncFizzClient and AsyncFizzServer provide implementations of the folly -AsyncTransportWrapper interface. They own an underlying transport (for example -AsyncSocket) and perform the TLS handshake and encrypt/decrypt application -data. - -ClientSocket and ServerSocket provide sample usage of AsyncFizzClient and -AsyncFizzServer and can be used to start up a simple TLS 1.3 client or server -over a TCP connection. diff --git a/README.md b/README.md new file mode 100644 index 00000000000..a50d96acce4 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +

+ Fizz +

+Fizz is a TLS 1.3 implementation. + +Fizz currently supports TLS 1.3 drafts 18-28. HelloRetryRequest, early data, +and client authentication are only supported on draft 19 and above. Each draft +also has a corresponding "fb" version. These match the draft versions except +for some minor record layer differences. + +## Dependencies +Fizz largely depends on three libraries: [folly](https://www.github.com/facebook/folly), +[OpenSSL](https://www.openssl.org/), and [libsodium](https://github.com/jedisct1/libsodium). + +## Source Layout +- `fizz/crypto`: Cryptographic primitive implementations (most are wrapping + OpenSSL or libsodium) +- `fizz/record`: TLS 1.3 record layer parsing +- `fizz/protocol`: Common protocol code shared between client and server +- `fizz/client`: Client protocol implementation +- `fizz/server`: Server protocol implementation + +## Design +The core protocol implementations are in `ClientProtocol` and `ServerProtocol`. +`FizzClientContext` and `FizzServerContext` provide configuration options. +`FizzClient` and `FizzServer` (which both inherit from `FizzBase`) provide +applications with an interface to interact with the state machine. +`FizzClient`/`FizzServer` receives events from the application layer, invokes the +correct event handler, and invokes the application `ActionVisitor` to process the +actions. + +`AsyncFizzClient` and `AsyncFizzServer` provide implementations of the folly +`AsyncTransportWrapper` interface. They own an underlying transport (for example +`AsyncSocket`) and perform the TLS handshake and encrypt/decrypt application +data. + +## Sample Applications +`ClientSocket` and `ServerSocket` provide sample usage of `AsyncFizzClient` and +`AsyncFizzServer` and can be used to start up a simple TLS 1.3 client or server +over a TCP connection. + +For example, to start ServerSocket on port 443 with a specified cert: +`ServerSocket -port 443 -cert foo.pem -key foo.key`. Then, on the same host, +you can connect with `ClientSocket -host localhost -port 443`. Both will dump +the data they get and will remain running until interrupted via CTRL+C. diff --git a/logo2x.png b/logo2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70a68375a923724425a3429368466531e34328c GIT binary patch literal 22717 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 F{x33F)J6aR literal 0 HcmV?d00001