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:
jeff
2019-03-08 18:22:30 +08:00
committed by Jeff
parent 858facd4b2
commit 4ac20ffc2b
1709 changed files with 344390 additions and 60749 deletions

View File

@@ -1,94 +0,0 @@
![A lock with a mint leaf](https://ipv.sx/mint/mint.svg)
mint - A Minimal TLS 1.3 stack
==============================
[![Build Status](https://circleci.com/gh/bifurcation/mint.svg)](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
```

View File

@@ -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,

View File

@@ -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

View File

@@ -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
}

View File

@@ -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),
}
}

View File

@@ -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) {

View File

@@ -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"`
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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())

View File

@@ -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