add service mesh controller
add service mesh metrics remove unused circle yaml fix travis misconfiguration fix travis misconfiguration fix travis misconfiguration
This commit is contained in:
94
vendor/github.com/bifurcation/mint/README.md
generated
vendored
94
vendor/github.com/bifurcation/mint/README.md
generated
vendored
@@ -1,94 +0,0 @@
|
||||

|
||||
|
||||
mint - A Minimal TLS 1.3 stack
|
||||
==============================
|
||||
|
||||
[](https://circleci.com/gh/bifurcation/mint)
|
||||
|
||||
This project is primarily a learning effort for me to understand the [TLS
|
||||
1.3](http://tlswg.github.io/tls13-spec/) 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](https://golang.org/pkg/crypto/tls/), 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](https://godoc.org/github.com/bifurcation/mint)
|
||||
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
22
vendor/github.com/bifurcation/mint/client-state-machine.go
generated
vendored
22
vendor/github.com/bifurcation/mint/client-state-machine.go
generated
vendored
@@ -89,7 +89,7 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
|
||||
logf(logTypeHandshake, "opts: %+v", state.Opts)
|
||||
|
||||
// supported_versions, supported_groups, signature_algorithms, server_name
|
||||
sv := SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello, Versions: []uint16{supportedVersion}}
|
||||
sv := SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello, Versions: []uint16{tls13Version}}
|
||||
sni := ServerNameExtension(state.Opts.ServerName)
|
||||
sg := SupportedGroupsExtension{Groups: state.Config.Groups}
|
||||
sa := SignatureAlgorithmsExtension{Algorithms: state.Config.SignatureSchemes}
|
||||
@@ -136,6 +136,15 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
|
||||
}
|
||||
}
|
||||
|
||||
if len(state.Config.PSKModes) != 0 {
|
||||
kem := &PSKKeyExchangeModesExtension{KEModes: state.Config.PSKModes}
|
||||
err = ch.Extensions.Add(kem)
|
||||
if err != nil {
|
||||
logf(logTypeHandshake, "Error adding PSKKeyExchangeModes extension: %v", err)
|
||||
return nil, nil, AlertInternalError
|
||||
}
|
||||
}
|
||||
|
||||
// Run the external extension handler.
|
||||
if state.Config.ExtensionHandler != nil {
|
||||
err := state.Config.ExtensionHandler.Send(HandshakeTypeClientHello, &ch.Extensions)
|
||||
@@ -152,7 +161,7 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
|
||||
var offeredPSK PreSharedKey
|
||||
var earlyHash crypto.Hash
|
||||
var earlySecret []byte
|
||||
var clientEarlyTrafficKeys keySet
|
||||
var clientEarlyTrafficKeys KeySet
|
||||
var clientHello *HandshakeMessage
|
||||
if key, ok := state.Config.PSKs.Get(state.Opts.ServerName); ok {
|
||||
offeredPSK = key
|
||||
@@ -190,12 +199,6 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
|
||||
logf(logTypeHandshake, "PSK selected, but no PSKModes")
|
||||
return nil, nil, AlertInternalError
|
||||
}
|
||||
kem := &PSKKeyExchangeModesExtension{KEModes: state.Config.PSKModes}
|
||||
err = ch.Extensions.Add(kem)
|
||||
if err != nil {
|
||||
logf(logTypeHandshake, "Error adding PSKKeyExchangeModes extension: %v", err)
|
||||
return nil, nil, AlertInternalError
|
||||
}
|
||||
|
||||
// Add the shim PSK extension to the ClientHello
|
||||
logf(logTypeHandshake, "Adding PSK extension with id = %x", key.Identity)
|
||||
@@ -354,7 +357,7 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
|
||||
logf(logTypeHandshake, "[ClientStateWaitSH] no supported_versions extension")
|
||||
return nil, nil, AlertMissingExtension
|
||||
}
|
||||
if supportedVersions.Versions[0] != supportedVersion {
|
||||
if supportedVersions.Versions[0] != tls13Version {
|
||||
logf(logTypeHandshake, "[ClientStateWaitSH] unsupported version [%x]", supportedVersions.Versions[0])
|
||||
return nil, nil, AlertProtocolVersion
|
||||
}
|
||||
@@ -416,6 +419,7 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
|
||||
// mode. In DTLS, we also need to bump the sequence number.
|
||||
// This is a pre-existing defect in Mint. Issue #175.
|
||||
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]")
|
||||
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
|
||||
return clientStateStart{
|
||||
Config: state.Config,
|
||||
Opts: state.Opts,
|
||||
|
||||
4
vendor/github.com/bifurcation/mint/common.go
generated
vendored
4
vendor/github.com/bifurcation/mint/common.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
supportedVersion uint16 = 0x7f16 // draft-22
|
||||
tls13Version uint16 = 0x0304
|
||||
tls12Version uint16 = 0x0303
|
||||
tls10Version uint16 = 0x0301
|
||||
dtls12WireVersion uint16 = 0xfefd
|
||||
@@ -118,7 +118,7 @@ const (
|
||||
ExtensionTypeSupportedGroups ExtensionType = 10
|
||||
ExtensionTypeSignatureAlgorithms ExtensionType = 13
|
||||
ExtensionTypeALPN ExtensionType = 16
|
||||
ExtensionTypeKeyShare ExtensionType = 40
|
||||
ExtensionTypeKeyShare ExtensionType = 51
|
||||
ExtensionTypePreSharedKey ExtensionType = 41
|
||||
ExtensionTypeEarlyData ExtensionType = 42
|
||||
ExtensionTypeSupportedVersions ExtensionType = 43
|
||||
|
||||
27
vendor/github.com/bifurcation/mint/conn.go
generated
vendored
27
vendor/github.com/bifurcation/mint/conn.go
generated
vendored
@@ -129,6 +129,8 @@ type Config struct {
|
||||
NonBlocking bool
|
||||
UseDTLS bool
|
||||
|
||||
RecordLayer RecordLayerFactory
|
||||
|
||||
// The same config object can be shared among different connections, so it
|
||||
// needs its own mutex
|
||||
mutex sync.RWMutex
|
||||
@@ -270,28 +272,33 @@ type Conn struct {
|
||||
handshakeComplete bool
|
||||
|
||||
readBuffer []byte
|
||||
in, out *RecordLayer
|
||||
in, out RecordLayer
|
||||
hsCtx *HandshakeContext
|
||||
}
|
||||
|
||||
func NewConn(conn net.Conn, config *Config, isClient bool) *Conn {
|
||||
c := &Conn{conn: conn, config: config, isClient: isClient, hsCtx: &HandshakeContext{}}
|
||||
if !config.UseDTLS {
|
||||
c.in = NewRecordLayerTLS(c.conn, directionRead)
|
||||
c.out = NewRecordLayerTLS(c.conn, directionWrite)
|
||||
if config.RecordLayer == nil {
|
||||
c.in = NewRecordLayerTLS(c.conn, DirectionRead)
|
||||
c.out = NewRecordLayerTLS(c.conn, DirectionWrite)
|
||||
} else {
|
||||
c.in = config.RecordLayer.NewLayer(c.conn, DirectionRead)
|
||||
c.out = config.RecordLayer.NewLayer(c.conn, DirectionWrite)
|
||||
}
|
||||
c.hsCtx.hIn = NewHandshakeLayerTLS(c.hsCtx, c.in)
|
||||
c.hsCtx.hOut = NewHandshakeLayerTLS(c.hsCtx, c.out)
|
||||
} else {
|
||||
c.in = NewRecordLayerDTLS(c.conn, directionRead)
|
||||
c.out = NewRecordLayerDTLS(c.conn, directionWrite)
|
||||
c.in = NewRecordLayerDTLS(c.conn, DirectionRead)
|
||||
c.out = NewRecordLayerDTLS(c.conn, DirectionWrite)
|
||||
c.hsCtx.hIn = NewHandshakeLayerDTLS(c.hsCtx, c.in)
|
||||
c.hsCtx.hOut = NewHandshakeLayerDTLS(c.hsCtx, c.out)
|
||||
c.hsCtx.timeoutMS = initialTimeout
|
||||
c.hsCtx.timers = newTimerSet()
|
||||
c.hsCtx.waitingNextFlight = true
|
||||
}
|
||||
c.in.label = c.label()
|
||||
c.out.label = c.label()
|
||||
c.in.SetLabel(c.label())
|
||||
c.out.SetLabel(c.label())
|
||||
c.hsCtx.hIn.nonblocking = c.config.NonBlocking
|
||||
return c
|
||||
}
|
||||
@@ -598,7 +605,7 @@ func (c *Conn) takeAction(actionGeneric HandshakeAction) Alert {
|
||||
logf(logTypeHandshake, "%s Rekey with data still in handshake buffers", label)
|
||||
return AlertDecodeError
|
||||
}
|
||||
err := c.in.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv)
|
||||
err := c.in.Rekey(action.epoch, action.KeySet.Cipher, &action.KeySet)
|
||||
if err != nil {
|
||||
logf(logTypeHandshake, "%s Unable to rekey inbound: %v", label, err)
|
||||
return AlertInternalError
|
||||
@@ -606,7 +613,7 @@ func (c *Conn) takeAction(actionGeneric HandshakeAction) Alert {
|
||||
|
||||
case RekeyOut:
|
||||
logf(logTypeHandshake, "%s Rekeying out to %s: %+v", label, action.epoch.label(), action.KeySet)
|
||||
err := c.out.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv)
|
||||
err := c.out.Rekey(action.epoch, action.KeySet.Cipher, &action.KeySet)
|
||||
if err != nil {
|
||||
logf(logTypeHandshake, "%s Unable to rekey outbound: %v", label, err)
|
||||
return AlertInternalError
|
||||
@@ -906,7 +913,7 @@ func (c *Conn) Writable() bool {
|
||||
}
|
||||
|
||||
// If we're a client in 0-RTT, then we're writable.
|
||||
if c.isClient && c.out.cipher.epoch == EpochEarlyData {
|
||||
if c.isClient && c.out.Epoch() == EpochEarlyData {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
28
vendor/github.com/bifurcation/mint/crypto.go
generated
vendored
28
vendor/github.com/bifurcation/mint/crypto.go
generated
vendored
@@ -27,11 +27,11 @@ import (
|
||||
|
||||
var prng = rand.Reader
|
||||
|
||||
type aeadFactory func(key []byte) (cipher.AEAD, error)
|
||||
type AeadFactory func(key []byte) (cipher.AEAD, error)
|
||||
|
||||
type CipherSuiteParams struct {
|
||||
Suite CipherSuite
|
||||
Cipher aeadFactory // Cipher factory
|
||||
Cipher AeadFactory // Cipher factory
|
||||
Hash crypto.Hash // Hash function
|
||||
KeyLen int // Key length in octets
|
||||
IvLen int // IV length in octets
|
||||
@@ -546,8 +546,10 @@ const (
|
||||
// opaque label<9..255>;
|
||||
// opaque hash_value<0..255>;
|
||||
// };
|
||||
var HkdfLabelPrefix = "tls13 "
|
||||
|
||||
func hkdfEncodeLabel(labelIn string, hashValue []byte, outLen int) []byte {
|
||||
label := "tls13 " + labelIn
|
||||
label := HkdfLabelPrefix + labelIn
|
||||
|
||||
labelLen := len(label)
|
||||
hashLen := len(hashValue)
|
||||
@@ -604,18 +606,20 @@ func computeFinishedData(params CipherSuiteParams, baseKey []byte, input []byte)
|
||||
return mac.Sum(nil)
|
||||
}
|
||||
|
||||
type keySet struct {
|
||||
cipher aeadFactory
|
||||
key []byte
|
||||
iv []byte
|
||||
type KeySet struct {
|
||||
Cipher AeadFactory
|
||||
Key []byte
|
||||
Iv []byte
|
||||
Pn []byte
|
||||
}
|
||||
|
||||
func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet {
|
||||
func makeTrafficKeys(params CipherSuiteParams, secret []byte) KeySet {
|
||||
logf(logTypeCrypto, "making traffic keys: secret=%x", secret)
|
||||
return keySet{
|
||||
cipher: params.Cipher,
|
||||
key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen),
|
||||
iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
|
||||
return KeySet{
|
||||
Cipher: params.Cipher,
|
||||
Key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen),
|
||||
Iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
|
||||
Pn: HkdfExpandLabel(params.Hash, secret, "pn", []byte{}, params.KeyLen),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
51
vendor/github.com/bifurcation/mint/handshake-layer.go
generated
vendored
51
vendor/github.com/bifurcation/mint/handshake-layer.go
generated
vendored
@@ -120,7 +120,7 @@ func (h *HandshakeLayer) HandshakeMessageFromBody(body HandshakeMessageBody) (*H
|
||||
type HandshakeLayer struct {
|
||||
ctx *HandshakeContext // The handshake we are attached to
|
||||
nonblocking bool // Should we operate in nonblocking mode
|
||||
conn *RecordLayer // Used for reading/writing records
|
||||
conn RecordLayer // Used for reading/writing records
|
||||
frame *frameReader // The buffered frame reader
|
||||
datagram bool // Is this DTLS?
|
||||
msgSeq uint32 // The DTLS message sequence number
|
||||
@@ -153,7 +153,7 @@ func (d handshakeLayerFrameDetails) frameLen(hdr []byte) (int, error) {
|
||||
return int(val), nil
|
||||
}
|
||||
|
||||
func NewHandshakeLayerTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
|
||||
func NewHandshakeLayerTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer {
|
||||
h := HandshakeLayer{}
|
||||
h.ctx = c
|
||||
h.conn = r
|
||||
@@ -163,7 +163,7 @@ func NewHandshakeLayerTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
|
||||
return &h
|
||||
}
|
||||
|
||||
func NewHandshakeLayerDTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
|
||||
func NewHandshakeLayerDTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer {
|
||||
h := HandshakeLayer{}
|
||||
h.ctx = c
|
||||
h.conn = r
|
||||
@@ -174,8 +174,15 @@ func NewHandshakeLayerDTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer
|
||||
}
|
||||
|
||||
func (h *HandshakeLayer) readRecord() error {
|
||||
logf(logTypeVerbose, "Trying to read record")
|
||||
pt, err := h.conn.readRecordAnyEpoch()
|
||||
var pt *TLSPlaintext
|
||||
var err error
|
||||
|
||||
if h.datagram {
|
||||
logf(logTypeVerbose, "Trying to read record")
|
||||
pt, err = h.conn.(*RecordLayerImpl).ReadRecordAnyEpoch()
|
||||
} else {
|
||||
pt, err = h.conn.ReadRecord()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -204,7 +211,7 @@ func (h *HandshakeLayer) readRecord() error {
|
||||
}
|
||||
|
||||
assert(h.ctx.hIn.conn != nil)
|
||||
if pt.epoch != h.ctx.hIn.conn.cipher.epoch {
|
||||
if pt.epoch != h.ctx.hIn.conn.Epoch() {
|
||||
// This is out of order but we're dropping it.
|
||||
// TODO(ekr@rtfm.com): If server, need to retransmit Finished.
|
||||
if pt.epoch == EpochClear || pt.epoch == EpochHandshakeData {
|
||||
@@ -394,9 +401,13 @@ func (h *HandshakeLayer) ReadMessage() (*HandshakeMessage, error) {
|
||||
}
|
||||
|
||||
func (h *HandshakeLayer) QueueMessage(hm *HandshakeMessage) error {
|
||||
hm.cipher = h.conn.cipher
|
||||
h.queued = append(h.queued, hm)
|
||||
return nil
|
||||
if h.datagram {
|
||||
hm.cipher = h.conn.(*RecordLayerImpl).cipher
|
||||
h.queued = append(h.queued, hm)
|
||||
return nil
|
||||
}
|
||||
_, err := h.WriteMessages([]*HandshakeMessage{hm})
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *HandshakeLayer) SendQueuedMessages() (int, error) {
|
||||
@@ -456,22 +467,30 @@ func (h *HandshakeLayer) writeFragment(hm *HandshakeMessage, start int, room int
|
||||
buf = body
|
||||
}
|
||||
|
||||
var err error
|
||||
if h.datagram {
|
||||
// Remember that we sent this.
|
||||
h.ctx.sentFragments = append(h.ctx.sentFragments, &SentHandshakeFragment{
|
||||
hm.seq,
|
||||
start,
|
||||
len(body),
|
||||
h.conn.cipher.combineSeq(true),
|
||||
h.conn.(*RecordLayerImpl).cipher.combineSeq(true),
|
||||
false,
|
||||
})
|
||||
err = h.conn.(*RecordLayerImpl).writeRecordWithPadding(
|
||||
&TLSPlaintext{
|
||||
contentType: RecordTypeHandshake,
|
||||
fragment: buf,
|
||||
},
|
||||
hm.cipher, 0)
|
||||
} else {
|
||||
err = h.conn.WriteRecord(
|
||||
&TLSPlaintext{
|
||||
contentType: RecordTypeHandshake,
|
||||
fragment: buf,
|
||||
})
|
||||
}
|
||||
return true, start + bodylen, h.conn.writeRecordWithPadding(
|
||||
&TLSPlaintext{
|
||||
contentType: RecordTypeHandshake,
|
||||
fragment: buf,
|
||||
},
|
||||
hm.cipher, 0)
|
||||
return true, start + bodylen, err
|
||||
}
|
||||
|
||||
func (h *HandshakeLayer) WriteMessage(hm *HandshakeMessage) (int, error) {
|
||||
|
||||
2
vendor/github.com/bifurcation/mint/handshake-messages.go
generated
vendored
2
vendor/github.com/bifurcation/mint/handshake-messages.go
generated
vendored
@@ -406,7 +406,7 @@ func (cr *CertificateRequestBody) Unmarshal(data []byte) (int, error) {
|
||||
type NewSessionTicketBody struct {
|
||||
TicketLifetime uint32
|
||||
TicketAgeAdd uint32
|
||||
TicketNonce []byte `tls:"head=1,min=1"`
|
||||
TicketNonce []byte `tls:"head=1"`
|
||||
Ticket []byte `tls:"head=2,min=1"`
|
||||
Extensions ExtensionList `tls:"head=2"`
|
||||
}
|
||||
|
||||
101
vendor/github.com/bifurcation/mint/mint.svg
generated
vendored
101
vendor/github.com/bifurcation/mint/mint.svg
generated
vendored
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 16 KiB |
6
vendor/github.com/bifurcation/mint/negotiation.go
generated
vendored
6
vendor/github.com/bifurcation/mint/negotiation.go
generated
vendored
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
func VersionNegotiation(offered, supported []uint16) (bool, uint16) {
|
||||
for _, offeredVersion := range offered {
|
||||
for _, supportedVersion := range supported {
|
||||
logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, supportedVersion)
|
||||
if offeredVersion == supportedVersion {
|
||||
for _, tls13Version := range supported {
|
||||
logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, tls13Version)
|
||||
if offeredVersion == tls13Version {
|
||||
// XXX: Should probably be highest supported version, but for now, we
|
||||
// only support one version, so it doesn't really matter.
|
||||
return true, offeredVersion
|
||||
|
||||
161
vendor/github.com/bifurcation/mint/record-layer.go
generated
vendored
161
vendor/github.com/bifurcation/mint/record-layer.go
generated
vendored
@@ -20,11 +20,11 @@ func (err DecryptError) Error() string {
|
||||
return string(err)
|
||||
}
|
||||
|
||||
type direction uint8
|
||||
type Direction uint8
|
||||
|
||||
const (
|
||||
directionWrite = direction(1)
|
||||
directionRead = direction(2)
|
||||
DirectionWrite = Direction(1)
|
||||
DirectionRead = Direction(2)
|
||||
)
|
||||
|
||||
// struct {
|
||||
@@ -42,6 +42,18 @@ type TLSPlaintext struct {
|
||||
fragment []byte
|
||||
}
|
||||
|
||||
func NewTLSPlaintext(ct RecordType, epoch Epoch, fragment []byte) *TLSPlaintext {
|
||||
return &TLSPlaintext{
|
||||
contentType: ct,
|
||||
epoch: epoch,
|
||||
fragment: fragment,
|
||||
}
|
||||
}
|
||||
|
||||
func (t TLSPlaintext) Fragment() []byte {
|
||||
return t.fragment
|
||||
}
|
||||
|
||||
type cipherState struct {
|
||||
epoch Epoch // DTLS epoch
|
||||
ivLength int // Length of the seq and nonce fields
|
||||
@@ -50,10 +62,28 @@ type cipherState struct {
|
||||
cipher cipher.AEAD // AEAD cipher
|
||||
}
|
||||
|
||||
type RecordLayer struct {
|
||||
type RecordLayerFactory interface {
|
||||
NewLayer(conn io.ReadWriter, dir Direction) 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 RecordLayerImpl struct {
|
||||
sync.Mutex
|
||||
label string
|
||||
direction direction
|
||||
direction Direction
|
||||
version uint16 // The current version number
|
||||
conn io.ReadWriter // The underlying connection
|
||||
frame *frameReader // The buffered frame reader
|
||||
@@ -67,6 +97,10 @@ type RecordLayer struct {
|
||||
datagram bool
|
||||
}
|
||||
|
||||
func (r *RecordLayerImpl) Impl() *RecordLayerImpl {
|
||||
return r
|
||||
}
|
||||
|
||||
type recordLayerFrameDetails struct {
|
||||
datagram bool
|
||||
}
|
||||
@@ -90,7 +124,7 @@ func newCipherStateNull() *cipherState {
|
||||
return &cipherState{EpochClear, 0, 0, nil, nil}
|
||||
}
|
||||
|
||||
func newCipherStateAead(epoch Epoch, factory aeadFactory, key []byte, iv []byte) (*cipherState, error) {
|
||||
func newCipherStateAead(epoch Epoch, factory AeadFactory, key []byte, iv []byte) (*cipherState, error) {
|
||||
cipher, err := factory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,8 +133,8 @@ func newCipherStateAead(epoch Epoch, factory aeadFactory, key []byte, iv []byte)
|
||||
return &cipherState{epoch, len(iv), 0, iv, cipher}, nil
|
||||
}
|
||||
|
||||
func NewRecordLayerTLS(conn io.ReadWriter, dir direction) *RecordLayer {
|
||||
r := RecordLayer{}
|
||||
func NewRecordLayerTLS(conn io.ReadWriter, dir Direction) *RecordLayerImpl {
|
||||
r := RecordLayerImpl{}
|
||||
r.label = ""
|
||||
r.direction = dir
|
||||
r.conn = conn
|
||||
@@ -110,8 +144,8 @@ func NewRecordLayerTLS(conn io.ReadWriter, dir direction) *RecordLayer {
|
||||
return &r
|
||||
}
|
||||
|
||||
func NewRecordLayerDTLS(conn io.ReadWriter, dir direction) *RecordLayer {
|
||||
r := RecordLayer{}
|
||||
func NewRecordLayerDTLS(conn io.ReadWriter, dir Direction) *RecordLayerImpl {
|
||||
r := RecordLayerImpl{}
|
||||
r.label = ""
|
||||
r.direction = dir
|
||||
r.conn = conn
|
||||
@@ -123,29 +157,37 @@ func NewRecordLayerDTLS(conn io.ReadWriter, dir direction) *RecordLayer {
|
||||
return &r
|
||||
}
|
||||
|
||||
func (r *RecordLayer) SetVersion(v uint16) {
|
||||
func (r *RecordLayerImpl) SetVersion(v uint16) {
|
||||
r.version = v
|
||||
}
|
||||
|
||||
func (r *RecordLayer) ResetClear(seq uint64) {
|
||||
func (r *RecordLayerImpl) ResetClear(seq uint64) {
|
||||
r.cipher = newCipherStateNull()
|
||||
r.cipher.seq = seq
|
||||
}
|
||||
|
||||
func (r *RecordLayer) Rekey(epoch Epoch, factory aeadFactory, key []byte, iv []byte) error {
|
||||
cipher, err := newCipherStateAead(epoch, factory, key, iv)
|
||||
func (r *RecordLayerImpl) Epoch() Epoch {
|
||||
return r.cipher.epoch
|
||||
}
|
||||
|
||||
func (r *RecordLayerImpl) SetLabel(s string) {
|
||||
r.label = s
|
||||
}
|
||||
|
||||
func (r *RecordLayerImpl) Rekey(epoch Epoch, factory AeadFactory, keys *KeySet) error {
|
||||
cipher, err := newCipherStateAead(epoch, factory, keys.Key, keys.Iv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.cipher = cipher
|
||||
if r.datagram && r.direction == directionRead {
|
||||
if r.datagram && r.direction == DirectionRead {
|
||||
r.readCiphers[epoch] = cipher
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(ekr@rtfm.com): This is never used, which is a bug.
|
||||
func (r *RecordLayer) DiscardReadKey(epoch Epoch) {
|
||||
func (r *RecordLayerImpl) DiscardReadKey(epoch Epoch) {
|
||||
if !r.datagram {
|
||||
return
|
||||
}
|
||||
@@ -197,34 +239,29 @@ func (c *cipherState) overhead() int {
|
||||
return c.cipher.Overhead()
|
||||
}
|
||||
|
||||
func (r *RecordLayer) encrypt(cipher *cipherState, seq uint64, pt *TLSPlaintext, padLen int) *TLSPlaintext {
|
||||
assert(r.direction == directionWrite)
|
||||
func (r *RecordLayerImpl) encrypt(cipher *cipherState, seq uint64, header []byte, pt *TLSPlaintext, padLen int) []byte {
|
||||
assert(r.direction == DirectionWrite)
|
||||
logf(logTypeIO, "%s Encrypt seq=[%x]", r.label, seq)
|
||||
// Expand the fragment to hold contentType, padding, and overhead
|
||||
originalLen := len(pt.fragment)
|
||||
plaintextLen := originalLen + 1 + padLen
|
||||
ciphertextLen := plaintextLen + cipher.overhead()
|
||||
|
||||
// Assemble the revised plaintext
|
||||
out := &TLSPlaintext{
|
||||
|
||||
contentType: RecordTypeApplicationData,
|
||||
fragment: make([]byte, ciphertextLen),
|
||||
}
|
||||
copy(out.fragment, pt.fragment)
|
||||
out.fragment[originalLen] = byte(pt.contentType)
|
||||
ciphertext := make([]byte, ciphertextLen)
|
||||
copy(ciphertext, pt.fragment)
|
||||
ciphertext[originalLen] = byte(pt.contentType)
|
||||
for i := 1; i <= padLen; i++ {
|
||||
out.fragment[originalLen+i] = 0
|
||||
ciphertext[originalLen+i] = 0
|
||||
}
|
||||
|
||||
// Encrypt the fragment
|
||||
payload := out.fragment[:plaintextLen]
|
||||
cipher.cipher.Seal(payload[:0], cipher.computeNonce(seq), payload, nil)
|
||||
return out
|
||||
payload := ciphertext[:plaintextLen]
|
||||
cipher.cipher.Seal(payload[:0], cipher.computeNonce(seq), payload, header)
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int, error) {
|
||||
assert(r.direction == directionRead)
|
||||
func (r *RecordLayerImpl) decrypt(seq uint64, header []byte, pt *TLSPlaintext) (*TLSPlaintext, int, error) {
|
||||
assert(r.direction == DirectionRead)
|
||||
logf(logTypeIO, "%s Decrypt seq=[%x]", r.label, seq)
|
||||
if len(pt.fragment) < r.cipher.overhead() {
|
||||
msg := fmt.Sprintf("tls.record.decrypt: Record too short [%d] < [%d]", len(pt.fragment), r.cipher.overhead())
|
||||
@@ -238,7 +275,7 @@ func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int,
|
||||
}
|
||||
|
||||
// Decrypt
|
||||
_, err := r.cipher.cipher.Open(out.fragment[:0], r.cipher.computeNonce(seq), pt.fragment, nil)
|
||||
_, err := r.cipher.cipher.Open(out.fragment[:0], r.cipher.computeNonce(seq), pt.fragment, header)
|
||||
if err != nil {
|
||||
logf(logTypeIO, "%s AEAD decryption failure [%x]", r.label, pt)
|
||||
return nil, 0, DecryptError("tls.record.decrypt: AEAD decrypt failed")
|
||||
@@ -259,7 +296,7 @@ func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int,
|
||||
return out, padLen, nil
|
||||
}
|
||||
|
||||
func (r *RecordLayer) PeekRecordType(block bool) (RecordType, error) {
|
||||
func (r *RecordLayerImpl) PeekRecordType(block bool) (RecordType, error) {
|
||||
var pt *TLSPlaintext
|
||||
var err error
|
||||
|
||||
@@ -275,7 +312,7 @@ func (r *RecordLayer) PeekRecordType(block bool) (RecordType, error) {
|
||||
return pt.contentType, nil
|
||||
}
|
||||
|
||||
func (r *RecordLayer) ReadRecord() (*TLSPlaintext, error) {
|
||||
func (r *RecordLayerImpl) ReadRecord() (*TLSPlaintext, error) {
|
||||
pt, err := r.nextRecord(false)
|
||||
|
||||
// Consume the cached record if there was one
|
||||
@@ -285,7 +322,7 @@ func (r *RecordLayer) ReadRecord() (*TLSPlaintext, error) {
|
||||
return pt, err
|
||||
}
|
||||
|
||||
func (r *RecordLayer) readRecordAnyEpoch() (*TLSPlaintext, error) {
|
||||
func (r *RecordLayerImpl) ReadRecordAnyEpoch() (*TLSPlaintext, error) {
|
||||
pt, err := r.nextRecord(true)
|
||||
|
||||
// Consume the cached record if there was one
|
||||
@@ -295,7 +332,7 @@ func (r *RecordLayer) readRecordAnyEpoch() (*TLSPlaintext, error) {
|
||||
return pt, err
|
||||
}
|
||||
|
||||
func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
|
||||
func (r *RecordLayerImpl) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
|
||||
cipher := r.cipher
|
||||
if r.cachedRecord != nil {
|
||||
logf(logTypeIO, "%s Returning cached record", r.label)
|
||||
@@ -391,7 +428,7 @@ func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
|
||||
|
||||
if cipher.cipher != nil {
|
||||
logf(logTypeIO, "%s RecordLayer.ReadRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), seq, pt.contentType, pt.fragment)
|
||||
pt, _, err = r.decrypt(pt, seq)
|
||||
pt, _, err = r.decrypt(seq, header, pt)
|
||||
if err != nil {
|
||||
logf(logTypeIO, "%s Decryption failed", r.label)
|
||||
return nil, err
|
||||
@@ -411,46 +448,58 @@ func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
|
||||
return pt, nil
|
||||
}
|
||||
|
||||
func (r *RecordLayer) WriteRecord(pt *TLSPlaintext) error {
|
||||
func (r *RecordLayerImpl) WriteRecord(pt *TLSPlaintext) error {
|
||||
return r.writeRecordWithPadding(pt, r.cipher, 0)
|
||||
}
|
||||
|
||||
func (r *RecordLayer) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error {
|
||||
func (r *RecordLayerImpl) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error {
|
||||
return r.writeRecordWithPadding(pt, r.cipher, padLen)
|
||||
}
|
||||
|
||||
func (r *RecordLayer) writeRecordWithPadding(pt *TLSPlaintext, cipher *cipherState, padLen int) error {
|
||||
func (r *RecordLayerImpl) writeRecordWithPadding(pt *TLSPlaintext, cipher *cipherState, padLen int) error {
|
||||
seq := cipher.combineSeq(r.datagram)
|
||||
if cipher.cipher != nil {
|
||||
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] plaintext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
|
||||
pt = r.encrypt(cipher, seq, pt, padLen)
|
||||
} else if padLen > 0 {
|
||||
return fmt.Errorf("tls.record: Padding can only be done on encrypted records")
|
||||
}
|
||||
|
||||
if len(pt.fragment) > maxFragmentLen {
|
||||
return fmt.Errorf("tls.record: Record size too big")
|
||||
}
|
||||
|
||||
length := len(pt.fragment)
|
||||
var contentType RecordType
|
||||
if cipher.cipher != nil {
|
||||
length += 1 + padLen + cipher.cipher.Overhead()
|
||||
contentType = RecordTypeApplicationData
|
||||
} else {
|
||||
contentType = pt.contentType
|
||||
}
|
||||
var header []byte
|
||||
|
||||
if !r.datagram {
|
||||
header = []byte{byte(pt.contentType),
|
||||
header = []byte{byte(contentType),
|
||||
byte(r.version >> 8), byte(r.version & 0xff),
|
||||
byte(length >> 8), byte(length)}
|
||||
} else {
|
||||
header = make([]byte, 13)
|
||||
version := dtlsConvertVersion(r.version)
|
||||
copy(header, []byte{byte(pt.contentType),
|
||||
copy(header, []byte{byte(contentType),
|
||||
byte(version >> 8), byte(version & 0xff),
|
||||
})
|
||||
encodeUint(seq, 8, header[3:])
|
||||
encodeUint(uint64(length), 2, header[11:])
|
||||
}
|
||||
record := append(header, pt.fragment...)
|
||||
|
||||
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
|
||||
var ciphertext []byte
|
||||
if cipher.cipher != nil {
|
||||
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] plaintext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
|
||||
ciphertext = r.encrypt(cipher, seq, header, pt, padLen)
|
||||
} else {
|
||||
if padLen > 0 {
|
||||
return fmt.Errorf("tls.record: Padding can only be done on encrypted records")
|
||||
}
|
||||
ciphertext = pt.fragment
|
||||
}
|
||||
|
||||
if len(ciphertext) > maxFragmentLen {
|
||||
return fmt.Errorf("tls.record: Record size too big")
|
||||
}
|
||||
|
||||
record := append(header, ciphertext...)
|
||||
|
||||
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), cipher.seq, contentType, ciphertext)
|
||||
|
||||
cipher.incrementSequenceNumber()
|
||||
_, err := r.conn.Write(record)
|
||||
|
||||
8
vendor/github.com/bifurcation/mint/server-state-machine.go
generated
vendored
8
vendor/github.com/bifurcation/mint/server-state-machine.go
generated
vendored
@@ -163,7 +163,7 @@ func (state serverStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
|
||||
logf(logTypeHandshake, "[ServerStateStart] Client did not send supported_versions")
|
||||
return nil, nil, AlertProtocolVersion
|
||||
}
|
||||
versionOK, _ := VersionNegotiation(supportedVersions.Versions, []uint16{supportedVersion})
|
||||
versionOK, _ := VersionNegotiation(supportedVersions.Versions, []uint16{tls13Version})
|
||||
if !versionOK {
|
||||
logf(logTypeHandshake, "[ServerStateStart] Client does not support the same version")
|
||||
return nil, nil, AlertProtocolVersion
|
||||
@@ -416,7 +416,7 @@ func (state *serverStateStart) generateHRR(cs CipherSuite, legacySessionId []byt
|
||||
|
||||
sv := &SupportedVersionsExtension{
|
||||
HandshakeType: HandshakeTypeServerHello,
|
||||
Versions: []uint16{supportedVersion},
|
||||
Versions: []uint16{tls13Version},
|
||||
}
|
||||
|
||||
if err := hrr.Extensions.Add(sv); err != nil {
|
||||
@@ -483,7 +483,7 @@ func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
|
||||
|
||||
err := sh.Extensions.Add(&SupportedVersionsExtension{
|
||||
HandshakeType: HandshakeTypeServerHello,
|
||||
Versions: []uint16{supportedVersion},
|
||||
Versions: []uint16{tls13Version},
|
||||
})
|
||||
if err != nil {
|
||||
logf(logTypeHandshake, "[ServerStateNegotiated] Error adding supported_versions extension [%v]", err)
|
||||
@@ -785,7 +785,7 @@ func (state serverStateWaitEOED) State() State {
|
||||
func (state serverStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
|
||||
for {
|
||||
logf(logTypeHandshake, "Server reading early data...")
|
||||
assert(state.hsCtx.hIn.conn.cipher.epoch == EpochEarlyData)
|
||||
assert(state.hsCtx.hIn.conn.Epoch() == EpochEarlyData)
|
||||
t, err := state.hsCtx.hIn.conn.PeekRecordType(!state.hsCtx.hIn.nonblocking)
|
||||
if err == AlertWouldBlock {
|
||||
return nil, nil, AlertWouldBlock
|
||||
|
||||
8
vendor/github.com/bifurcation/mint/state-machine.go
generated
vendored
8
vendor/github.com/bifurcation/mint/state-machine.go
generated
vendored
@@ -19,12 +19,12 @@ type SendEarlyData struct{}
|
||||
|
||||
type RekeyIn struct {
|
||||
epoch Epoch
|
||||
KeySet keySet
|
||||
KeySet KeySet
|
||||
}
|
||||
|
||||
type RekeyOut struct {
|
||||
epoch Epoch
|
||||
KeySet keySet
|
||||
KeySet KeySet
|
||||
}
|
||||
|
||||
type ResetOut struct {
|
||||
@@ -111,7 +111,7 @@ func (state stateConnected) State() State {
|
||||
}
|
||||
|
||||
func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
|
||||
var trafficKeys keySet
|
||||
var trafficKeys KeySet
|
||||
if state.isClient {
|
||||
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
|
||||
labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
|
||||
@@ -196,7 +196,7 @@ func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState
|
||||
|
||||
switch body := bodyGeneric.(type) {
|
||||
case *KeyUpdateBody:
|
||||
var trafficKeys keySet
|
||||
var trafficKeys KeySet
|
||||
if !state.isClient {
|
||||
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
|
||||
labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
|
||||
|
||||
84
vendor/github.com/bifurcation/mint/syntax/README.md
generated
vendored
84
vendor/github.com/bifurcation/mint/syntax/README.md
generated
vendored
@@ -1,84 +0,0 @@
|
||||
TLS Syntax
|
||||
==========
|
||||
|
||||
TLS defines [its own syntax](https://tlswg.github.io/tls13-spec/#rfc.section.3)
|
||||
for describing structures used in that protocol. To facilitate experimentation
|
||||
with TLS in Go, this module maps that syntax to the Go structure syntax, taking
|
||||
advantage of Go's type annotations to encode non-type information carried in the
|
||||
TLS presentation format.
|
||||
|
||||
For example, in the TLS specification, a ClientHello message has the following
|
||||
structure:
|
||||
|
||||
~~~~~
|
||||
uint16 ProtocolVersion;
|
||||
opaque Random[32];
|
||||
uint8 CipherSuite[2];
|
||||
enum { ... (65535)} ExtensionType;
|
||||
|
||||
struct {
|
||||
ExtensionType extension_type;
|
||||
opaque extension_data<0..2^16-1>;
|
||||
} Extension;
|
||||
|
||||
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;
|
||||
~~~~~
|
||||
|
||||
This maps to the following Go type definitions:
|
||||
|
||||
~~~~~
|
||||
type protocolVersion uint16
|
||||
type random [32]byte
|
||||
type cipherSuite uint16 // or [2]byte
|
||||
type extensionType uint16
|
||||
|
||||
type extension struct {
|
||||
ExtensionType extensionType
|
||||
ExtensionData []byte `tls:"head=2"`
|
||||
}
|
||||
|
||||
type clientHello struct {
|
||||
LegacyVersion protocolVersion
|
||||
Random random
|
||||
LegacySessionID []byte `tls:"head=1,max=32"`
|
||||
CipherSuites []cipherSuite `tls:"head=2,min=2"`
|
||||
LegacyCompressionMethods []byte `tls:"head=1,min=1"`
|
||||
Extensions []extension `tls:"head=2"`
|
||||
}
|
||||
~~~~~
|
||||
|
||||
Then you can just declare, marshal, and unmarshal structs just like you would
|
||||
with, say JSON.
|
||||
|
||||
The available annotations right now are all related to vectors:
|
||||
|
||||
* `head`: The number of bytes of length to use as a "header"
|
||||
* `min`: The minimum length of the vector, in bytes
|
||||
* `max`: The maximum length of the vector, in bytes
|
||||
|
||||
## Not supported
|
||||
|
||||
* The `select()` syntax for creating alternate version of the same struct (see,
|
||||
e.g., the KeyShare extension)
|
||||
|
||||
* The backreference syntax for array lengths or select parameters, as in `opaque
|
||||
fragment[TLSPlaintext.length]`. Note, however, that in cases where the length
|
||||
immediately preceds the array, these can be reframed as vectors with
|
||||
appropriate sizes.
|
||||
|
||||
|
||||
QUIC Extensions Syntax
|
||||
======================
|
||||
syntax also supports some minor extensions to allow implementing QUIC.
|
||||
|
||||
* The `varint` annotation describes a QUIC-style varint
|
||||
* `head=none` means no header, i.e., the bytes are encoded directly on the wire.
|
||||
On reading, the decoder will consume all available data.
|
||||
* `head=varint` means to encode the header as a varint
|
||||
Reference in New Issue
Block a user