tris: add new key schedule implementation

In order to reduce repetitive complexity (extract handshake context,
pass the right secrets around to calculate a secret and build a cipher),
create a new type that tracks the hash type, the handshake context and
intermediate secrets.

Advantages: facilitates reuse between client and server code, makes it
easier to update labels for draft-19, makes it easier to add central
KeyLogWriter functionality.
This commit is contained in:
Peter Wu 2017-09-18 15:55:55 +01:00
parent 079992e500
commit 9f9f06de80

78
13.go
View File

@ -28,6 +28,84 @@ import (
// server sends to a TLS 1.3 client, who will use each only once. // server sends to a TLS 1.3 client, who will use each only once.
const numSessionTickets = 2 const numSessionTickets = 2
type secretLabel int
const (
secretResumptionPskBinder secretLabel = iota
secretEarlyClient
secretHandshakeClient
secretHandshakeServer
secretApplicationClient
secretApplicationServer
secretResumption
)
type keySchedule13 struct {
suite *cipherSuite
transcriptHash hash.Hash // uses the cipher suite hash algo
secret []byte // Current secret as used for Derive-Secret
handshakeCtx []byte // cached handshake context, invalidated on updates.
}
func newKeySchedule13(suite *cipherSuite) *keySchedule13 {
return &keySchedule13{
suite: suite,
transcriptHash: hashForSuite(suite).New(),
}
}
// setSecret sets the early/handshake/master secret based on the given secret
// (IKM). The salt is based on previous secrets (nil for the early secret).
func (ks *keySchedule13) setSecret(secret []byte) {
hash := hashForSuite(ks.suite)
salt := ks.secret
ks.secret = hkdfExtract(hash, secret, salt)
}
// write appends the data to the transcript hash context.
func (ks *keySchedule13) write(data []byte) {
ks.handshakeCtx = nil
ks.transcriptHash.Write(data)
}
func (ks *keySchedule13) getLabel(secretLabel secretLabel) (label string) {
switch secretLabel {
case secretResumptionPskBinder:
label = "resumption psk binder key"
case secretEarlyClient:
label = "client early traffic secret"
case secretHandshakeClient:
label = "client handshake traffic secret"
case secretHandshakeServer:
label = "server handshake traffic secret"
case secretApplicationClient:
label = "client application traffic secret"
case secretApplicationServer:
label = "server application traffic secret"
case secretResumption:
label = "resumption master secret"
}
return
}
// deriveSecret returns the secret derived from the handshake context and label.
func (ks *keySchedule13) deriveSecret(secretLabel secretLabel) []byte {
label := ks.getLabel(secretLabel)
if ks.handshakeCtx == nil {
ks.handshakeCtx = ks.transcriptHash.Sum(nil)
}
hash := hashForSuite(ks.suite)
return hkdfExpandLabel(hash, ks.secret, ks.handshakeCtx, label, hash.Size())
}
func (ks *keySchedule13) prepareCipher(secretLabel secretLabel) (interface{}, []byte) {
trafficSecret := ks.deriveSecret(secretLabel)
hash := hashForSuite(ks.suite)
key := hkdfExpandLabel(hash, trafficSecret, nil, "key", ks.suite.keyLen)
iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", 12)
return ks.suite.aead(key, iv), trafficSecret
}
func (hs *serverHandshakeState) doTLS13Handshake() error { func (hs *serverHandshakeState) doTLS13Handshake() error {
config := hs.c.config config := hs.c.config
c := hs.c c := hs.c