diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index 42a0c4e9..cb48ac0b 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -359,6 +359,12 @@ func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { case <-h.handshakeErrChan: return false } + // get the handshake write key + select { + case <-h.receivedWriteKey: + case <-h.handshakeErrChan: + return false + } return true case typeEncryptedExtensions: select { @@ -372,12 +378,6 @@ func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { // nothing to do return false case typeFinished: - // get the handshake write key - select { - case <-h.receivedWriteKey: - case <-h.handshakeErrChan: - return false - } // While the order of these two is not defined by the TLS spec, // we have to do it on the same order as our TLS library does it. // get the handshake write key diff --git a/vendor/github.com/marten-seemann/qtls/13.go b/vendor/github.com/marten-seemann/qtls/13.go index 6ba7b0fd..90ae05d8 100644 --- a/vendor/github.com/marten-seemann/qtls/13.go +++ b/vendor/github.com/marten-seemann/qtls/13.go @@ -116,9 +116,9 @@ func (ks *keySchedule13) setSecret(secret []byte) { salt := ks.secret if salt != nil { h0 := hash.New().Sum(nil) - salt = HkdfExpandLabel(hash, salt, h0, "derived", hash.Size()) + salt = hkdfExpandLabel(hash, salt, h0, "derived", hash.Size()) } - ks.secret = HkdfExtract(hash, secret, salt) + ks.secret = hkdfExtract(hash, secret, salt) } // Depending on role returns pair of key variant to be used by @@ -168,7 +168,7 @@ func (ks *keySchedule13) deriveSecret(secretLabel secretLabel) []byte { ks.handshakeCtx = ks.transcriptHash.Sum(nil) } hash := hashForSuite(ks.suite) - secret := HkdfExpandLabel(hash, ks.secret, ks.handshakeCtx, label, hash.Size()) + secret := hkdfExpandLabel(hash, ks.secret, ks.handshakeCtx, label, hash.Size()) if keylogType != "" && ks.config != nil { ks.config.writeKeyLog(keylogType, ks.clientRandom, secret) } @@ -177,8 +177,8 @@ func (ks *keySchedule13) deriveSecret(secretLabel secretLabel) []byte { func (ks *keySchedule13) prepareCipher(trafficSecret []byte) cipher.AEAD { hash := hashForSuite(ks.suite) - key := HkdfExpandLabel(hash, trafficSecret, nil, "key", ks.suite.keyLen) - iv := HkdfExpandLabel(hash, trafficSecret, nil, "iv", ks.suite.ivLen) + key := hkdfExpandLabel(hash, trafficSecret, nil, "key", ks.suite.keyLen) + iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", ks.suite.ivLen) return ks.suite.aead(key, iv) } @@ -254,10 +254,11 @@ CurvePreferenceLoop: hs.keySchedule.setSecret(ecdheSecret) hs.hsClientTrafficSecret = hs.keySchedule.deriveSecret(secretHandshakeClient) hsServerTrafficSecret := hs.keySchedule.deriveSecret(secretHandshakeServer) + c.out.exportKey(hs.keySchedule.suite, hsServerTrafficSecret) c.out.setKey(c.vers, hs.keySchedule.suite, hsServerTrafficSecret) - serverFinishedKey := HkdfExpandLabel(hash, hsServerTrafficSecret, nil, "finished", hashSize) - hs.clientFinishedKey = HkdfExpandLabel(hash, hs.hsClientTrafficSecret, nil, "finished", hashSize) + serverFinishedKey := hkdfExpandLabel(hash, hsServerTrafficSecret, nil, "finished", hashSize) + hs.clientFinishedKey = hkdfExpandLabel(hash, hs.hsClientTrafficSecret, nil, "finished", hashSize) // EncryptedExtensions hs.keySchedule.write(hs.hello13Enc.marshal()) @@ -296,6 +297,7 @@ CurvePreferenceLoop: hs.keySchedule.setSecret(nil) // derive master secret serverAppTrafficSecret := hs.keySchedule.deriveSecret(secretApplicationServer) + c.out.exportKey(hs.keySchedule.suite, serverAppTrafficSecret) c.out.setKey(c.vers, hs.keySchedule.suite, serverAppTrafficSecret) if c.hand.Len() > 0 { @@ -303,9 +305,11 @@ CurvePreferenceLoop: } hs.appClientTrafficSecret = hs.keySchedule.deriveSecret(secretApplicationClient) if hs.hello13Enc.earlyData { + c.in.exportKey(hs.keySchedule.suite, earlyClientTrafficSecret) c.in.setKey(c.vers, hs.keySchedule.suite, earlyClientTrafficSecret) c.phase = readingEarlyData } else { + c.in.exportKey(hs.keySchedule.suite, hs.hsClientTrafficSecret) c.in.setKey(c.vers, hs.keySchedule.suite, hs.hsClientTrafficSecret) if hs.clientHello.earlyData { c.phase = discardingEarlyData @@ -418,6 +422,7 @@ func (hs *serverHandshakeState) readClientFinished13(hasConfirmLock bool) error if c.hand.Len() > 0 { return c.sendAlert(alertUnexpectedMessage) } + c.in.exportKey(hs.keySchedule.suite, hs.appClientTrafficSecret) c.in.setKey(c.vers, hs.keySchedule.suite, hs.appClientTrafficSecret) c.in.traceErr, c.out.traceErr = nil, nil c.phase = handshakeConfirmed @@ -514,6 +519,7 @@ func (c *Conn) handleEndOfEarlyData() error { } c.hs.keySchedule.write(endOfEarlyData.marshal()) c.phase = waitingClientFinished + c.in.exportKey(c.hs.keySchedule.suite, c.hs.hsClientTrafficSecret) c.in.setKey(c.vers, c.hs.keySchedule.suite, c.hs.hsClientTrafficSecret) return nil } @@ -618,6 +624,10 @@ func (c *Conn) deriveDHESecret(ks keyShare, secretKey []byte) []byte { // HkdfExpandLabel HKDF expands a label func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte { + return hkdfExpandLabel(hash, secret, hashValue, label, L) +} + +func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte { prefix := "tls13 " hkdfLabel := make([]byte, 4+len(prefix)+len(label)+len(hashValue)) hkdfLabel[0] = byte(L >> 8) @@ -710,7 +720,7 @@ func (hs *serverHandshakeState) checkPSK() (isResumed bool, alert alert) { hs.keySchedule.setSecret(s.pskSecret) binderKey := hs.keySchedule.deriveSecret(secretResumptionPskBinder) - binderFinishedKey := HkdfExpandLabel(hash, binderKey, nil, "finished", hashSize) + binderFinishedKey := hkdfExpandLabel(hash, binderKey, nil, "finished", hashSize) chHash := hash.New() chHash.Write(hs.clientHello.rawTruncated) expectedBinder := hmacOfSum(hash, chHash, binderFinishedKey) @@ -781,7 +791,7 @@ func (hs *serverHandshakeState) sendSessionTicket13() error { // tickets might have the same PSK which could be a problem if // one of them is compromised. ticketNonce := []byte{byte(i)} - sessionState.pskSecret = HkdfExpandLabel(hash, resumptionMasterSecret, ticketNonce, "resumption", hash.Size()) + sessionState.pskSecret = hkdfExpandLabel(hash, resumptionMasterSecret, ticketNonce, "resumption", hash.Size()) ticket := sessionState.marshal() var err error if c.config.SessionTicketSealer != nil { @@ -1006,13 +1016,17 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.sendAlert(alertUnexpectedMessage) return errors.New("tls: unexpected data after Server Hello") } - // Do not change the sender key yet, the server must authenticate first. serverHandshakeSecret := hs.keySchedule.deriveSecret(secretHandshakeServer) + c.in.exportKey(hs.keySchedule.suite, serverHandshakeSecret) + // Already the sender key yet, when using an alternative record layer. + // QUIC needs the handshake write key in order to acknowlege Handshake packets. + c.out.exportKey(hs.keySchedule.suite, clientHandshakeSecret) + // Do not change the sender key yet, the server must authenticate first. c.in.setKey(c.vers, hs.keySchedule.suite, serverHandshakeSecret) // Calculate MAC key for Finished messages. - serverFinishedKey := HkdfExpandLabel(hash, serverHandshakeSecret, nil, "finished", hashSize) - clientFinishedKey := HkdfExpandLabel(hash, clientHandshakeSecret, nil, "finished", hashSize) + serverFinishedKey := hkdfExpandLabel(hash, serverHandshakeSecret, nil, "finished", hashSize) + clientFinishedKey := hkdfExpandLabel(hash, clientHandshakeSecret, nil, "finished", hashSize) msg, err := c.readHandshake() if err != nil { @@ -1155,11 +1169,13 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // Handshake done, set application traffic secret // TODO store initial traffic secret key for KeyUpdate GH #85 + c.out.exportKey(hs.keySchedule.suite, clientAppTrafficSecret) c.out.setKey(c.vers, hs.keySchedule.suite, clientAppTrafficSecret) if c.hand.Len() > 0 { c.sendAlert(alertUnexpectedMessage) return errors.New("tls: unexpected data after handshake") } + c.in.exportKey(hs.keySchedule.suite, serverAppTrafficSecret) c.in.setKey(c.vers, hs.keySchedule.suite, serverAppTrafficSecret) return nil } diff --git a/vendor/github.com/marten-seemann/qtls/conn.go b/vendor/github.com/marten-seemann/qtls/conn.go index 07f36895..66931539 100644 --- a/vendor/github.com/marten-seemann/qtls/conn.go +++ b/vendor/github.com/marten-seemann/qtls/conn.go @@ -234,15 +234,20 @@ func (hc *halfConn) changeCipherSpec() error { return nil } -func (hc *halfConn) setKey(version uint16, suite *cipherSuite, trafficSecret []byte) { +func (hc *halfConn) exportKey(suite *cipherSuite, trafficSecret []byte) { if hc.setKeyCallback != nil { hc.setKeyCallback(&CipherSuite{*suite}, trafficSecret) + } +} + +func (hc *halfConn) setKey(version uint16, suite *cipherSuite, trafficSecret []byte) { + if hc.setKeyCallback != nil { return } hc.version = version hash := hashForSuite(suite) - key := HkdfExpandLabel(hash, trafficSecret, nil, "key", suite.keyLen) - iv := HkdfExpandLabel(hash, trafficSecret, nil, "iv", suite.ivLen) + key := hkdfExpandLabel(hash, trafficSecret, nil, "key", suite.keyLen) + iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", suite.ivLen) hc.cipher = suite.aead(key, iv) for i := range hc.seq { hc.seq[i] = 0 diff --git a/vendor/github.com/marten-seemann/qtls/hkdf.go b/vendor/github.com/marten-seemann/qtls/hkdf.go index bc91e47d..456de3f7 100644 --- a/vendor/github.com/marten-seemann/qtls/hkdf.go +++ b/vendor/github.com/marten-seemann/qtls/hkdf.go @@ -47,6 +47,10 @@ func hkdfExpand(hash crypto.Hash, prk, info []byte, l int) []byte { // HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt. func HkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { + return hkdfExtract(hash, secret, salt) +} + +func hkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { if salt == nil { salt = make([]byte, hash.Size()) } diff --git a/vendor/vendor.json b/vendor/vendor.json index d6691a77..9a41e95d 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -45,10 +45,10 @@ "revisionTime": "2018-11-11T22:04:28Z" }, { - "checksumSHA1": "dpjM/eonkDPExO4QWg4+R0wZPCs=", + "checksumSHA1": "9D0GoLWn+P00plU66qfLxFB1kNg=", "path": "github.com/marten-seemann/qtls", - "revision": "26b223ad36d4436ed3eeb843041b66ac21dcee34", - "revisionTime": "2019-01-06T03:45:47Z" + "revision": "646330209b76bfdcdc054a863468f473e9d0a7af", + "revisionTime": "2019-01-10T16:28:36Z" }, { "checksumSHA1": "9TPZ7plxFmlYtMEv2LLXRCEQg7c=",