diff options
| author | Filippo Valsorda <filippo@golang.org> | 2024-05-18 20:15:38 +0200 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-05-22 14:56:25 +0000 |
| commit | d0edd9acc80a16ca1dd9c6f9045fdd34efabcd42 (patch) | |
| tree | df7d7d2260eb49a9194077433abf1fa1042be122 /src/crypto/tls/handshake_client.go | |
| parent | 7c52c064df8d14971b319ebb508b782a5fa39221 (diff) | |
| download | go-d0edd9acc80a16ca1dd9c6f9045fdd34efabcd42.tar.xz | |
crypto/tls: implement X25519Kyber768Draft00
Forced the testConfig CurvePreferences to exclude X25519Kyber768Draft00
to avoid bloating the transcripts, but I manually tested it and the
tests all update and pass successfully, causing 7436 insertions(+), 3251
deletions(-).
Fixes #67061
Change-Id: If6f13bca561835777ab0889a490487b7c2366c3c
Reviewed-on: https://go-review.googlesource.com/c/go/+/586656
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/crypto/tls/handshake_client.go')
| -rw-r--r-- | src/crypto/tls/handshake_client.go | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index cc3efe1a79..53d4f90503 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -8,15 +8,16 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/ecdsa" "crypto/ed25519" + "crypto/internal/mlkem768" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "fmt" "hash" + "internal/byteorder" "internal/godebug" "io" "net" @@ -39,7 +40,7 @@ type clientHandshakeState struct { var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme -func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { +func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, error) { config := c.config if len(config.ServerName) == 0 && !config.InsecureSkipVerify { return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") @@ -61,30 +62,30 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { if len(supportedVersions) == 0 { return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") } - - clientHelloVersion := config.maxSupportedVersion(roleClient) - // The version at the beginning of the ClientHello was capped at TLS 1.2 - // for compatibility reasons. The supported_versions extension is used - // to negotiate versions now. See RFC 8446, Section 4.2.1. - if clientHelloVersion > VersionTLS12 { - clientHelloVersion = VersionTLS12 - } + maxVersion := config.maxSupportedVersion(roleClient) hello := &clientHelloMsg{ - vers: clientHelloVersion, + vers: maxVersion, compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), extendedMasterSecret: true, ocspStapling: true, scts: true, serverName: hostnameInSNI(config.ServerName), - supportedCurves: config.curvePreferences(), + supportedCurves: config.curvePreferences(maxVersion), supportedPoints: []uint8{pointFormatUncompressed}, secureRenegotiationSupported: true, alpnProtocols: config.NextProtos, supportedVersions: supportedVersions, } + // The version at the beginning of the ClientHello was capped at TLS 1.2 + // for compatibility reasons. The supported_versions extension is used + // to negotiate versions now. See RFC 8446, Section 4.2.1. + if hello.vers > VersionTLS12 { + hello.vers = VersionTLS12 + } + if c.handshakes > 0 { hello.secureRenegotiation = c.clientFinished[:] } @@ -103,7 +104,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { } // Don't advertise TLS 1.2-only cipher suites unless // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 { continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) @@ -126,14 +127,14 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { } } - if hello.vers >= VersionTLS12 { + if maxVersion >= VersionTLS12 { hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms() } if testingOnlyForceClientHelloSignatureAlgorithms != nil { hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms } - var key *ecdh.PrivateKey + var keyShareKeys *keySharePrivateKeys if hello.supportedVersions[0] == VersionTLS13 { // Reset the list of ciphers when the client only supports TLS 1.3. if len(hello.supportedVersions) == 1 { @@ -145,15 +146,40 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) } - curveID := config.curvePreferences()[0] - if _, ok := curveForCurveID(curveID); !ok { - return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") - } - key, err = generateECDHEKey(config.rand(), curveID) - if err != nil { - return nil, nil, err + curveID := config.curvePreferences(maxVersion)[0] + keyShareKeys = &keySharePrivateKeys{curveID: curveID} + if curveID == x25519Kyber768Draft00 { + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) + if err != nil { + return nil, nil, err + } + seed := make([]byte, mlkem768.SeedSize) + if _, err := io.ReadFull(config.rand(), seed); err != nil { + return nil, nil, err + } + keyShareKeys.kyber, err = mlkem768.NewKeyFromSeed(seed) + if err != nil { + return nil, nil, err + } + // For draft-tls-westerbaan-xyber768d00-03, we send both a hybrid + // and a standard X25519 key share, since most servers will only + // support the latter. We reuse the same X25519 ephemeral key for + // both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. + hello.keyShares = []keyShare{ + {group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(), + keyShareKeys.kyber.EncapsulationKey()...)}, + {group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()}, + } + } else { + if _, ok := curveForCurveID(curveID); !ok { + return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") + } + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID) + if err != nil { + return nil, nil, err + } + hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}} } - hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} } if c.quic != nil { @@ -167,7 +193,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.quicTransportParameters = p } - return hello, key, nil + return hello, keyShareKeys, nil } func (c *Conn) clientHandshake(ctx context.Context) (err error) { @@ -179,7 +205,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { // need to be reset. c.didResume = false - hello, ecdheKey, err := c.makeClientHello() + hello, keyShareKeys, err := c.makeClientHello() if err != nil { return err } @@ -249,17 +275,15 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { if c.vers == VersionTLS13 { hs := &clientHandshakeStateTLS13{ - c: c, - ctx: ctx, - serverHello: serverHello, - hello: hello, - ecdheKey: ecdheKey, - session: session, - earlySecret: earlySecret, - binderKey: binderKey, + c: c, + ctx: ctx, + serverHello: serverHello, + hello: hello, + keyShareKeys: keyShareKeys, + session: session, + earlySecret: earlySecret, + binderKey: binderKey, } - - // In TLS 1.3, session tickets are delivered after the handshake. return hs.handshake() } @@ -270,12 +294,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { hello: hello, session: session, } - - if err := hs.handshake(); err != nil { - return err - } - - return nil + return hs.handshake() } func (c *Conn) loadSession(hello *clientHelloMsg) ( @@ -603,6 +622,9 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertUnexpectedMessage) return err } + if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { + c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + } msg, err = c.readHandshake(&hs.finishedHash) if err != nil { |
