return nil
}
+// setTrafficSecret sets the traffic secret for the given encryption level. setTrafficSecret
+// should not be called directly, but rather through the Conn setWriteTrafficSecret and
+// setReadTrafficSecret wrapper methods.
func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
hc.trafficSecret = secret
hc.level = level
return c.in.setErrorLocked(c.sendAlert(alertInternalError))
}
- newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
- c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
-
if keyUpdate.updateRequested {
c.out.Lock()
defer c.out.Unlock()
}
newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
- c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
+ c.setWriteTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
+ if err := c.setReadTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret); err != nil {
+ return err
}
return nil
// Provide the 1-RTT read secret now that the handshake is complete.
// The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
// the handshake (RFC 9001, Section 5.7).
- c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
+ if err := c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret); err != nil {
+ return err
+ }
} else {
c.out.Lock()
a, ok := errors.AsType[alert](c.out.err)
}
return c.peerCertificates[0].VerifyHostname(host)
}
+
+// setReadTrafficSecret sets the read traffic secret for the given encryption level. If
+// being called at the same time as setWriteTrafficSecret, the caller must ensure the call
+// to setWriteTrafficSecret happens first so any alerts are sent at the write level.
+func (c *Conn) setReadTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) error {
+ // Ensure that there are no buffered handshake messages before changing the
+ // read keys, since that can cause messages to be parsed that were encrypted
+ // using old keys which are no longer appropriate.
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: handshake buffer not empty before setting read traffic secret")
+ }
+ c.in.setTrafficSecret(suite, level, secret)
+ return nil
+}
+
+// setWriteTrafficSecret sets the write traffic secret for the given encryption level. If
+// being called at the same time as setReadTrafficSecret, the caller must ensure the call
+// to setWriteTrafficSecret happens first so any alerts are sent at the write level.
+func (c *Conn) setWriteTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
+ c.out.setTrafficSecret(suite, level, secret)
+}
handshakeSecret := earlySecret.HandshakeSecret(sharedKey)
clientSecret := handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
serverSecret := handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret); err != nil {
+ return err
+ }
if c.quic != nil {
- if c.hand.Len() != 0 {
- c.sendAlert(alertUnexpectedMessage)
- }
c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
- c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
+ if err := c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret); err != nil {
+ return err
+ }
}
err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret); err != nil {
+ return err
+ }
err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
if err != nil {
return err
}
- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)
}
if c.quic != nil {
- if c.hand.Len() != 0 {
- c.sendAlert(alertUnexpectedMessage)
- }
c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret)
}
return err
}
earlyTrafficSecret := hs.earlySecret.ClientEarlyTrafficSecret(transcript)
- c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret)
+ if err := c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret); err != nil {
+ return err
+ }
}
c.didResume = true
func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) (*keyShare, error) {
c := hs.c
+ // Make sure the client didn't send extra handshake messages alongside
+ // their initial client_hello. If they sent two client_hello messages,
+ // we will consume the second before they respond to the server_hello.
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, errors.New("tls: handshake buffer not empty before HelloRetryRequest")
+ }
+
// The first ClientHello gets double-hashed into the transcript upon a
// HelloRetryRequest. See RFC 8446, Section 4.4.1.
if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
}
hs.handshakeSecret = earlySecret.HandshakeSecret(hs.sharedKey)
- clientSecret := hs.handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
serverSecret := hs.handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+ clientSecret := hs.handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
+ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret); err != nil {
+ return err
+ }
if c.quic != nil {
- if c.hand.Len() != 0 {
- c.sendAlert(alertUnexpectedMessage)
- }
c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
- c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
+ if err := c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret); err != nil {
+ return err
+ }
}
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
if c.quic != nil {
- if c.hand.Len() != 0 {
- // TODO: Handle this in setTrafficSecret?
- c.sendAlert(alertUnexpectedMessage)
- }
c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret)
}
return errors.New("tls: invalid client finished hash")
}
- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret); err != nil {
+ return err
+ }
return nil
}
import (
"bufio"
"bytes"
+ "context"
"crypto/ed25519"
"crypto/x509"
"encoding/hex"
-----BEGIN TESTING KEY-----
MC4CAQAwBQYDK2VwBCIEINifzf07d9qx3d44e0FSbV4mC/xQxT644RRbpgNpin7I
-----END TESTING KEY-----`)
+
+func TestServerHelloTrailingMessage(t *testing.T) {
+ // In TLS 1.3 the change cipher spec message is optional. If a CCS message
+ // is not sent, after reading the ServerHello, the read traffic secret is
+ // set, and all following messages must be encrypted. If the server sends
+ // additional unencrypted messages in a record with the ServerHello, the
+ // client must either fail or ignore the additional messages.
+
+ c, s := localPipe(t)
+ go func() {
+ ctx := context.Background()
+ srv := Server(s, testConfig)
+ clientHello, _, err := srv.readClientHello(ctx)
+ if err != nil {
+ testFatal(t, err)
+ }
+
+ hs := serverHandshakeStateTLS13{
+ c: srv,
+ ctx: ctx,
+ clientHello: clientHello,
+ }
+ if err := hs.processClientHello(); err != nil {
+ testFatal(t, err)
+ }
+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+ testFatal(t, err)
+ }
+
+ record, err := concatHandshakeMessages(hs.hello, &encryptedExtensionsMsg{alpnProtocol: "h2"})
+ if err != nil {
+ testFatal(t, err)
+ }
+
+ if _, err := s.Write(record); err != nil {
+ testFatal(t, err)
+ }
+ srv.Close()
+ }()
+
+ cli := Client(c, testConfig)
+ expectedErr := "tls: handshake buffer not empty before setting read traffic secret"
+ if err := cli.Handshake(); err == nil {
+ t.Fatal("expected error from incomplete handshake, got nil")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("expected error %q, got %q", expectedErr, err.Error())
+ }
+}
+
+func TestClientHelloTrailingMessage(t *testing.T) {
+ // Same as TestServerHelloTrailingMessage but for the client side.
+
+ c, s := localPipe(t)
+ go func() {
+ cli := Client(c, testConfig)
+
+ hello, _, _, err := cli.makeClientHello()
+ if err != nil {
+ testFatal(t, err)
+ }
+
+ record, err := concatHandshakeMessages(hello, &certificateMsgTLS13{})
+ if err != nil {
+ testFatal(t, err)
+ }
+
+ if _, err := c.Write(record); err != nil {
+ testFatal(t, err)
+ }
+ cli.Close()
+ }()
+
+ srv := Server(s, testConfig)
+ expectedErr := "tls: handshake buffer not empty before setting read traffic secret"
+ if err := srv.Handshake(); err == nil {
+ t.Fatal("expected error from incomplete handshake, got nil")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("expected error %q, got %q", expectedErr, err.Error())
+ }
+}
+
+func TestDoubleClientHelloHRR(t *testing.T) {
+ // If a client sends two ClientHello messages in a single record, and the
+ // server sends a HRR after reading the first ClientHello, the server must
+ // either fail or ignore the trailing ClientHello.
+
+ c, s := localPipe(t)
+
+ go func() {
+ cli := Client(c, testConfig)
+
+ hello, _, _, err := cli.makeClientHello()
+ if err != nil {
+ testFatal(t, err)
+ }
+ hello.keyShares = nil
+
+ record, err := concatHandshakeMessages(hello, hello)
+ if err != nil {
+ testFatal(t, err)
+ }
+
+ if _, err := c.Write(record); err != nil {
+ testFatal(t, err)
+ }
+ cli.Close()
+ }()
+
+ srv := Server(s, testConfig)
+ expectedErr := "tls: handshake buffer not empty before HelloRetryRequest"
+ if err := srv.Handshake(); err == nil {
+ t.Fatal("expected error from incomplete handshake, got nil")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("expected error %q, got %q", expectedErr, err.Error())
+ }
+}
+
+// concatHandshakeMessages marshals and concatenates the given handshake
+// messages into a single record.
+func concatHandshakeMessages(msgs ...handshakeMessage) ([]byte, error) {
+ var marshalled []byte
+ for _, msg := range msgs {
+ data, err := msg.marshal()
+ if err != nil {
+ return nil, err
+ }
+ marshalled = append(marshalled, data...)
+ }
+ m := len(marshalled)
+ outBuf := make([]byte, recordHeaderLen)
+ outBuf[0] = byte(recordTypeHandshake)
+ vers := VersionTLS12
+ outBuf[1] = byte(vers >> 8)
+ outBuf[2] = byte(vers)
+ outBuf[3] = byte(m >> 8)
+ outBuf[4] = byte(m)
+ outBuf = append(outBuf, marshalled...)
+ return outBuf, nil
+}
return nil
}
-func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) error {
+ // Ensure that there are no buffered handshake messages before changing the
+ // read keys, since that can cause messages to be parsed that were encrypted
+ // using old keys which are no longer appropriate.
+ // TODO(roland): we should merge this check with the similar one in setReadTrafficSecret.
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: handshake buffer not empty before setting read traffic secret")
+ }
c.quic.events = append(c.quic.events, QUICEvent{
Kind: QUICSetReadSecret,
Level: level,
Suite: suite,
Data: secret,
})
+ return nil
}
func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {