mint

package module
v0.0.0-...-fd18df9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2021 License: MIT Imports: 33 Imported by: 51

README

A lock with a mint leaf

mint - A Minimal TLS 1.3 stack

Build Status

This project is primarily a learning effort for me to understand the TLS 1.3 protocol. The goal is to arrive at a pretty complete implementation of TLS 1.3, with minimal, elegant code that demonstrates how things work. Testing is a priority to ensure correctness, but otherwise, the quality of the software engineering might not be at a level where it makes sense to integrate this with other libraries. Backward compatibility is not an objective.

We borrow liberally from the Go TLS library, especially where TLS 1.3 aligns with earlier TLS versions. However, unnecessary parts will be ruthlessly cut off.

DTLS Support

Mint has partial support for DTLS, but that support is not yet complete and may still contain serious defects.

Quickstart

Installation is the same as for any other Go package:

go get github.com/bifurcation/mint

The API is pretty much the same as for the TLS module, with Dial and Listen methods wrapping the underlying socket APIs.

conn, err := mint.Dial("tcp", "localhost:4430", &mint.Config{...})
...
listener, err := mint.Listen("tcp", "localhost:4430", &mint.Config{...})

Documentation is available on godoc.org

Interoperability testing

The mint-client and mint-server executables are included to make it easy to do basic interoperability tests with other TLS 1.3 implementations. The steps for testing against NSS are as follows.

# Install mint
go get github.com/bifurcation/mint

# Environment for NSS (you'll probably want a new directory)
NSS_ROOT=<whereever you want to put NSS>
mkdir $NSS_ROOT
cd $NSS_ROOT
export USE_64=1
export ENABLE_TLS_1_3=1
export HOST=localhost
export DOMSUF=localhost

# Build NSS
hg clone https://hg.mozilla.org/projects/nss
hg clone https://hg.mozilla.org/projects/nspr
cd nss
make nss_build_all

export PLATFORM=`cat $NSS_ROOT/dist/latest`
export DYLD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib
export LD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib

# Run NSS tests (this creates data for the server to use)
cd tests/ssl_gtests
./ssl_gtests.sh

# Test with client=mint server=NSS
cd $NSS_ROOT
./dist/$PLATFORM/bin/selfserv -d tests_results/security/$HOST.1/ssl_gtests/ -n rsa -p 4430
# if you get `NSS_Init failed.`, check the path above, particularly around $HOST
# ...
go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-client/main.go

# Test with client=NSS server=mint
go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-server/main.go
# ...
cd $NSS_ROOT
dist/$PLATFORM/bin/tstclnt -d tests_results/security/$HOST/ssl_gtests/ -V tls1.3:tls1.3 -h 127.0.0.1 -p 4430 -o

Documentation

Overview

Read a generic "framed" packet consisting of a header and a This is used for both TLS Records and TLS Handshake Messages

Index

Constants

View Source
const (
	// alert level
	AlertLevelWarning = 1
	AlertLevelError   = 2
)
View Source
const (
	DirectionWrite = Direction(1)
	DirectionRead  = Direction(2)
)

Variables

This section is empty.

Functions

func ALPNNegotiation

func ALPNNegotiation(psk *PreSharedKey, offered, supported []string) (string, error)

func CertificateSelection

func CertificateSelection(serverName *string, signatureSchemes []SignatureScheme, certs []*Certificate) (*Certificate, SignatureScheme, error)

func EarlyDataNegotiation

func EarlyDataNegotiation(usingPSK, gotEarlyData, allowEarlyData bool) (using bool, rejected bool)

func HkdfExpand

func HkdfExpand(hash crypto.Hash, prk, info []byte, outLen int) []byte

func HkdfExpandLabel

func HkdfExpandLabel(hash crypto.Hash, secret []byte, label string, hashValue []byte, outLen int) []byte

func HkdfExtract

func HkdfExtract(hash crypto.Hash, saltIn, input []byte) []byte

From RFC 5869 PRK = HMAC-Hash(salt, IKM)

func Listen

func Listen(network, laddr string, config *Config) (net.Listener, error)

Listen creates a TLS listener accepting connections on the given network address using net.Listen. The configuration config must be non-nil and must include at least one certificate or else set GetCertificate.

func MakeNewSelfSignedCert

func MakeNewSelfSignedCert(name string, alg SignatureScheme) (crypto.Signer, *x509.Certificate, error)

func NewListener

func NewListener(inner net.Listener, config *Config) (net.Listener, error)

NewListener creates a Listener which accepts connections from an inner Listener and wraps each connection with Server. The configuration config must be non-nil and must include at least one certificate or else set GetCertificate.

func PSKModeNegotiation

func PSKModeNegotiation(canDoDH, canDoPSK bool, modes []PSKKeyExchangeMode) (bool, bool)

func PSKNegotiation

func PSKNegotiation(identities []PSKIdentity, binders []PSKBinderEntry, context []byte, psks PreSharedKeyCache) (bool, int, *PreSharedKey, CipherSuiteParams, error)

func VersionNegotiation

func VersionNegotiation(offered, supported []uint16) (bool, uint16)

Types

type AEADFactory

type AEADFactory func(key []byte) (cipher.AEAD, error)

type ALPNExtension

type ALPNExtension struct {
	Protocols []string
}

opaque ProtocolName<1..2^8-1>;

struct {
    ProtocolName protocol_name_list<2..2^16-1>
} ProtocolNameList;

func (ALPNExtension) Marshal

func (alpn ALPNExtension) Marshal() ([]byte, error)

func (ALPNExtension) Type

func (alpn ALPNExtension) Type() ExtensionType

func (*ALPNExtension) Unmarshal

func (alpn *ALPNExtension) Unmarshal(data []byte) (int, error)

type Alert

type Alert uint8
const (
	AlertCloseNotify                 Alert = 0
	AlertUnexpectedMessage           Alert = 10
	AlertBadRecordMAC                Alert = 20
	AlertDecryptionFailed            Alert = 21
	AlertRecordOverflow              Alert = 22
	AlertDecompressionFailure        Alert = 30
	AlertHandshakeFailure            Alert = 40
	AlertBadCertificate              Alert = 42
	AlertUnsupportedCertificate      Alert = 43
	AlertCertificateRevoked          Alert = 44
	AlertCertificateExpired          Alert = 45
	AlertCertificateUnknown          Alert = 46
	AlertIllegalParameter            Alert = 47
	AlertUnknownCA                   Alert = 48
	AlertAccessDenied                Alert = 49
	AlertDecodeError                 Alert = 50
	AlertDecryptError                Alert = 51
	AlertProtocolVersion             Alert = 70
	AlertInsufficientSecurity        Alert = 71
	AlertInternalError               Alert = 80
	AlertInappropriateFallback       Alert = 86
	AlertUserCanceled                Alert = 90
	AlertNoRenegotiation             Alert = 100
	AlertMissingExtension            Alert = 109
	AlertUnsupportedExtension        Alert = 110
	AlertCertificateUnobtainable     Alert = 111
	AlertUnrecognizedName            Alert = 112
	AlertBadCertificateStatsResponse Alert = 113
	AlertBadCertificateHashValue     Alert = 114
	AlertUnknownPSKIdentity          Alert = 115
	AlertNoApplicationProtocol       Alert = 120
	AlertStatelessRetry              Alert = 253
	AlertWouldBlock                  Alert = 254
	AlertNoAlert                     Alert = 255
)

func (Alert) Error

func (e Alert) Error() string

func (Alert) String

func (e Alert) String() string

type AppExtensionHandler

type AppExtensionHandler interface {
	Send(hs HandshakeType, el *ExtensionList) error
	Receive(hs HandshakeType, el *ExtensionList) error
}

type Certificate

type Certificate struct {
	Chain      []*x509.Certificate
	PrivateKey crypto.Signer
}

type CertificateBody

type CertificateBody struct {
	CertificateRequestContext []byte
	CertificateList           []CertificateEntry
}

func (CertificateBody) Marshal

func (c CertificateBody) Marshal() ([]byte, error)

func (CertificateBody) Type

func (c CertificateBody) Type() HandshakeType

func (*CertificateBody) Unmarshal

func (c *CertificateBody) Unmarshal(data []byte) (int, error)

type CertificateEntry

type CertificateEntry struct {
	CertData   *x509.Certificate
	Extensions ExtensionList
}

opaque ASN1Cert<1..2^24-1>;

struct {
    ASN1Cert cert_data;
    Extension extensions<0..2^16-1>
} CertificateEntry;
struct {
    opaque certificate_request_context<0..2^8-1>;
    CertificateEntry certificate_list<0..2^24-1>;
} Certificate;

type CertificateRequestBody

type CertificateRequestBody struct {
	CertificateRequestContext []byte        `tls:"head=1"`
	Extensions                ExtensionList `tls:"head=2"`
}
struct {
    opaque certificate_request_context<0..2^8-1>;
    Extension extensions<2..2^16-1>;
} CertificateRequest;

func (CertificateRequestBody) Marshal

func (cr CertificateRequestBody) Marshal() ([]byte, error)

func (CertificateRequestBody) Type

func (*CertificateRequestBody) Unmarshal

func (cr *CertificateRequestBody) Unmarshal(data []byte) (int, error)

type CertificateVerifyBody

type CertificateVerifyBody struct {
	Algorithm SignatureScheme
	Signature []byte `tls:"head=2"`
}
struct {
    SignatureScheme algorithm;
    opaque signature<0..2^16-1>;
} CertificateVerify;

func (*CertificateVerifyBody) EncodeSignatureInput

func (cv *CertificateVerifyBody) EncodeSignatureInput(data []byte) []byte

func (CertificateVerifyBody) Marshal

func (cv CertificateVerifyBody) Marshal() ([]byte, error)

func (*CertificateVerifyBody) Sign

func (cv *CertificateVerifyBody) Sign(privateKey crypto.Signer, handshakeHash []byte) (err error)

func (CertificateVerifyBody) Type

func (*CertificateVerifyBody) Unmarshal

func (cv *CertificateVerifyBody) Unmarshal(data []byte) (int, error)

func (*CertificateVerifyBody) Verify

func (cv *CertificateVerifyBody) Verify(publicKey crypto.PublicKey, handshakeHash []byte) error

type CipherSuite

type CipherSuite uint16

uint8 CipherSuite[2];

const (
	// XXX: Actually TLS_NULL_WITH_NULL_NULL, but we need a way to label the zero
	// value for this type so that we can detect when a field is set.
	CIPHER_SUITE_UNKNOWN         CipherSuite = 0x0000
	TLS_AES_128_GCM_SHA256       CipherSuite = 0x1301
	TLS_AES_256_GCM_SHA384       CipherSuite = 0x1302
	TLS_CHACHA20_POLY1305_SHA256 CipherSuite = 0x1303
	TLS_AES_128_CCM_SHA256       CipherSuite = 0x1304
	TLS_AES_256_CCM_8_SHA256     CipherSuite = 0x1305
)

func CipherSuiteNegotiation

func CipherSuiteNegotiation(psk *PreSharedKey, offered, supported []CipherSuite) (CipherSuite, error)

func (CipherSuite) String

func (c CipherSuite) String() string

type CipherSuiteParams

type CipherSuiteParams struct {
	Suite      CipherSuite
	Cipher     AEADFactory    // Cipher factory
	Hash       crypto.Hash    // Hash function
	KeyLengths map[string]int // This maps keys (the label used for HKDF-Expand-Label) to the length of the key needed.
}

type ClientHelloBody

type ClientHelloBody struct {
	LegacyVersion   uint16
	Random          [32]byte
	LegacySessionID []byte
	CipherSuites    []CipherSuite
	Extensions      ExtensionList
}
struct {
    ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
    Random random;
    opaque legacy_session_id<0..32>;
    CipherSuite cipher_suites<2..2^16-2>;
    opaque legacy_compression_methods<1..2^8-1>;
    Extension extensions<0..2^16-1>;
} ClientHello;

func (ClientHelloBody) Marshal

func (ch ClientHelloBody) Marshal() ([]byte, error)

func (ClientHelloBody) Truncated

func (ch ClientHelloBody) Truncated() ([]byte, error)

TODO: File a spec bug to clarify this

func (ClientHelloBody) Type

func (ch ClientHelloBody) Type() HandshakeType

func (*ClientHelloBody) Unmarshal

func (ch *ClientHelloBody) Unmarshal(data []byte) (int, error)

type Config

type Config struct {
	// Client fields
	ServerName string

	// Server fields
	SendSessionTickets bool
	TicketLifetime     uint32
	TicketLen          int
	EarlyDataLifetime  uint32
	AllowEarlyData     bool
	// Require the client to echo a cookie.
	RequireCookie bool
	// A CookieHandler can be used to set and validate a cookie.
	// The cookie returned by the CookieHandler will be part of the cookie sent on the wire, and encoded using the CookieProtector.
	// If no CookieHandler is set, mint will always send a cookie.
	// The CookieHandler can be used to decide on a per-connection basis, if a cookie should be sent.
	CookieHandler CookieHandler
	// The CookieProtector is used to encrypt / decrypt cookies.
	// It should make sure that the Cookie cannot be read and tampered with by the client.
	// If non-blocking mode is used, and cookies are required, this field has to be set.
	// In blocking mode, a default cookie protector is used, if this is unused.
	CookieProtector CookieProtector
	// The ExtensionHandler is used to add custom extensions.
	ExtensionHandler  AppExtensionHandler
	RequireClientAuth bool

	// Time returns the current time as the number of seconds since the epoch.
	// If Time is nil, TLS uses time.Now.
	Time func() time.Time
	// RootCAs defines the set of root certificate authorities
	// that clients use when verifying server certificates.
	// If RootCAs is nil, TLS uses the host's root CA set.
	RootCAs *x509.CertPool
	// InsecureSkipVerify controls whether a client verifies the
	// server's certificate chain and host name.
	// If InsecureSkipVerify is true, TLS accepts any certificate
	// presented by the server and any host name in that certificate.
	// In this mode, TLS is susceptible to man-in-the-middle attacks.
	// This should be used only for testing.
	InsecureSkipVerify bool

	// Shared fields
	Certificates []*Certificate
	// VerifyPeerCertificate, if not nil, is called after normal
	// certificate verification by either a TLS client or server. It
	// receives the raw ASN.1 certificates provided by the peer and also
	// any verified chains that normal processing found. If it returns a
	// non-nil error, the handshake is aborted and that error results.
	//
	// If normal verification fails then the handshake will abort before
	// considering this callback. If normal verification is disabled by
	// setting InsecureSkipVerify then this callback will be considered but
	// the verifiedChains argument will always be nil.
	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error

	CipherSuites     []CipherSuite
	Groups           []NamedGroup
	SignatureSchemes []SignatureScheme
	NextProtos       []string
	PSKs             PreSharedKeyCache
	PSKModes         []PSKKeyExchangeMode
	NonBlocking      bool
	UseDTLS          bool

	RecordLayer RecordLayerFactory
	// contains filtered or unexported fields
}

Config is the struct used to pass configuration settings to a TLS client or server instance. The settings for client and server are pretty different, but we just throw them all in here.

func (*Config) Clone

func (c *Config) Clone() *Config

Clone returns a shallow clone of c. It is safe to clone a Config that is being used concurrently by a TLS client or server.

func (*Config) Init

func (c *Config) Init(isClient bool) error

func (*Config) ValidForClient

func (c *Config) ValidForClient() bool

func (*Config) ValidForServer

func (c *Config) ValidForServer() bool

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn implements the net.Conn interface, as with "crypto/tls" * Read, Write, and Close are provided locally * LocalAddr, RemoteAddr, and Set*Deadline are forwarded to the inner Conn

func Client

func Client(conn net.Conn, config *Config) *Conn

Client returns a new TLS client side connection using conn as the underlying transport. The config cannot be nil: users must set either ServerName or InsecureSkipVerify in the config.

func Dial

func Dial(network, addr string, config *Config) (*Conn, error)

Dial connects to the given network address using net.Dial and then initiates a TLS handshake, returning the resulting TLS connection. Dial interprets a nil configuration as equivalent to the zero configuration; see the documentation of Config for the defaults.

func DialWithDialer

func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error)

DialWithDialer connects to the given network address using dialer.Dial and then initiates a TLS handshake, returning the resulting TLS connection. Any timeout or deadline given in the dialer apply to connection and TLS handshake as a whole.

DialWithDialer interprets a nil configuration as equivalent to the zero configuration; see the documentation of Config for the defaults.

func NewConn

func NewConn(conn net.Conn, config *Config, isClient bool) *Conn

func Server

func Server(conn net.Conn, config *Config) *Conn

Server returns a new TLS server side connection using conn as the underlying transport. The configuration config must be non-nil and must include at least one certificate or else set GetCertificate.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection.

func (*Conn) ComputeExporter

func (c *Conn) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error)

func (*Conn) ConnectionState

func (c *Conn) ConnectionState() ConnectionState

func (*Conn) GetDTLSTimeout

func (c *Conn) GetDTLSTimeout() (bool, time.Duration)

func (*Conn) GetHsState

func (c *Conn) GetHsState() State

func (*Conn) Handshake

func (c *Conn) Handshake() Alert

Handshake causes a TLS handshake on the connection. The `isClient` member determines whether a client or server handshake is performed. If a handshake has already been performed, then its result will be returned.

func (*Conn) HandshakeSetup

func (c *Conn) HandshakeSetup() Alert

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

LocalAddr returns the local network address.

func (*Conn) Read

func (c *Conn) Read(buffer []byte) (int, error)

Read application data up to the size of buffer. Handshake and alert records are consumed by the Conn object directly.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the remote network address.

func (*Conn) SendKeyUpdate

func (c *Conn) SendKeyUpdate(requestUpdate bool) error

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

SetDeadline sets the read and write deadlines associated with the connection. A zero value for t means Read and Write will not time out. After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the read deadline on the underlying connection. A zero value for t means Read will not time out.

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the write deadline on the underlying connection. A zero value for t means Write will not time out. After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.

func (*Conn) Writable

func (c *Conn) Writable() bool

func (*Conn) Write

func (c *Conn) Write(buffer []byte) (int, error)

Write application data

type ConnectionOptions

type ConnectionOptions struct {
	ServerName string
	NextProtos []string
}

ConnectionOptions objects represent per-connection settings for a client initiating a connection

type ConnectionParameters

type ConnectionParameters struct {
	UsingPSK               bool
	UsingDH                bool
	ClientSendingEarlyData bool
	UsingEarlyData         bool
	RejectedEarlyData      bool
	UsingClientAuth        bool

	CipherSuite CipherSuite
	ServerName  string
	NextProto   string
}

ConnectionParameters objects represent the parameters negotiated for a connection.

type ConnectionState

type ConnectionState struct {
	HandshakeState   State
	CipherSuite      CipherSuiteParams     // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
	PeerCertificates []*x509.Certificate   // certificate chain presented by remote peer
	VerifiedChains   [][]*x509.Certificate // verified chains built from PeerCertificates
	NextProto        string                // Selected ALPN proto
	UsingPSK         bool                  // Are we using PSK.
	UsingEarlyData   bool                  // Did we negotiate 0-RTT.
}

type CookieExtension

type CookieExtension struct {
	Cookie []byte `tls:"head=2,min=1"`
}
struct {
    opaque cookie<1..2^16-1>;
} Cookie;

func (CookieExtension) Marshal

func (c CookieExtension) Marshal() ([]byte, error)

func (CookieExtension) Type

func (c CookieExtension) Type() ExtensionType

func (*CookieExtension) Unmarshal

func (c *CookieExtension) Unmarshal(data []byte) (int, error)

type CookieHandler

type CookieHandler interface {
	// Generate a byte string that is sent as a part of a cookie to the client in the HelloRetryRequest
	// If Generate returns nil, mint will not send a HelloRetryRequest.
	Generate(*Conn) ([]byte, error)
	// Validate is called when receiving a ClientHello containing a Cookie.
	// If validation failed, the handshake is aborted.
	Validate(*Conn, []byte) bool
}

A CookieHandler can be used to give the application more fine-grained control over Cookies. Generate receives the Conn as an argument, so the CookieHandler can decide when to send the cookie based on that, and offload state to the client by encoding that into the Cookie. When the client echoes the Cookie, Validate is called. The application can then recover the state from the cookie.

type CookieProtector

type CookieProtector interface {
	// NewToken creates a new token
	NewToken([]byte) ([]byte, error)
	// DecodeToken decodes a token
	DecodeToken([]byte) ([]byte, error)
}

CookieProtector is used to create and verify a cookie

func NewDefaultCookieProtector

func NewDefaultCookieProtector() (CookieProtector, error)

NewDefaultCookieProtector creates a source for source address tokens

type DecryptError

type DecryptError string

func (DecryptError) Error

func (err DecryptError) Error() string

type DefaultCookieProtector

type DefaultCookieProtector struct {
	// contains filtered or unexported fields
}

The DefaultCookieProtector is a simple implementation for the CookieProtector.

func (*DefaultCookieProtector) DecodeToken

func (s *DefaultCookieProtector) DecodeToken(p []byte) ([]byte, error)

DecodeToken decodes a token.

func (*DefaultCookieProtector) NewToken

func (s *DefaultCookieProtector) NewToken(data []byte) ([]byte, error)

NewToken encodes data into a new token.

type DefaultRecordLayer

type DefaultRecordLayer struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func NewRecordLayerDTLS

func NewRecordLayerDTLS(conn io.ReadWriter, dir Direction) *DefaultRecordLayer

func NewRecordLayerTLS

func NewRecordLayerTLS(conn io.ReadWriter, dir Direction) *DefaultRecordLayer

func (*DefaultRecordLayer) DiscardReadKey

func (r *DefaultRecordLayer) DiscardReadKey(epoch Epoch)

TODO(ekr@rtfm.com): This is never used, which is a bug.

func (*DefaultRecordLayer) Epoch

func (r *DefaultRecordLayer) Epoch() Epoch

func (*DefaultRecordLayer) Impl

func (*DefaultRecordLayer) PeekRecordType

func (r *DefaultRecordLayer) PeekRecordType(block bool) (RecordType, error)

func (*DefaultRecordLayer) ReadRecord

func (r *DefaultRecordLayer) ReadRecord() (*TLSPlaintext, error)

func (*DefaultRecordLayer) ReadRecordAnyEpoch

func (r *DefaultRecordLayer) ReadRecordAnyEpoch() (*TLSPlaintext, error)

func (*DefaultRecordLayer) Rekey

func (r *DefaultRecordLayer) Rekey(epoch Epoch, factory AEADFactory, keys *KeySet) error

func (*DefaultRecordLayer) ResetClear

func (r *DefaultRecordLayer) ResetClear(seq uint64)

func (*DefaultRecordLayer) SetLabel

func (r *DefaultRecordLayer) SetLabel(s string)

func (*DefaultRecordLayer) SetVersion

func (r *DefaultRecordLayer) SetVersion(v uint16)

func (*DefaultRecordLayer) WriteRecord

func (r *DefaultRecordLayer) WriteRecord(pt *TLSPlaintext) error

func (*DefaultRecordLayer) WriteRecordWithPadding

func (r *DefaultRecordLayer) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error

type Direction

type Direction uint8

type DtlsAck

type DtlsAck struct {
	RecordNumbers []uint64 `tls:"head=2"`
}

type EarlyDataExtension

type EarlyDataExtension struct{}

func (EarlyDataExtension) Marshal

func (ed EarlyDataExtension) Marshal() ([]byte, error)

func (EarlyDataExtension) Type

func (*EarlyDataExtension) Unmarshal

func (ed *EarlyDataExtension) Unmarshal(data []byte) (int, error)

type EncryptedExtensionsBody

type EncryptedExtensionsBody struct {
	Extensions ExtensionList `tls:"head=2"`
}
struct {
    Extension extensions<0..2^16-1>;
} EncryptedExtensions;

Marshal() and Unmarshal() are handled by ExtensionList

func (EncryptedExtensionsBody) Marshal

func (ee EncryptedExtensionsBody) Marshal() ([]byte, error)

func (EncryptedExtensionsBody) Type

func (*EncryptedExtensionsBody) Unmarshal

func (ee *EncryptedExtensionsBody) Unmarshal(data []byte) (int, error)

type EndOfEarlyDataBody

type EndOfEarlyDataBody struct{}

struct {} EndOfEarlyData;

func (EndOfEarlyDataBody) Marshal

func (eoed EndOfEarlyDataBody) Marshal() ([]byte, error)

func (EndOfEarlyDataBody) Type

func (eoed EndOfEarlyDataBody) Type() HandshakeType

func (*EndOfEarlyDataBody) Unmarshal

func (eoed *EndOfEarlyDataBody) Unmarshal(data []byte) (int, error)

type Epoch

type Epoch uint16

Epochs for DTLS (also used for key phase labelling)

const (
	EpochClear           Epoch = 0
	EpochEarlyData       Epoch = 1
	EpochHandshakeData   Epoch = 2
	EpochApplicationData Epoch = 3
	EpochUpdate          Epoch = 4
)

type Extension

type Extension struct {
	ExtensionType ExtensionType
	ExtensionData []byte `tls:"head=2"`
}
struct {
    ExtensionType extension_type;
    opaque extension_data<0..2^16-1>;
} Extension;

func (Extension) Marshal

func (ext Extension) Marshal() ([]byte, error)

func (*Extension) Unmarshal

func (ext *Extension) Unmarshal(data []byte) (int, error)

type ExtensionBody

type ExtensionBody interface {
	Type() ExtensionType
	Marshal() ([]byte, error)
	Unmarshal(data []byte) (int, error)
}

type ExtensionList

type ExtensionList []Extension

func (*ExtensionList) Add

func (el *ExtensionList) Add(src ExtensionBody) error

func (ExtensionList) Find

func (el ExtensionList) Find(dst ExtensionBody) (bool, error)

func (ExtensionList) Marshal

func (el ExtensionList) Marshal() ([]byte, error)

func (ExtensionList) Parse

func (el ExtensionList) Parse(dsts []ExtensionBody) (map[ExtensionType]bool, error)

func (*ExtensionList) Unmarshal

func (el *ExtensionList) Unmarshal(data []byte) (int, error)

type ExtensionType

type ExtensionType uint16

enum {...} ExtensionType

const (
	ExtensionTypeServerName          ExtensionType = 0
	ExtensionTypeSupportedGroups     ExtensionType = 10
	ExtensionTypeSignatureAlgorithms ExtensionType = 13
	ExtensionTypeALPN                ExtensionType = 16
	ExtensionTypeKeyShare            ExtensionType = 51
	ExtensionTypePreSharedKey        ExtensionType = 41
	ExtensionTypeEarlyData           ExtensionType = 42
	ExtensionTypeSupportedVersions   ExtensionType = 43
	ExtensionTypeCookie              ExtensionType = 44
	ExtensionTypePSKKeyExchangeModes ExtensionType = 45
	ExtensionTypeTicketEarlyDataInfo ExtensionType = 46
)

type FinishedBody

type FinishedBody struct {
	VerifyDataLen int
	VerifyData    []byte
}
struct {
    opaque verify_data[verify_data_length];
} Finished;

verifyDataLen is not a field in the TLS struct, but we add it here so that calling code can tell us how much data to expect when we marshal / unmarshal. (We could add this to the marshal/unmarshal methods, but let's try to keep the signature consistent for now.)

For similar reasons, we don't use the `syntax` module here, because this struct doesn't map well to standard TLS presentation language concepts.

TODO: File a spec bug

func (FinishedBody) Marshal

func (fin FinishedBody) Marshal() ([]byte, error)

func (FinishedBody) Type

func (fin FinishedBody) Type() HandshakeType

func (*FinishedBody) Unmarshal

func (fin *FinishedBody) Unmarshal(data []byte) (int, error)

type HandshakeAction

type HandshakeAction interface{}

Marker interface for actions that an implementation should take based on state transitions.

type HandshakeContext

type HandshakeContext struct {
	// contains filtered or unexported fields
}

Working state for the handshake.

func (*HandshakeContext) SetVersion

func (hc *HandshakeContext) SetVersion(version uint16)

type HandshakeLayer

type HandshakeLayer struct {
	// contains filtered or unexported fields
}

func NewHandshakeLayerDTLS

func NewHandshakeLayerDTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer

func NewHandshakeLayerTLS

func NewHandshakeLayerTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer

func (*HandshakeLayer) ClearQueuedMessages

func (h *HandshakeLayer) ClearQueuedMessages()

func (*HandshakeLayer) HandshakeMessageFromBody

func (h *HandshakeLayer) HandshakeMessageFromBody(body HandshakeMessageBody) (*HandshakeMessage, error)

func (*HandshakeLayer) QueueMessage

func (h *HandshakeLayer) QueueMessage(hm *HandshakeMessage) error

func (*HandshakeLayer) ReadMessage

func (h *HandshakeLayer) ReadMessage() (*HandshakeMessage, error)

func (*HandshakeLayer) SendQueuedMessages

func (h *HandshakeLayer) SendQueuedMessages() (int, error)

func (*HandshakeLayer) WriteMessage

func (h *HandshakeLayer) WriteMessage(hm *HandshakeMessage) (int, error)

func (*HandshakeLayer) WriteMessages

func (h *HandshakeLayer) WriteMessages(hms []*HandshakeMessage) (int, error)

type HandshakeMessage

type HandshakeMessage struct {
	// contains filtered or unexported fields
}
struct {
    HandshakeType msg_type;    /* handshake type */
    uint24 length;             /* bytes in message */
    select (HandshakeType) {
      ...
    } body;
} Handshake;

We do the select{...} part in a different layer, so we treat the actual message body as opaque:

struct {
    HandshakeType msg_type;
    opaque msg<0..2^24-1>
} Handshake;

func (*HandshakeMessage) Marshal

func (hm *HandshakeMessage) Marshal() []byte

Note: This could be done with the `syntax` module, using the simplified syntax as discussed above. However, since this is so simple, there's not much benefit to doing so. When datagram is set, we marshal this as a whole DTLS record.

func (HandshakeMessage) ToBody

type HandshakeMessageBody

type HandshakeMessageBody interface {
	Type() HandshakeType
	Marshal() ([]byte, error)
	Unmarshal(data []byte) (int, error)
}

type HandshakeState

type HandshakeState interface {
	Next(handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert)
	State() State
}

type HandshakeType

type HandshakeType byte

enum {...} HandshakeType;

const (
	// Omitted: *_RESERVED
	HandshakeTypeClientHello         HandshakeType = 1
	HandshakeTypeServerHello         HandshakeType = 2
	HandshakeTypeNewSessionTicket    HandshakeType = 4
	HandshakeTypeEndOfEarlyData      HandshakeType = 5
	HandshakeTypeHelloRetryRequest   HandshakeType = 6
	HandshakeTypeEncryptedExtensions HandshakeType = 8
	HandshakeTypeCertificate         HandshakeType = 11
	HandshakeTypeCertificateRequest  HandshakeType = 13
	HandshakeTypeCertificateVerify   HandshakeType = 15
	HandshakeTypeServerConfiguration HandshakeType = 17
	HandshakeTypeFinished            HandshakeType = 20
	HandshakeTypeKeyUpdate           HandshakeType = 24
	HandshakeTypeMessageHash         HandshakeType = 254
)

type KeySet

type KeySet struct {
	Cipher AEADFactory
	Keys   map[string][]byte
}

type KeyShareClientHelloInner

type KeyShareClientHelloInner struct {
	ClientShares []KeyShareEntry `tls:"head=2,min=0"`
}

type KeyShareEntry

type KeyShareEntry struct {
	Group       NamedGroup
	KeyExchange []byte `tls:"head=2,min=1"`
}
struct {
    NamedGroup group;
    opaque key_exchange<1..2^16-1>;
} KeyShareEntry;
struct {
    select (Handshake.msg_type) {
        case client_hello:
            KeyShareEntry client_shares<0..2^16-1>;

        case hello_retry_request:
            NamedGroup selected_group;

        case server_hello:
            KeyShareEntry server_share;
    };
} KeyShare;

func (KeyShareEntry) SizeValid

func (kse KeyShareEntry) SizeValid() bool

type KeyShareExtension

type KeyShareExtension struct {
	HandshakeType HandshakeType
	SelectedGroup NamedGroup
	Shares        []KeyShareEntry
}

func (KeyShareExtension) Marshal

func (ks KeyShareExtension) Marshal() ([]byte, error)

func (KeyShareExtension) Type

func (ks KeyShareExtension) Type() ExtensionType

func (*KeyShareExtension) Unmarshal

func (ks *KeyShareExtension) Unmarshal(data []byte) (int, error)

type KeyShareHelloRetryInner

type KeyShareHelloRetryInner struct {
	SelectedGroup NamedGroup
}

type KeyShareServerHelloInner

type KeyShareServerHelloInner struct {
	ServerShare KeyShareEntry
}

type KeyUpdateBody

type KeyUpdateBody struct {
	KeyUpdateRequest KeyUpdateRequest
}
enum {
    update_not_requested(0), update_requested(1), (255)
} KeyUpdateRequest;
struct {
    KeyUpdateRequest request_update;
} KeyUpdate;

func (KeyUpdateBody) Marshal

func (ku KeyUpdateBody) Marshal() ([]byte, error)

func (KeyUpdateBody) Type

func (ku KeyUpdateBody) Type() HandshakeType

func (*KeyUpdateBody) Unmarshal

func (ku *KeyUpdateBody) Unmarshal(data []byte) (int, error)

type KeyUpdateRequest

type KeyUpdateRequest uint8
enum {
    update_not_requested(0), update_requested(1), (255)
} KeyUpdateRequest;
const (
	KeyUpdateNotRequested KeyUpdateRequest = 0
	KeyUpdateRequested    KeyUpdateRequest = 1
)

type Listener

type Listener struct {
	net.Listener
	// contains filtered or unexported fields
}

A listener implements a network listener (net.Listener) for TLS connections.

func (*Listener) Accept

func (l *Listener) Accept() (c net.Conn, err error)

Accept waits for and returns the next incoming TLS connection. The returned connection c is a *tls.Conn.

type NamedGroup

type NamedGroup uint16

enum {...} NamedGroup

const (
	// Elliptic Curve Groups.
	P256 NamedGroup = 23
	P384 NamedGroup = 24
	P521 NamedGroup = 25
	// ECDH functions.
	X25519 NamedGroup = 29
	X448   NamedGroup = 30
	// Finite field groups.
	FFDHE2048 NamedGroup = 256
	FFDHE3072 NamedGroup = 257
	FFDHE4096 NamedGroup = 258
	FFDHE6144 NamedGroup = 259
	FFDHE8192 NamedGroup = 260
)

func DHNegotiation

func DHNegotiation(keyShares []KeyShareEntry, groups []NamedGroup) (bool, NamedGroup, []byte, []byte)

type NewSessionTicketBody

type NewSessionTicketBody struct {
	TicketLifetime uint32
	TicketAgeAdd   uint32
	TicketNonce    []byte        `tls:"head=1"`
	Ticket         []byte        `tls:"head=2,min=1"`
	Extensions     ExtensionList `tls:"head=2"`
}
struct {
    uint32 ticket_lifetime;
    uint32 ticket_age_add;
		 opaque ticket_nonce<1..255>;
    opaque ticket<1..2^16-1>;
    Extension extensions<0..2^16-2>;
} NewSessionTicket;

func NewSessionTicket

func NewSessionTicket(ticketLen int, ticketLifetime uint32) (*NewSessionTicketBody, error)

func (NewSessionTicketBody) Marshal

func (tkt NewSessionTicketBody) Marshal() ([]byte, error)

func (NewSessionTicketBody) Type

func (*NewSessionTicketBody) Unmarshal

func (tkt *NewSessionTicketBody) Unmarshal(data []byte) (int, error)

type PSKBinderEntry

type PSKBinderEntry struct {
	Binder []byte `tls:"head=1,min=32"`
}

type PSKIdentity

type PSKIdentity struct {
	Identity            []byte `tls:"head=2,min=1"`
	ObfuscatedTicketAge uint32
}
struct {
    opaque identity<1..2^16-1>;
    uint32 obfuscated_ticket_age;
} PskIdentity;

opaque PskBinderEntry<32..255>;

struct {
    select (Handshake.msg_type) {
        case client_hello:
            PskIdentity identities<7..2^16-1>;
            PskBinderEntry binders<33..2^16-1>;

        case server_hello:
            uint16 selected_identity;
    };

} PreSharedKeyExtension;

type PSKKeyExchangeMode

type PSKKeyExchangeMode uint8

enum {...} PskKeyExchangeMode;

const (
	PSKModeKE    PSKKeyExchangeMode = 0
	PSKModeDHEKE PSKKeyExchangeMode = 1
)

type PSKKeyExchangeModesExtension

type PSKKeyExchangeModesExtension struct {
	KEModes []PSKKeyExchangeMode `tls:"head=1,min=1"`
}

enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;

struct {
    PskKeyExchangeMode ke_modes<1..255>;
} PskKeyExchangeModes;

func (PSKKeyExchangeModesExtension) Marshal

func (pkem PSKKeyExchangeModesExtension) Marshal() ([]byte, error)

func (PSKKeyExchangeModesExtension) Type

func (*PSKKeyExchangeModesExtension) Unmarshal

func (pkem *PSKKeyExchangeModesExtension) Unmarshal(data []byte) (int, error)

type PSKMapCache

type PSKMapCache map[string]PreSharedKey

func (PSKMapCache) Get

func (cache PSKMapCache) Get(key string) (psk PreSharedKey, ok bool)

func (*PSKMapCache) Put

func (cache *PSKMapCache) Put(key string, psk PreSharedKey)

func (PSKMapCache) Size

func (cache PSKMapCache) Size() int

type PreSharedKey

type PreSharedKey struct {
	CipherSuite  CipherSuite
	IsResumption bool
	Identity     []byte
	Key          []byte
	NextProto    string
	ReceivedAt   time.Time
	ExpiresAt    time.Time
	TicketAgeAdd uint32
}

type PreSharedKeyCache

type PreSharedKeyCache interface {
	Get(string) (PreSharedKey, bool)
	Put(string, PreSharedKey)
	Size() int
}

type PreSharedKeyExtension

type PreSharedKeyExtension struct {
	HandshakeType    HandshakeType
	Identities       []PSKIdentity
	Binders          []PSKBinderEntry
	SelectedIdentity uint16
}

func (PreSharedKeyExtension) HasIdentity

func (psk PreSharedKeyExtension) HasIdentity(id []byte) ([]byte, bool)

func (PreSharedKeyExtension) Marshal

func (psk PreSharedKeyExtension) Marshal() ([]byte, error)

func (PreSharedKeyExtension) Type

func (*PreSharedKeyExtension) Unmarshal

func (psk *PreSharedKeyExtension) Unmarshal(data []byte) (int, error)

type QueueHandshakeMessage

type QueueHandshakeMessage struct {
	Message *HandshakeMessage
}

type RecordLayer

type RecordLayer interface {
	Lock()
	Unlock()
	SetVersion(v uint16)
	SetLabel(s string)
	Rekey(epoch Epoch, factory AEADFactory, keys *KeySet) error
	ResetClear(seq uint64)
	DiscardReadKey(epoch Epoch)
	PeekRecordType(block bool) (RecordType, error)
	ReadRecord() (*TLSPlaintext, error)
	WriteRecord(pt *TLSPlaintext) error
	Epoch() Epoch
}

type RecordLayerFactory

type RecordLayerFactory interface {
	NewLayer(conn io.ReadWriter, dir Direction) RecordLayer
}

type RecordType

type RecordType byte

enum {...} ContentType;

const (
	RecordTypeAlert           RecordType = 21
	RecordTypeHandshake       RecordType = 22
	RecordTypeApplicationData RecordType = 23
	RecordTypeAck             RecordType = 25
)

type RekeyIn

type RekeyIn struct {
	KeySet KeySet
	// contains filtered or unexported fields
}

type RekeyOut

type RekeyOut struct {
	KeySet KeySet
	// contains filtered or unexported fields
}

type ResetOut

type ResetOut struct {
	// contains filtered or unexported fields
}

type SendEarlyData

type SendEarlyData struct{}

type SendQueuedHandshake

type SendQueuedHandshake struct{}

type SentHandshakeFragment

type SentHandshakeFragment struct {
	// contains filtered or unexported fields
}

type ServerHelloBody

type ServerHelloBody struct {
	Version                 uint16
	Random                  [32]byte
	LegacySessionID         []byte `tls:"head=1,max=32"`
	CipherSuite             CipherSuite
	LegacyCompressionMethod uint8
	Extensions              ExtensionList `tls:"head=2"`
}
struct {
    ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */
    Random random;
    opaque legacy_session_id_echo<0..32>;
    CipherSuite cipher_suite;
    uint8 legacy_compression_method = 0;
    Extension extensions<6..2^16-1>;
} ServerHello;

func (ServerHelloBody) Marshal

func (sh ServerHelloBody) Marshal() ([]byte, error)

func (ServerHelloBody) Type

func (sh ServerHelloBody) Type() HandshakeType

func (*ServerHelloBody) Unmarshal

func (sh *ServerHelloBody) Unmarshal(data []byte) (int, error)

type ServerNameExtension

type ServerNameExtension string
struct {
    NameType name_type;
    select (name_type) {
        case host_name: HostName;
    } name;
} ServerName;
enum {
    host_name(0), (255)
} NameType;

opaque HostName<1..2^16-1>;

struct {
    ServerName server_name_list<1..2^16-1>
} ServerNameList;

But we only care about the case where there's a single DNS hostname. We will never create anything else, and throw if we receive something else

2         1          2

| listLen | NameType | nameLen | name |

func (ServerNameExtension) Marshal

func (sni ServerNameExtension) Marshal() ([]byte, error)

func (ServerNameExtension) Type

func (*ServerNameExtension) Unmarshal

func (sni *ServerNameExtension) Unmarshal(data []byte) (int, error)

type SignatureAlgorithmsExtension

type SignatureAlgorithmsExtension struct {
	Algorithms []SignatureScheme `tls:"head=2,min=2"`
}
struct {
  SignatureScheme supported_signature_algorithms<2..2^16-2>;
} SignatureSchemeList

func (SignatureAlgorithmsExtension) Marshal

func (sa SignatureAlgorithmsExtension) Marshal() ([]byte, error)

func (SignatureAlgorithmsExtension) Type

func (*SignatureAlgorithmsExtension) Unmarshal

func (sa *SignatureAlgorithmsExtension) Unmarshal(data []byte) (int, error)

type SignatureScheme

type SignatureScheme uint16

enum {...} SignatureScheme

const (
	// RSASSA-PKCS1-v1_5 algorithms
	RSA_PKCS1_SHA1   SignatureScheme = 0x0201
	RSA_PKCS1_SHA256 SignatureScheme = 0x0401
	RSA_PKCS1_SHA384 SignatureScheme = 0x0501
	RSA_PKCS1_SHA512 SignatureScheme = 0x0601
	// ECDSA algorithms
	ECDSA_P256_SHA256 SignatureScheme = 0x0403
	ECDSA_P384_SHA384 SignatureScheme = 0x0503
	ECDSA_P521_SHA512 SignatureScheme = 0x0603
	// RSASSA-PSS algorithms
	RSA_PSS_SHA256 SignatureScheme = 0x0804
	RSA_PSS_SHA384 SignatureScheme = 0x0805
	RSA_PSS_SHA512 SignatureScheme = 0x0806
	// EdDSA algorithms
	Ed25519 SignatureScheme = 0x0807
	Ed448   SignatureScheme = 0x0808
)

type State

type State uint8
const (
	StateInit = 0

	// states valid for the client
	StateClientStart State = iota
	StateClientWaitSH
	StateClientWaitEE
	StateClientWaitCert
	StateClientWaitCV
	StateClientWaitFinished
	StateClientWaitCertCR
	StateClientConnected
	// states valid for the server
	StateServerStart State = iota
	StateServerRecvdCH
	StateServerNegotiated
	StateServerReadPastEarlyData
	StateServerWaitEOED
	StateServerWaitFlight2
	StateServerWaitCert
	StateServerWaitCV
	StateServerWaitFinished
	StateServerConnected
)

func (State) String

func (s State) String() string

type StorePSK

type StorePSK struct {
	PSK PreSharedKey
}

type SupportedGroupsExtension

type SupportedGroupsExtension struct {
	Groups []NamedGroup `tls:"head=2,min=2"`
}
struct {
    NamedGroup named_group_list<2..2^16-1>;
} NamedGroupList;

func (SupportedGroupsExtension) Marshal

func (sg SupportedGroupsExtension) Marshal() ([]byte, error)

func (SupportedGroupsExtension) Type

func (*SupportedGroupsExtension) Unmarshal

func (sg *SupportedGroupsExtension) Unmarshal(data []byte) (int, error)

type SupportedVersionsClientHelloInner

type SupportedVersionsClientHelloInner struct {
	Versions []uint16 `tls:"head=1,min=2,max=254"`
}

type SupportedVersionsExtension

type SupportedVersionsExtension struct {
	HandshakeType HandshakeType
	Versions      []uint16
}
struct {
    ProtocolVersion versions<2..254>;
} SupportedVersions;

func (SupportedVersionsExtension) Marshal

func (sv SupportedVersionsExtension) Marshal() ([]byte, error)

func (SupportedVersionsExtension) Type

func (*SupportedVersionsExtension) Unmarshal

func (sv *SupportedVersionsExtension) Unmarshal(data []byte) (int, error)

type SupportedVersionsServerHelloInner

type SupportedVersionsServerHelloInner struct {
	Version uint16
}

type TLSPlaintext

type TLSPlaintext struct {
	// contains filtered or unexported fields
}
struct {
    ContentType type;
    ProtocolVersion record_version [0301 for CH, 0303 for others]
    uint16 length;
    opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

func NewTLSPlaintext

func NewTLSPlaintext(ct RecordType, epoch Epoch, fragment []byte) *TLSPlaintext

func (TLSPlaintext) Fragment

func (t TLSPlaintext) Fragment() []byte

type TicketEarlyDataInfoExtension

type TicketEarlyDataInfoExtension struct {
	MaxEarlyDataSize uint32
}

func (TicketEarlyDataInfoExtension) Marshal

func (tedi TicketEarlyDataInfoExtension) Marshal() ([]byte, error)

func (TicketEarlyDataInfoExtension) Type

func (*TicketEarlyDataInfoExtension) Unmarshal

func (tedi *TicketEarlyDataInfoExtension) Unmarshal(data []byte) (int, error)

type TimeoutError

type TimeoutError struct{}

func (TimeoutError) Error

func (TimeoutError) Error() string

func (TimeoutError) Temporary

func (TimeoutError) Temporary() bool

func (TimeoutError) Timeout

func (TimeoutError) Timeout() bool

Directories

Path Synopsis
bin

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL