chore: Adds lots of documentation.
This commit is contained in:
parent
514ccee264
commit
8eb9bb3cee
11 changed files with 101 additions and 14 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
bismuthd
|
21
README.md
21
README.md
|
@ -1,3 +1,24 @@
|
|||
# Bismuth Protocol
|
||||
|
||||
The Bismuth protocol is a thin wrapper for any protocol that adds TLS-like features, without being TLS on its own.
|
||||
|
||||
## Application
|
||||
### Building
|
||||
|
||||
Git clone this repository and check out a release (except for development, as you probably don't wanna develop on a release version):
|
||||
```bash
|
||||
git clone https://git.greysoh.dev/imterah/bismuthd
|
||||
git checkout v0.1.0
|
||||
```
|
||||
Then, build the code:
|
||||
```bash
|
||||
go build .
|
||||
```
|
||||
|
||||
### Usage
|
||||
To get started, you'll need an exported armored public and private key pair.
|
||||
|
||||
After that, for usage help, run the help command:
|
||||
```
|
||||
./bismuthd help
|
||||
```
|
||||
|
|
3
client/README.md
Normal file
3
client/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Bismuth Client
|
||||
|
||||
This is a wrapper around connections which lets you speak the Bismuth protocol.
|
|
@ -41,13 +41,18 @@ func (bismuth BismuthClient) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]
|
|||
return decryptedData, nil
|
||||
}
|
||||
|
||||
// Bismuth Client
|
||||
type BismuthClient struct {
|
||||
PublicKey *crypto.Key
|
||||
// GOpenPGP public key
|
||||
PublicKey *crypto.Key
|
||||
// GOpenPGP private key
|
||||
PrivateKey *crypto.Key
|
||||
|
||||
pgp *crypto.PGPHandle
|
||||
}
|
||||
|
||||
// Connects to a Bismuth server. This wraps an existing net.Conn interface.
|
||||
// The returned net.Conn is the server, but over bismuth.
|
||||
func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) {
|
||||
// Yes, I'm aware defer exists. It won't work if I use it in this context. I'll shank anyone that complains
|
||||
// Exchange our public keys first
|
||||
|
@ -183,6 +188,9 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Creates a new BismuthClient.
|
||||
//
|
||||
// Both `pubKey` and `privKey` are armored PGP public and private keys respectively.
|
||||
func New(pubKey string, privKey string) (*BismuthClient, error) {
|
||||
publicKey, err := crypto.NewKeyFromArmored(pubKey)
|
||||
|
||||
|
|
4
commons/README.md
Normal file
4
commons/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Commons between Bismuth Client and Server
|
||||
|
||||
This houses common internal libraries and constants between the bismuth client and server.
|
||||
For most of the time, you're probably going to want the connection handler, which is in `conn.go`.
|
|
@ -1,3 +1,5 @@
|
|||
// Shared connection handler after both the client and server handshake successfully
|
||||
|
||||
package commons
|
||||
|
||||
import (
|
||||
|
@ -9,11 +11,18 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// Max size for a TCP packet
|
||||
// Maximum size for a TCP packet
|
||||
var ConnStandardMaxBufSize = 65535
|
||||
var CryptHeader = 43
|
||||
var cryptHeaderSize = 43
|
||||
|
||||
// Wild
|
||||
// Connection used after both the Bismuth client and server negotiate and start
|
||||
// transmitting data.
|
||||
//
|
||||
// Note that using this has the same API as the net.Conn, but it isn't conformant to
|
||||
// the interface due to using pointers rather than copies to access the struct.
|
||||
//
|
||||
// If you need the same interface, wrap this in WrappedBismuthConn.
|
||||
// Wrapping BismuthConn is done automatically by the client and server.
|
||||
type BismuthConn struct {
|
||||
Aead cipher.AEAD
|
||||
PassedConn net.Conn
|
||||
|
@ -26,10 +35,11 @@ type BismuthConn struct {
|
|||
contentBufPos int
|
||||
contentBufSize int
|
||||
|
||||
MaxBufSize int
|
||||
// Maximum buffer size to be used to internally buffer packets
|
||||
MaxBufSize int
|
||||
// If true, it enables using the content buffer maximum size
|
||||
// instead of the TCP packet maximum size
|
||||
AllowNonstandardPacketSizeLimit bool
|
||||
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (bmConn *BismuthConn) DoInitSteps() {
|
||||
|
@ -68,6 +78,7 @@ func (bmConn *BismuthConn) decryptMessage(encMsg []byte) ([]byte, error) {
|
|||
return decryptedData, nil
|
||||
}
|
||||
|
||||
// After you update the property `bmConn.MaxBufSize`, call this function to resize the content buffer
|
||||
func (bmConn *BismuthConn) ResizeContentBuf() error {
|
||||
if !bmConn.initDone {
|
||||
return fmt.Errorf("bmConn not initialized")
|
||||
|
@ -95,6 +106,7 @@ func (bmConn *BismuthConn) ResizeContentBuf() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Reads specifically from the buffer only. If nothing is in the buffer, nothing is returned.
|
||||
func (bmConn *BismuthConn) ReadFromBuffer(b []byte) (n int, err error) {
|
||||
bmConn.lock.Lock()
|
||||
defer bmConn.lock.Unlock()
|
||||
|
@ -126,6 +138,7 @@ func (bmConn *BismuthConn) ReadFromBuffer(b []byte) (n int, err error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
// Reads specifically from the network. Be careful as using only this may overflow the buffer.
|
||||
func (bmConn *BismuthConn) ReadFromNetwork(b []byte) (n int, err error) {
|
||||
bmConn.lock.Lock()
|
||||
defer bmConn.lock.Unlock()
|
||||
|
@ -146,7 +159,7 @@ func (bmConn *BismuthConn) ReadFromNetwork(b []byte) (n int, err error) {
|
|||
// - the max buffer size if 'AllowNonstandardPacketSizeLimit' is set
|
||||
// We check AFTER we read to make sure that we don't corrupt any future packets, because if we don't read the packet,
|
||||
// it will think that the actual packet will be the start of the packet, and that would cause loads of problems.
|
||||
if !bmConn.AllowNonstandardPacketSizeLimit && encryptedContentLength > uint32(65535+CryptHeader) {
|
||||
if !bmConn.AllowNonstandardPacketSizeLimit && encryptedContentLength > uint32(65535+cryptHeaderSize) {
|
||||
return 0, fmt.Errorf("packet too large")
|
||||
} else if bmConn.AllowNonstandardPacketSizeLimit && encryptedContentLength > uint32(bmConn.MaxBufSize) {
|
||||
return 0, fmt.Errorf("packet too large")
|
||||
|
@ -187,6 +200,7 @@ func (bmConn *BismuthConn) ReadFromNetwork(b []byte) (n int, err error) {
|
|||
return calcSize, nil
|
||||
}
|
||||
|
||||
// Reads from the Bismuth connection, using both the buffered and network methods
|
||||
func (bmConn *BismuthConn) Read(b []byte) (n int, err error) {
|
||||
if !bmConn.initDone {
|
||||
return 0, fmt.Errorf("bmConn not initialized")
|
||||
|
@ -211,6 +225,7 @@ func (bmConn *BismuthConn) Read(b []byte) (n int, err error) {
|
|||
return bufferReadSize + networkReadSize, nil
|
||||
}
|
||||
|
||||
// Encrypts and sends off a message
|
||||
func (bmConn *BismuthConn) Write(b []byte) (n int, err error) {
|
||||
encryptedMessage, err := bmConn.encryptMessage(b)
|
||||
|
||||
|
@ -251,8 +266,10 @@ func (bmConn *BismuthConn) SetWriteDeadline(time time.Time) error {
|
|||
return bmConn.PassedConn.SetWriteDeadline(time)
|
||||
}
|
||||
|
||||
// TODO: remove this ugly hack if possible! There's probably a better way around this...
|
||||
|
||||
// Wrapped BismuthConn struct. This is conformant to net.Conn, unlike above.
|
||||
// To get the raw Bismuth struct, just get the Bismuth property:
|
||||
//
|
||||
// `bmConn.Bismuth` -> `BismuthConn`
|
||||
type BismuthConnWrapped struct {
|
||||
Bismuth *BismuthConn
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// Conversion libraries for 24 bit numbering instead of 32 bit numbering
|
||||
|
||||
package commons
|
||||
|
||||
// Converts a 24 bit unsigned integer stored in a big-endian byte array to a 32 bit unsigned integer.
|
||||
func Int24ToInt32(b []byte) uint32 {
|
||||
return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16
|
||||
}
|
||||
|
||||
// Converts a 32 bit unsigned integer to a 24 bit unsigned integer in a byte array using big-endian ordering.
|
||||
func Int32ToInt24(b []byte, int uint32) {
|
||||
b[0] = uint8((int >> 16) & 0xff)
|
||||
b[1] = uint8((int >> 8) & 0xff)
|
||||
|
|
|
@ -1,18 +1,33 @@
|
|||
// Enums used internally
|
||||
|
||||
package commons
|
||||
|
||||
// Commands
|
||||
const (
|
||||
// SendPublicKey: Sending public key back and forth
|
||||
SendPublicKey = iota
|
||||
// SwitchToSymmetricKey: Sent by the client along with the symmetric key that is going to be used
|
||||
SwitchToSymmetricKey
|
||||
// ClientSendHost: Currently unimplemented.
|
||||
// Client sends what host they are connecting to.
|
||||
ClientSendHost
|
||||
// GetSigningServers: Currently unimplemented.
|
||||
// Gets the signing servers trusting/signing the current server.
|
||||
GetSigningServers
|
||||
// GetTrustedDomains: Currently unimplemented.
|
||||
// Gets the domains that are supported by this certificate (should be cross-checked)
|
||||
GetTrustedDomains
|
||||
// InitiateForwarding: Starts forwarding traffic over this protocol.
|
||||
InitiateForwarding
|
||||
)
|
||||
|
||||
// Encryption algorithms
|
||||
const (
|
||||
// Default and only encryption algorithm
|
||||
XChaCha20Poly1305 = iota
|
||||
)
|
||||
|
||||
// Unsigned integer limits
|
||||
const (
|
||||
BitLimit24 = 16_777_215
|
||||
BitLimit16 = 65535
|
||||
|
|
3
server/README.md
Normal file
3
server/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Bismuth Server
|
||||
|
||||
This is the Bismuth server, which lets you speak the Bismuth protocol.
|
|
@ -13,17 +13,22 @@ import (
|
|||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// Bismuth Server
|
||||
type BismuthServer struct {
|
||||
PublicKey *crypto.Key
|
||||
// Public key to use for transmission
|
||||
PublicKey *crypto.Key
|
||||
// Private key to use for transmission
|
||||
PrivateKey *crypto.Key
|
||||
|
||||
pgp *crypto.PGPHandle
|
||||
|
||||
// Algorithm to use for encryption (currently XChaCha20Poly1305 is the only option)
|
||||
SymmetricEncryptionAlgorithm int
|
||||
|
||||
// Servers that are signing this server. If none, this server becomes self-signed
|
||||
// in the clients eyes
|
||||
SigningServers []string
|
||||
|
||||
// This is what's called after a successful handshake & connection.
|
||||
// Called after a successful handshake & connection.
|
||||
HandleConnection func(conn net.Conn) error
|
||||
}
|
||||
|
||||
|
@ -56,7 +61,7 @@ func (bismuth BismuthServer) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]
|
|||
return decryptedData, nil
|
||||
}
|
||||
|
||||
// This is what's called to handle a connnection for Bismuth.
|
||||
// Called to handle a connnection for Bismuth. The conn argument is the client you'd like to handle
|
||||
func (bismuth BismuthServer) HandleProxy(conn net.Conn) error {
|
||||
serverState := "keyHandshake"
|
||||
|
||||
|
@ -225,6 +230,9 @@ func (bismuth BismuthServer) HandleProxy(conn net.Conn) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Initializes a Bismuth server.
|
||||
//
|
||||
// Both `pubKey` and `privKey` are armored PGP public and private keys respectively.
|
||||
func NewBismuthServer(pubKey string, privKey string, signServers []string, encryptionAlgo int, connHandler func(conn net.Conn) error) (*BismuthServer, error) {
|
||||
publicKey, err := crypto.NewKeyFromArmored(pubKey)
|
||||
|
||||
|
|
3
tests/README.md
Normal file
3
tests/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Test Suites
|
||||
|
||||
These are either test suites or support code for test suites for Bismuth's client and server code.
|
Loading…
Add table
Reference in a new issue