Bug#1031330: [pre-approval] unblock: golang-1.19/1.19.6-2
On 2023-02-15 11:58:54 +0800, Shengjing Zhu wrote:
> Package: release.debian.org
> Severity: normal
> User: release.debian.org@packages.debian.org
> Usertags: unblock
> X-Debbugs-Cc: golang-1.19@packages.debian.org, zhsj@debian.org
> Control: affects -1 + src:golang-1.19
>
> Please unblock package golang-1.19
Please go ahead with the upload.
>
> [ Reason ]
> A new upstream release that addresses 4 CVE in Go standard library.
>
> [ Impact ]
> CVE in Go standard library and the Go packages that have statically
> linked with it.
>
> [ Tests ]
> The fixes are covered by new unit tests.
>
> [ Risks ]
> The package is in the toolchain set.
>
> [ Checklist ]
> [x] all changes are documented in the d/changelog
> [x] I reviewed all changes and I approve them
> [x] attach debdiff against the package in testing
>
> The diff is for golang-1.19/1.19.6-1, which I have uploaded to
> experimental first. -2 should be no-change rebuild on unstable.
>
> [ Other info ]
> So same as previous unblock request #1028452
> + This package doesn't have autopkgtest.
> + The upload will trigger Release Team to perform a new round of rebuilding
> outdated Built-Using for all Go packages.
>
> The Go upstream usually has one minor version (may or may not carry CVE
> fixes) release every month.
> I'm wondering what Release Team thinks how often we should update
> during the freeze periods. Some options are:
> + Only ask pre-approval for minor versions with CVE
> + Don't update any (probably at late freeze period, like hard/full-freeze).
I would suggest to stick to versions fixing CVEs for now. If there is a
no-CVE releases between the last update and the start of the hard
freeze, we can revisit a final update and rebuild of the golang-world.
Cheers
>
> The package currently FTBFS on i386/experimental but it won't be problem on
> unstable.
> The dep-resolver (aspcud) in experimental chooses gccgo to bootstrap,
> which has a bug https://github.com/golang/go/issues/51850.
> But on unstable the dep-resolver is apt, and will choose old golang-go to
> bootstrap.
>
> unblock golang-1.19/1.19.6-2
> diff -Nru golang-1.19-1.19.5/debian/changelog golang-1.19-1.19.6/debian/changelog
> --- golang-1.19-1.19.5/debian/changelog 2023-01-11 15:35:00.000000000 +0800
> +++ golang-1.19-1.19.6/debian/changelog 2023-02-15 10:09:02.000000000 +0800
> @@ -1,3 +1,16 @@
> +golang-1.19 (1.19.6-1) experimental; urgency=medium
> +
> + * Team upload
> + * New upstream version 1.19.6
> + + CVE-2022-41722: path/filepath: path traversal in filepath.Clean on
> + Windows
> + + CVE-2022-41725: net/http, mime/multipart: denial of service from
> + excessive resource consumption
> + + CVE-2022-41724: crypto/tls: large handshake records may cause panics
> + + CVE-2022-41723: net/http: avoid quadratic complexity in HPACK decoding
> +
> + -- Shengjing Zhu <zhsj@debian.org> Wed, 15 Feb 2023 10:09:02 +0800
> +
> golang-1.19 (1.19.5-1) unstable; urgency=medium
>
> * Team upload
> diff -Nru golang-1.19-1.19.5/src/cmd/go/internal/modfetch/coderepo_test.go golang-1.19-1.19.6/src/cmd/go/internal/modfetch/coderepo_test.go
> --- golang-1.19-1.19.5/src/cmd/go/internal/modfetch/coderepo_test.go 2023-01-10 06:38:03.000000000 +0800
> +++ golang-1.19-1.19.6/src/cmd/go/internal/modfetch/coderepo_test.go 2023-02-14 01:38:43.000000000 +0800
> @@ -379,18 +379,6 @@
> zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5",
> },
> {
> - vcs: "git",
> - path: "gopkg.in/natefinch/lumberjack.v2",
> - rev: "latest",
> - version: "v2.0.0-20170531160350-a96e63847dc3",
> - name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
> - short: "a96e63847dc3",
> - time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
> - gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
> - zipSum: "h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI=",
> - zipFileHash: "b5de0da7bbbec76709eef1ac71b6c9ff423b9fbf3bb97b56743450d4937b06d5",
> - },
> - {
> vcs: "git",
> path: "gopkg.in/natefinch/lumberjack.v2",
> // This repo has a v2.1 tag.
> @@ -578,6 +566,10 @@
> for _, tt := range codeRepoTests {
> f := func(tt codeRepoTest) func(t *testing.T) {
> return func(t *testing.T) {
> + if strings.Contains(tt.path, "gopkg.in") {
> + testenv.SkipFlaky(t, 54503)
> + }
> +
> t.Parallel()
> if tt.vcs != "mod" {
> testenv.MustHaveExecPath(t, tt.vcs)
> @@ -790,11 +782,6 @@
> },
> {
> vcs: "git",
> - path: "gopkg.in/natefinch/lumberjack.v2",
> - versions: []string{"v2.0.0"},
> - },
> - {
> - vcs: "git",
> path: "vcs-test.golang.org/git/odd-tags.git",
> versions: nil,
> },
> @@ -811,8 +798,12 @@
>
> t.Run("parallel", func(t *testing.T) {
> for _, tt := range codeRepoVersionsTests {
> + tt := tt
> t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
> - tt := tt
> + if strings.Contains(tt.path, "gopkg.in") {
> + testenv.SkipFlaky(t, 54503)
> + }
> +
> t.Parallel()
> if tt.vcs != "mod" {
> testenv.MustHaveExecPath(t, tt.vcs)
> diff -Nru golang-1.19-1.19.5/src/cmd/go/testdata/script/mod_gopkg_unstable.txt golang-1.19-1.19.6/src/cmd/go/testdata/script/mod_gopkg_unstable.txt
> --- golang-1.19-1.19.5/src/cmd/go/testdata/script/mod_gopkg_unstable.txt 2023-01-10 06:38:05.000000000 +0800
> +++ golang-1.19-1.19.6/src/cmd/go/testdata/script/mod_gopkg_unstable.txt 2023-02-14 01:38:43.000000000 +0800
> @@ -10,6 +10,8 @@
> [!net] skip
> [!exec:git] skip
>
> +skip # TODO(#54503): redirect gopkg.in requests to a local server and re-enable.
> +
> env GOPROXY=direct
> env GOSUMDB=off
> go get gopkg.in/macaroon-bakery.v2-unstable/bakery
> diff -Nru golang-1.19-1.19.5/src/cmd/go/testdata/script/version_gc_sections.txt golang-1.19-1.19.6/src/cmd/go/testdata/script/version_gc_sections.txt
> --- golang-1.19-1.19.5/src/cmd/go/testdata/script/version_gc_sections.txt 1970-01-01 08:00:00.000000000 +0800
> +++ golang-1.19-1.19.6/src/cmd/go/testdata/script/version_gc_sections.txt 2023-02-14 01:38:43.000000000 +0800
> @@ -0,0 +1,24 @@
> +# This test checks that external linking with --gc-sections does not strip version information.
> +
> +[short] skip
> +[!cgo] skip
> +[aix] skip # no --gc-sections
> +[darwin] skip # no --gc-sections
> +
> +go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections'
> +go version hello$GOEXE
> +! stdout 'not a Go executable'
> +! stderr 'not a Go executable'
> +
> +-- go.mod --
> +module hello
> +-- hello.go --
> +package main
> +
> +/*
> +*/
> +import "C"
> +
> +func main() {
> + println("hello")
> +}
> diff -Nru golang-1.19-1.19.5/src/cmd/internal/moddeps/moddeps_test.go golang-1.19-1.19.6/src/cmd/internal/moddeps/moddeps_test.go
> --- golang-1.19-1.19.5/src/cmd/internal/moddeps/moddeps_test.go 2023-01-10 06:38:05.000000000 +0800
> +++ golang-1.19-1.19.6/src/cmd/internal/moddeps/moddeps_test.go 2023-02-14 01:38:43.000000000 +0800
> @@ -33,7 +33,7 @@
> // See issues 36852, 41409, and 43687.
> // (Also see golang.org/issue/27348.)
> func TestAllDependencies(t *testing.T) {
> - t.Skip("TODO(#57009): 1.19.4 contains unreleased changes from vendored modules")
> + t.Skip("TODO(#58355): 1.19.4 contains unreleased changes from vendored modules")
>
> goBin := testenv.GoToolPath(t)
>
> diff -Nru golang-1.19-1.19.5/src/cmd/link/internal/ld/data.go golang-1.19-1.19.6/src/cmd/link/internal/ld/data.go
> --- golang-1.19-1.19.5/src/cmd/link/internal/ld/data.go 2023-01-10 06:38:05.000000000 +0800
> +++ golang-1.19-1.19.6/src/cmd/link/internal/ld/data.go 2023-02-14 01:38:43.000000000 +0800
> @@ -1601,6 +1601,9 @@
> func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section {
> ldr := state.ctxt.loader
> sname := ldr.SymName(s)
> + if sname == "go.buildinfo" { // clumsy hack for Go 1.19 builders
> + sname = ".go.buildinfo"
> + }
> sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
> sect.Align = symalign(ldr, s)
> state.datsize = Rnd(state.datsize, int64(sect.Align))
> @@ -2177,7 +2180,7 @@
> // Write the buildinfo symbol, which go version looks for.
> // The code reading this data is in package debug/buildinfo.
> ldr := ctxt.loader
> - s := ldr.CreateSymForUpdate(".go.buildinfo", 0)
> + s := ldr.CreateSymForUpdate("go.buildinfo", 0)
> s.SetType(sym.SBUILDINFO)
> s.SetAlign(16)
> // The \xff is invalid UTF-8, meant to make it less likely
> @@ -2199,6 +2202,14 @@
> }
> s.SetData(data)
> s.SetSize(int64(len(data)))
> +
> + // Add reference to go:buildinfo from the rodata section,
> + // so that external linking with -Wl,--gc-sections does not
> + // delete the build info.
> + sr := ldr.CreateSymForUpdate("go.buildinfo.ref", 0)
> + sr.SetType(sym.SRODATA)
> + sr.SetAlign(int32(ctxt.Arch.PtrSize))
> + sr.AddAddr(ctxt.Arch, s.Sym())
> }
>
> // appendString appends s to data, prefixed by its varint-encoded length.
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/boring_test.go golang-1.19-1.19.6/src/crypto/tls/boring_test.go
> --- golang-1.19-1.19.5/src/crypto/tls/boring_test.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/boring_test.go 2023-02-14 01:38:45.000000000 +0800
> @@ -269,7 +269,7 @@
>
> go Client(c, clientConfig).Handshake()
> srv := Server(s, testConfig)
> - msg, err := srv.readHandshake()
> + msg, err := srv.readHandshake(nil)
> if err != nil {
> t.Fatal(err)
> }
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/common.go golang-1.19-1.19.6/src/crypto/tls/common.go
> --- golang-1.19-1.19.5/src/crypto/tls/common.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/common.go 2023-02-14 01:38:45.000000000 +0800
> @@ -1384,7 +1384,7 @@
> }
>
> type handshakeMessage interface {
> - marshal() []byte
> + marshal() ([]byte, error)
> unmarshal([]byte) bool
> }
>
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/conn.go golang-1.19-1.19.6/src/crypto/tls/conn.go
> --- golang-1.19-1.19.5/src/crypto/tls/conn.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/conn.go 2023-02-14 01:38:45.000000000 +0800
> @@ -1003,18 +1003,37 @@
> return n, nil
> }
>
> -// writeRecord writes a TLS record with the given type and payload to the
> -// connection and updates the record layer state.
> -func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
> +// writeHandshakeRecord writes a handshake message to the connection and updates
> +// the record layer state. If transcript is non-nil the marshalled message is
> +// written to it.
> +func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
> c.out.Lock()
> defer c.out.Unlock()
>
> - return c.writeRecordLocked(typ, data)
> + data, err := msg.marshal()
> + if err != nil {
> + return 0, err
> + }
> + if transcript != nil {
> + transcript.Write(data)
> + }
> +
> + return c.writeRecordLocked(recordTypeHandshake, data)
> +}
> +
> +// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
> +// updates the record layer state.
> +func (c *Conn) writeChangeCipherRecord() error {
> + c.out.Lock()
> + defer c.out.Unlock()
> + _, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
> + return err
> }
>
> // readHandshake reads the next handshake message from
> -// the record layer.
> -func (c *Conn) readHandshake() (any, error) {
> +// the record layer. If transcript is non-nil, the message
> +// is written to the passed transcriptHash.
> +func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
> for c.hand.Len() < 4 {
> if err := c.readRecord(); err != nil {
> return nil, err
> @@ -1093,6 +1112,11 @@
> if !m.unmarshal(data) {
> return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
> }
> +
> + if transcript != nil {
> + transcript.Write(data)
> + }
> +
> return m, nil
> }
>
> @@ -1168,7 +1192,7 @@
> return errors.New("tls: internal error: unexpected renegotiation")
> }
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -1214,7 +1238,7 @@
> return c.handleRenegotiation()
> }
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -1250,7 +1274,11 @@
> defer c.out.Unlock()
>
> msg := &keyUpdateMsg{}
> - _, err := c.writeRecordLocked(recordTypeHandshake, msg.marshal())
> + msgBytes, err := msg.marshal()
> + if err != nil {
> + return err
> + }
> + _, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
> if err != nil {
> // Surface the error at the next write.
> c.out.setErrorLocked(err)
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_client.go golang-1.19-1.19.6/src/crypto/tls/handshake_client.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_client.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_client.go 2023-02-14 01:38:45.000000000 +0800
> @@ -162,7 +162,10 @@
> }
> c.serverName = hello.serverName
>
> - cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
> + cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello)
> + if err != nil {
> + return err
> + }
> if cacheKey != "" && session != nil {
> defer func() {
> // If we got a handshake failure when resuming a session, throw away
> @@ -177,11 +180,12 @@
> }()
> }
>
> - if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
> + if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
> return err
> }
>
> - msg, err := c.readHandshake()
> + // serverHelloMsg is not included in the transcript
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -246,9 +250,9 @@
> }
>
> func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
> - session *ClientSessionState, earlySecret, binderKey []byte) {
> + session *ClientSessionState, earlySecret, binderKey []byte, err error) {
> if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
> - return "", nil, nil, nil
> + return "", nil, nil, nil, nil
> }
>
> hello.ticketSupported = true
> @@ -263,14 +267,14 @@
> // renegotiation is primarily used to allow a client to send a client
> // certificate, which would be skipped if session resumption occurred.
> if c.handshakes != 0 {
> - return "", nil, nil, nil
> + return "", nil, nil, nil, nil
> }
>
> // Try to resume a previously negotiated TLS session, if available.
> cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
> session, ok := c.config.ClientSessionCache.Get(cacheKey)
> if !ok || session == nil {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
>
> // Check that version used for the previous session is still valid.
> @@ -282,7 +286,7 @@
> }
> }
> if !versOk {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
>
> // Check that the cached server certificate is not expired, and that it's
> @@ -291,16 +295,16 @@
> if !c.config.InsecureSkipVerify {
> if len(session.verifiedChains) == 0 {
> // The original connection had InsecureSkipVerify, while this doesn't.
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
> serverCert := session.serverCertificates[0]
> if c.config.time().After(serverCert.NotAfter) {
> // Expired certificate, delete the entry.
> c.config.ClientSessionCache.Put(cacheKey, nil)
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
> if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
> }
>
> @@ -308,7 +312,7 @@
> // In TLS 1.2 the cipher suite must match the resumed session. Ensure we
> // are still offering it.
> if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
>
> hello.sessionTicket = session.sessionTicket
> @@ -318,14 +322,14 @@
> // Check that the session ticket is not expired.
> if c.config.time().After(session.useBy) {
> c.config.ClientSessionCache.Put(cacheKey, nil)
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
>
> // In TLS 1.3 the KDF hash must match the resumed session. Ensure we
> // offer at least one cipher suite with that hash.
> cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
> if cipherSuite == nil {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
> cipherSuiteOk := false
> for _, offeredID := range hello.cipherSuites {
> @@ -336,7 +340,7 @@
> }
> }
> if !cipherSuiteOk {
> - return cacheKey, nil, nil, nil
> + return cacheKey, nil, nil, nil, nil
> }
>
> // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
> @@ -354,9 +358,15 @@
> earlySecret = cipherSuite.extract(psk, nil)
> binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
> transcript := cipherSuite.hash.New()
> - transcript.Write(hello.marshalWithoutBinders())
> + helloBytes, err := hello.marshalWithoutBinders()
> + if err != nil {
> + return "", nil, nil, nil, err
> + }
> + transcript.Write(helloBytes)
> pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
> - hello.updateBinders(pskBinders)
> + if err := hello.updateBinders(pskBinders); err != nil {
> + return "", nil, nil, nil, err
> + }
>
> return
> }
> @@ -401,8 +411,12 @@
> hs.finishedHash.discardHandshakeBuffer()
> }
>
> - hs.finishedHash.Write(hs.hello.marshal())
> - hs.finishedHash.Write(hs.serverHello.marshal())
> + if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
> + return err
> + }
> + if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
> + return err
> + }
>
> c.buffering = true
> c.didResume = isResume
> @@ -473,7 +487,7 @@
> func (hs *clientHandshakeState) doFullHandshake() error {
> c := hs.c
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -482,9 +496,8 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(certMsg, msg)
> }
> - hs.finishedHash.Write(certMsg.marshal())
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -502,11 +515,10 @@
> c.sendAlert(alertUnexpectedMessage)
> return errors.New("tls: received unexpected CertificateStatus message")
> }
> - hs.finishedHash.Write(cs.marshal())
>
> c.ocspResponse = cs.response
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -535,14 +547,13 @@
>
> skx, ok := msg.(*serverKeyExchangeMsg)
> if ok {
> - hs.finishedHash.Write(skx.marshal())
> err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
> if err != nil {
> c.sendAlert(alertUnexpectedMessage)
> return err
> }
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -553,7 +564,6 @@
> certReq, ok := msg.(*certificateRequestMsg)
> if ok {
> certRequested = true
> - hs.finishedHash.Write(certReq.marshal())
>
> cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
> if chainToSend, err = c.getClientCertificate(cri); err != nil {
> @@ -561,7 +571,7 @@
> return err
> }
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -572,7 +582,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(shd, msg)
> }
> - hs.finishedHash.Write(shd.marshal())
>
> // If the server requested a certificate then we have to send a
> // Certificate message, even if it's empty because we don't have a
> @@ -580,8 +589,7 @@
> if certRequested {
> certMsg = new(certificateMsg)
> certMsg.certificates = chainToSend.Certificate
> - hs.finishedHash.Write(certMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
> return err
> }
> }
> @@ -592,8 +600,7 @@
> return err
> }
> if ckx != nil {
> - hs.finishedHash.Write(ckx.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
> return err
> }
> }
> @@ -640,8 +647,7 @@
> return err
> }
>
> - hs.finishedHash.Write(certVerify.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
> return err
> }
> }
> @@ -776,7 +782,10 @@
> return err
> }
>
> - msg, err := c.readHandshake()
> + // finishedMsg is included in the transcript, but not until after we
> + // check the client version, since the state before this message was
> + // sent is used during verification.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -792,7 +801,11 @@
> c.sendAlert(alertHandshakeFailure)
> return errors.New("tls: server's Finished message was incorrect")
> }
> - hs.finishedHash.Write(serverFinished.marshal())
> +
> + if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
> + return err
> + }
> +
> copy(out, verify)
> return nil
> }
> @@ -803,7 +816,7 @@
> }
>
> c := hs.c
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -812,7 +825,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(sessionTicketMsg, msg)
> }
> - hs.finishedHash.Write(sessionTicketMsg.marshal())
>
> hs.session = &ClientSessionState{
> sessionTicket: sessionTicketMsg.ticket,
> @@ -832,14 +844,13 @@
> func (hs *clientHandshakeState) sendFinished(out []byte) error {
> c := hs.c
>
> - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
> + if err := c.writeChangeCipherRecord(); err != nil {
> return err
> }
>
> finished := new(finishedMsg)
> finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
> - hs.finishedHash.Write(finished.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
> return err
> }
> copy(out, finished.verifyData)
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_client_test.go golang-1.19-1.19.6/src/crypto/tls/handshake_client_test.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_client_test.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_client_test.go 2023-02-14 01:38:45.000000000 +0800
> @@ -1257,7 +1257,7 @@
> cipherSuite: TLS_RSA_WITH_AES_128_GCM_SHA256,
> alpnProtocol: "how-about-this",
> }
> - serverHelloBytes := serverHello.marshal()
> + serverHelloBytes := mustMarshal(t, serverHello)
>
> s.Write([]byte{
> byte(recordTypeHandshake),
> @@ -1500,7 +1500,7 @@
> random: make([]byte, 32),
> cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
> }
> - serverHelloBytes := serverHello.marshal()
> + serverHelloBytes := mustMarshal(t, serverHello)
>
> s.Write([]byte{
> byte(recordTypeHandshake),
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_client_tls13.go golang-1.19-1.19.6/src/crypto/tls/handshake_client_tls13.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_client_tls13.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_client_tls13.go 2023-02-14 01:38:45.000000000 +0800
> @@ -62,7 +62,10 @@
> }
>
> hs.transcript = hs.suite.hash.New()
> - hs.transcript.Write(hs.hello.marshal())
> +
> + if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
> + return err
> + }
>
> if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
> if err := hs.sendDummyChangeCipherSpec(); err != nil {
> @@ -73,7 +76,9 @@
> }
> }
>
> - hs.transcript.Write(hs.serverHello.marshal())
> + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
> + return err
> + }
>
> c.buffering = true
> if err := hs.processServerHello(); err != nil {
> @@ -172,8 +177,7 @@
> }
> hs.sentDummyCCS = true
>
> - _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
> - return err
> + return hs.c.writeChangeCipherRecord()
> }
>
> // processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
> @@ -188,7 +192,9 @@
> hs.transcript.Reset()
> hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
> hs.transcript.Write(chHash)
> - hs.transcript.Write(hs.serverHello.marshal())
> + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
> + return err
> + }
>
> // The only HelloRetryRequest extensions we support are key_share and
> // cookie, and clients must abort the handshake if the HRR would not result
> @@ -253,10 +259,18 @@
> transcript := hs.suite.hash.New()
> transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
> transcript.Write(chHash)
> - transcript.Write(hs.serverHello.marshal())
> - transcript.Write(hs.hello.marshalWithoutBinders())
> + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
> + return err
> + }
> + helloBytes, err := hs.hello.marshalWithoutBinders()
> + if err != nil {
> + return err
> + }
> + transcript.Write(helloBytes)
> pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
> - hs.hello.updateBinders(pskBinders)
> + if err := hs.hello.updateBinders(pskBinders); err != nil {
> + return err
> + }
> } else {
> // Server selected a cipher suite incompatible with the PSK.
> hs.hello.pskIdentities = nil
> @@ -264,12 +278,12 @@
> }
> }
>
> - hs.transcript.Write(hs.hello.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
> return err
> }
>
> - msg, err := c.readHandshake()
> + // serverHelloMsg is not included in the transcript
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -358,6 +372,7 @@
> if !hs.usingPSK {
> earlySecret = hs.suite.extract(nil, nil)
> }
> +
> handshakeSecret := hs.suite.extract(sharedKey,
> hs.suite.deriveSecret(earlySecret, "derived", nil))
>
> @@ -388,7 +403,7 @@
> func (hs *clientHandshakeStateTLS13) readServerParameters() error {
> c := hs.c
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(hs.transcript)
> if err != nil {
> return err
> }
> @@ -398,7 +413,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(encryptedExtensions, msg)
> }
> - hs.transcript.Write(encryptedExtensions.marshal())
>
> if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
> c.sendAlert(alertUnsupportedExtension)
> @@ -427,18 +441,16 @@
> return nil
> }
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(hs.transcript)
> if err != nil {
> return err
> }
>
> certReq, ok := msg.(*certificateRequestMsgTLS13)
> if ok {
> - hs.transcript.Write(certReq.marshal())
> -
> hs.certReq = certReq
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(hs.transcript)
> if err != nil {
> return err
> }
> @@ -453,7 +465,6 @@
> c.sendAlert(alertDecodeError)
> return errors.New("tls: received empty certificates message")
> }
> - hs.transcript.Write(certMsg.marshal())
>
> c.scts = certMsg.certificate.SignedCertificateTimestamps
> c.ocspResponse = certMsg.certificate.OCSPStaple
> @@ -462,7 +473,10 @@
> return err
> }
>
> - msg, err = c.readHandshake()
> + // certificateVerifyMsg is included in the transcript, but not until
> + // after we verify the handshake signature, since the state before
> + // this message was sent is used.
> + msg, err = c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -493,7 +507,9 @@
> return errors.New("tls: invalid signature by the server certificate: " + err.Error())
> }
>
> - hs.transcript.Write(certVerify.marshal())
> + if err := transcriptMsg(certVerify, hs.transcript); err != nil {
> + return err
> + }
>
> return nil
> }
> @@ -501,7 +517,10 @@
> func (hs *clientHandshakeStateTLS13) readServerFinished() error {
> c := hs.c
>
> - msg, err := c.readHandshake()
> + // finishedMsg is included in the transcript, but not until after we
> + // check the client version, since the state before this message was
> + // sent is used during verification.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -518,7 +537,9 @@
> return errors.New("tls: invalid server finished hash")
> }
>
> - hs.transcript.Write(finished.marshal())
> + if err := transcriptMsg(finished, hs.transcript); err != nil {
> + return err
> + }
>
> // Derive secrets that take context through the server Finished.
>
> @@ -567,8 +588,7 @@
> certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
> certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
>
> - hs.transcript.Write(certMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
> return err
> }
>
> @@ -605,8 +625,7 @@
> }
> certVerifyMsg.signature = sig
>
> - hs.transcript.Write(certVerifyMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
> return err
> }
>
> @@ -620,8 +639,7 @@
> verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
> }
>
> - hs.transcript.Write(finished.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
> return err
> }
>
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_messages.go golang-1.19-1.19.6/src/crypto/tls/handshake_messages.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_messages.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_messages.go 2023-02-14 01:38:45.000000000 +0800
> @@ -5,6 +5,7 @@
> package tls
>
> import (
> + "errors"
> "fmt"
> "strings"
>
> @@ -94,9 +95,181 @@
> pskBinders [][]byte
> }
>
> -func (m *clientHelloMsg) marshal() []byte {
> +func (m *clientHelloMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> + }
> +
> + var exts cryptobyte.Builder
> + if len(m.serverName) > 0 {
> + // RFC 6066, Section 3
> + exts.AddUint16(extensionServerName)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8(0) // name_type = host_name
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes([]byte(m.serverName))
> + })
> + })
> + })
> + }
> + if m.ocspStapling {
> + // RFC 4366, Section 3.6
> + exts.AddUint16(extensionStatusRequest)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8(1) // status_type = ocsp
> + exts.AddUint16(0) // empty responder_id_list
> + exts.AddUint16(0) // empty request_extensions
> + })
> + }
> + if len(m.supportedCurves) > 0 {
> + // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
> + exts.AddUint16(extensionSupportedCurves)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, curve := range m.supportedCurves {
> + exts.AddUint16(uint16(curve))
> + }
> + })
> + })
> + }
> + if len(m.supportedPoints) > 0 {
> + // RFC 4492, Section 5.1.2
> + exts.AddUint16(extensionSupportedPoints)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.supportedPoints)
> + })
> + })
> + }
> + if m.ticketSupported {
> + // RFC 5077, Section 3.2
> + exts.AddUint16(extensionSessionTicket)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.sessionTicket)
> + })
> + }
> + if len(m.supportedSignatureAlgorithms) > 0 {
> + // RFC 5246, Section 7.4.1.4.1
> + exts.AddUint16(extensionSignatureAlgorithms)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, sigAlgo := range m.supportedSignatureAlgorithms {
> + exts.AddUint16(uint16(sigAlgo))
> + }
> + })
> + })
> + }
> + if len(m.supportedSignatureAlgorithmsCert) > 0 {
> + // RFC 8446, Section 4.2.3
> + exts.AddUint16(extensionSignatureAlgorithmsCert)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
> + exts.AddUint16(uint16(sigAlgo))
> + }
> + })
> + })
> + }
> + if m.secureRenegotiationSupported {
> + // RFC 5746, Section 3.2
> + exts.AddUint16(extensionRenegotiationInfo)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.secureRenegotiation)
> + })
> + })
> + }
> + if len(m.alpnProtocols) > 0 {
> + // RFC 7301, Section 3.1
> + exts.AddUint16(extensionALPN)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, proto := range m.alpnProtocols {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes([]byte(proto))
> + })
> + }
> + })
> + })
> + }
> + if m.scts {
> + // RFC 6962, Section 3.3.1
> + exts.AddUint16(extensionSCT)
> + exts.AddUint16(0) // empty extension_data
> + }
> + if len(m.supportedVersions) > 0 {
> + // RFC 8446, Section 4.2.1
> + exts.AddUint16(extensionSupportedVersions)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, vers := range m.supportedVersions {
> + exts.AddUint16(vers)
> + }
> + })
> + })
> + }
> + if len(m.cookie) > 0 {
> + // RFC 8446, Section 4.2.2
> + exts.AddUint16(extensionCookie)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.cookie)
> + })
> + })
> + }
> + if len(m.keyShares) > 0 {
> + // RFC 8446, Section 4.2.8
> + exts.AddUint16(extensionKeyShare)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, ks := range m.keyShares {
> + exts.AddUint16(uint16(ks.group))
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(ks.data)
> + })
> + }
> + })
> + })
> + }
> + if m.earlyData {
> + // RFC 8446, Section 4.2.10
> + exts.AddUint16(extensionEarlyData)
> + exts.AddUint16(0) // empty extension_data
> + }
> + if len(m.pskModes) > 0 {
> + // RFC 8446, Section 4.2.9
> + exts.AddUint16(extensionPSKModes)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.pskModes)
> + })
> + })
> + }
> + if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
> + // RFC 8446, Section 4.2.11
> + exts.AddUint16(extensionPreSharedKey)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, psk := range m.pskIdentities {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(psk.label)
> + })
> + exts.AddUint32(psk.obfuscatedTicketAge)
> + }
> + })
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, binder := range m.pskBinders {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(binder)
> + })
> + }
> + })
> + })
> + }
> + extBytes, err := exts.Bytes()
> + if err != nil {
> + return nil, err
> }
>
> var b cryptobyte.Builder
> @@ -116,219 +289,53 @@
> b.AddBytes(m.compressionMethods)
> })
>
> - // If extensions aren't present, omit them.
> - var extensionsPresent bool
> - bWithoutExtensions := *b
> -
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - if len(m.serverName) > 0 {
> - // RFC 6066, Section 3
> - b.AddUint16(extensionServerName)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8(0) // name_type = host_name
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes([]byte(m.serverName))
> - })
> - })
> - })
> - }
> - if m.ocspStapling {
> - // RFC 4366, Section 3.6
> - b.AddUint16(extensionStatusRequest)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8(1) // status_type = ocsp
> - b.AddUint16(0) // empty responder_id_list
> - b.AddUint16(0) // empty request_extensions
> - })
> - }
> - if len(m.supportedCurves) > 0 {
> - // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
> - b.AddUint16(extensionSupportedCurves)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, curve := range m.supportedCurves {
> - b.AddUint16(uint16(curve))
> - }
> - })
> - })
> - }
> - if len(m.supportedPoints) > 0 {
> - // RFC 4492, Section 5.1.2
> - b.AddUint16(extensionSupportedPoints)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.supportedPoints)
> - })
> - })
> - }
> - if m.ticketSupported {
> - // RFC 5077, Section 3.2
> - b.AddUint16(extensionSessionTicket)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.sessionTicket)
> - })
> - }
> - if len(m.supportedSignatureAlgorithms) > 0 {
> - // RFC 5246, Section 7.4.1.4.1
> - b.AddUint16(extensionSignatureAlgorithms)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, sigAlgo := range m.supportedSignatureAlgorithms {
> - b.AddUint16(uint16(sigAlgo))
> - }
> - })
> - })
> - }
> - if len(m.supportedSignatureAlgorithmsCert) > 0 {
> - // RFC 8446, Section 4.2.3
> - b.AddUint16(extensionSignatureAlgorithmsCert)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
> - b.AddUint16(uint16(sigAlgo))
> - }
> - })
> - })
> - }
> - if m.secureRenegotiationSupported {
> - // RFC 5746, Section 3.2
> - b.AddUint16(extensionRenegotiationInfo)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.secureRenegotiation)
> - })
> - })
> - }
> - if len(m.alpnProtocols) > 0 {
> - // RFC 7301, Section 3.1
> - b.AddUint16(extensionALPN)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, proto := range m.alpnProtocols {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes([]byte(proto))
> - })
> - }
> - })
> - })
> - }
> - if m.scts {
> - // RFC 6962, Section 3.3.1
> - b.AddUint16(extensionSCT)
> - b.AddUint16(0) // empty extension_data
> - }
> - if len(m.supportedVersions) > 0 {
> - // RFC 8446, Section 4.2.1
> - b.AddUint16(extensionSupportedVersions)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, vers := range m.supportedVersions {
> - b.AddUint16(vers)
> - }
> - })
> - })
> - }
> - if len(m.cookie) > 0 {
> - // RFC 8446, Section 4.2.2
> - b.AddUint16(extensionCookie)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.cookie)
> - })
> - })
> - }
> - if len(m.keyShares) > 0 {
> - // RFC 8446, Section 4.2.8
> - b.AddUint16(extensionKeyShare)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, ks := range m.keyShares {
> - b.AddUint16(uint16(ks.group))
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(ks.data)
> - })
> - }
> - })
> - })
> - }
> - if m.earlyData {
> - // RFC 8446, Section 4.2.10
> - b.AddUint16(extensionEarlyData)
> - b.AddUint16(0) // empty extension_data
> - }
> - if len(m.pskModes) > 0 {
> - // RFC 8446, Section 4.2.9
> - b.AddUint16(extensionPSKModes)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.pskModes)
> - })
> - })
> - }
> - if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
> - // RFC 8446, Section 4.2.11
> - b.AddUint16(extensionPreSharedKey)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, psk := range m.pskIdentities {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(psk.label)
> - })
> - b.AddUint32(psk.obfuscatedTicketAge)
> - }
> - })
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, binder := range m.pskBinders {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(binder)
> - })
> - }
> - })
> - })
> - }
> -
> - extensionsPresent = len(b.BytesOrPanic()) > 2
> - })
> -
> - if !extensionsPresent {
> - *b = bWithoutExtensions
> + if len(extBytes) > 0 {
> + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> + b.AddBytes(extBytes)
> + })
> }
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> // marshalWithoutBinders returns the ClientHello through the
> // PreSharedKeyExtension.identities field, according to RFC 8446, Section
> // 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
> -func (m *clientHelloMsg) marshalWithoutBinders() []byte {
> +func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) {
> bindersLen := 2 // uint16 length prefix
> for _, binder := range m.pskBinders {
> bindersLen += 1 // uint8 length prefix
> bindersLen += len(binder)
> }
>
> - fullMessage := m.marshal()
> - return fullMessage[:len(fullMessage)-bindersLen]
> + fullMessage, err := m.marshal()
> + if err != nil {
> + return nil, err
> + }
> + return fullMessage[:len(fullMessage)-bindersLen], nil
> }
>
> // updateBinders updates the m.pskBinders field, if necessary updating the
> // cached marshaled representation. The supplied binders must have the same
> // length as the current m.pskBinders.
> -func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
> +func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error {
> if len(pskBinders) != len(m.pskBinders) {
> - panic("tls: internal error: pskBinders length mismatch")
> + return errors.New("tls: internal error: pskBinders length mismatch")
> }
> for i := range m.pskBinders {
> if len(pskBinders[i]) != len(m.pskBinders[i]) {
> - panic("tls: internal error: pskBinders length mismatch")
> + return errors.New("tls: internal error: pskBinders length mismatch")
> }
> }
> m.pskBinders = pskBinders
> if m.raw != nil {
> - lenWithoutBinders := len(m.marshalWithoutBinders())
> + helloBytes, err := m.marshalWithoutBinders()
> + if err != nil {
> + return err
> + }
> + lenWithoutBinders := len(helloBytes)
> b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
> b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> for _, binder := range m.pskBinders {
> @@ -338,9 +345,11 @@
> }
> })
> if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
> - panic("tls: internal error: failed to update binders")
> + return errors.New("tls: internal error: failed to update binders")
> }
> }
> +
> + return nil
> }
>
> func (m *clientHelloMsg) unmarshal(data []byte) bool {
> @@ -618,9 +627,98 @@
> selectedGroup CurveID
> }
>
> -func (m *serverHelloMsg) marshal() []byte {
> +func (m *serverHelloMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> + }
> +
> + var exts cryptobyte.Builder
> + if m.ocspStapling {
> + exts.AddUint16(extensionStatusRequest)
> + exts.AddUint16(0) // empty extension_data
> + }
> + if m.ticketSupported {
> + exts.AddUint16(extensionSessionTicket)
> + exts.AddUint16(0) // empty extension_data
> + }
> + if m.secureRenegotiationSupported {
> + exts.AddUint16(extensionRenegotiationInfo)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.secureRenegotiation)
> + })
> + })
> + }
> + if len(m.alpnProtocol) > 0 {
> + exts.AddUint16(extensionALPN)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes([]byte(m.alpnProtocol))
> + })
> + })
> + })
> + }
> + if len(m.scts) > 0 {
> + exts.AddUint16(extensionSCT)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + for _, sct := range m.scts {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(sct)
> + })
> + }
> + })
> + })
> + }
> + if m.supportedVersion != 0 {
> + exts.AddUint16(extensionSupportedVersions)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16(m.supportedVersion)
> + })
> + }
> + if m.serverShare.group != 0 {
> + exts.AddUint16(extensionKeyShare)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16(uint16(m.serverShare.group))
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.serverShare.data)
> + })
> + })
> + }
> + if m.selectedIdentityPresent {
> + exts.AddUint16(extensionPreSharedKey)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16(m.selectedIdentity)
> + })
> + }
> +
> + if len(m.cookie) > 0 {
> + exts.AddUint16(extensionCookie)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.cookie)
> + })
> + })
> + }
> + if m.selectedGroup != 0 {
> + exts.AddUint16(extensionKeyShare)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint16(uint16(m.selectedGroup))
> + })
> + }
> + if len(m.supportedPoints) > 0 {
> + exts.AddUint16(extensionSupportedPoints)
> + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
> + exts.AddBytes(m.supportedPoints)
> + })
> + })
> + }
> +
> + extBytes, err := exts.Bytes()
> + if err != nil {
> + return nil, err
> }
>
> var b cryptobyte.Builder
> @@ -634,104 +732,15 @@
> b.AddUint16(m.cipherSuite)
> b.AddUint8(m.compressionMethod)
>
> - // If extensions aren't present, omit them.
> - var extensionsPresent bool
> - bWithoutExtensions := *b
> -
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - if m.ocspStapling {
> - b.AddUint16(extensionStatusRequest)
> - b.AddUint16(0) // empty extension_data
> - }
> - if m.ticketSupported {
> - b.AddUint16(extensionSessionTicket)
> - b.AddUint16(0) // empty extension_data
> - }
> - if m.secureRenegotiationSupported {
> - b.AddUint16(extensionRenegotiationInfo)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.secureRenegotiation)
> - })
> - })
> - }
> - if len(m.alpnProtocol) > 0 {
> - b.AddUint16(extensionALPN)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes([]byte(m.alpnProtocol))
> - })
> - })
> - })
> - }
> - if len(m.scts) > 0 {
> - b.AddUint16(extensionSCT)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - for _, sct := range m.scts {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(sct)
> - })
> - }
> - })
> - })
> - }
> - if m.supportedVersion != 0 {
> - b.AddUint16(extensionSupportedVersions)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16(m.supportedVersion)
> - })
> - }
> - if m.serverShare.group != 0 {
> - b.AddUint16(extensionKeyShare)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16(uint16(m.serverShare.group))
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.serverShare.data)
> - })
> - })
> - }
> - if m.selectedIdentityPresent {
> - b.AddUint16(extensionPreSharedKey)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16(m.selectedIdentity)
> - })
> - }
> -
> - if len(m.cookie) > 0 {
> - b.AddUint16(extensionCookie)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.cookie)
> - })
> - })
> - }
> - if m.selectedGroup != 0 {
> - b.AddUint16(extensionKeyShare)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint16(uint16(m.selectedGroup))
> - })
> - }
> - if len(m.supportedPoints) > 0 {
> - b.AddUint16(extensionSupportedPoints)
> - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> - b.AddBytes(m.supportedPoints)
> - })
> - })
> - }
> -
> - extensionsPresent = len(b.BytesOrPanic()) > 2
> - })
> -
> - if !extensionsPresent {
> - *b = bWithoutExtensions
> + if len(extBytes) > 0 {
> + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
> + b.AddBytes(extBytes)
> + })
> }
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *serverHelloMsg) unmarshal(data []byte) bool {
> @@ -855,9 +864,9 @@
> alpnProtocol string
> }
>
> -func (m *encryptedExtensionsMsg) marshal() []byte {
> +func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -877,8 +886,9 @@
> })
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
> @@ -926,10 +936,10 @@
>
> type endOfEarlyDataMsg struct{}
>
> -func (m *endOfEarlyDataMsg) marshal() []byte {
> +func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
> x := make([]byte, 4)
> x[0] = typeEndOfEarlyData
> - return x
> + return x, nil
> }
>
> func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
> @@ -941,9 +951,9 @@
> updateRequested bool
> }
>
> -func (m *keyUpdateMsg) marshal() []byte {
> +func (m *keyUpdateMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -956,8 +966,9 @@
> }
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *keyUpdateMsg) unmarshal(data []byte) bool {
> @@ -989,9 +1000,9 @@
> maxEarlyData uint32
> }
>
> -func (m *newSessionTicketMsgTLS13) marshal() []byte {
> +func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1016,8 +1027,9 @@
> })
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
> @@ -1070,9 +1082,9 @@
> certificateAuthorities [][]byte
> }
>
> -func (m *certificateRequestMsgTLS13) marshal() []byte {
> +func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1131,8 +1143,9 @@
> })
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
> @@ -1216,9 +1229,9 @@
> certificates [][]byte
> }
>
> -func (m *certificateMsg) marshal() (x []byte) {
> +func (m *certificateMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var i int
> @@ -1227,7 +1240,7 @@
> }
>
> length := 3 + 3*len(m.certificates) + i
> - x = make([]byte, 4+length)
> + x := make([]byte, 4+length)
> x[0] = typeCertificate
> x[1] = uint8(length >> 16)
> x[2] = uint8(length >> 8)
> @@ -1248,7 +1261,7 @@
> }
>
> m.raw = x
> - return
> + return m.raw, nil
> }
>
> func (m *certificateMsg) unmarshal(data []byte) bool {
> @@ -1295,9 +1308,9 @@
> scts bool
> }
>
> -func (m *certificateMsgTLS13) marshal() []byte {
> +func (m *certificateMsgTLS13) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1315,8 +1328,9 @@
> marshalCertificate(b, certificate)
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
> @@ -1439,9 +1453,9 @@
> key []byte
> }
>
> -func (m *serverKeyExchangeMsg) marshal() []byte {
> +func (m *serverKeyExchangeMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
> length := len(m.key)
> x := make([]byte, length+4)
> @@ -1452,7 +1466,7 @@
> copy(x[4:], m.key)
>
> m.raw = x
> - return x
> + return x, nil
> }
>
> func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
> @@ -1469,9 +1483,9 @@
> response []byte
> }
>
> -func (m *certificateStatusMsg) marshal() []byte {
> +func (m *certificateStatusMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1483,8 +1497,9 @@
> })
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *certificateStatusMsg) unmarshal(data []byte) bool {
> @@ -1503,10 +1518,10 @@
>
> type serverHelloDoneMsg struct{}
>
> -func (m *serverHelloDoneMsg) marshal() []byte {
> +func (m *serverHelloDoneMsg) marshal() ([]byte, error) {
> x := make([]byte, 4)
> x[0] = typeServerHelloDone
> - return x
> + return x, nil
> }
>
> func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
> @@ -1518,9 +1533,9 @@
> ciphertext []byte
> }
>
> -func (m *clientKeyExchangeMsg) marshal() []byte {
> +func (m *clientKeyExchangeMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
> length := len(m.ciphertext)
> x := make([]byte, length+4)
> @@ -1531,7 +1546,7 @@
> copy(x[4:], m.ciphertext)
>
> m.raw = x
> - return x
> + return x, nil
> }
>
> func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
> @@ -1552,9 +1567,9 @@
> verifyData []byte
> }
>
> -func (m *finishedMsg) marshal() []byte {
> +func (m *finishedMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1563,8 +1578,9 @@
> b.AddBytes(m.verifyData)
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *finishedMsg) unmarshal(data []byte) bool {
> @@ -1586,9 +1602,9 @@
> certificateAuthorities [][]byte
> }
>
> -func (m *certificateRequestMsg) marshal() (x []byte) {
> +func (m *certificateRequestMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> // See RFC 4346, Section 7.4.4.
> @@ -1603,7 +1619,7 @@
> length += 2 + 2*len(m.supportedSignatureAlgorithms)
> }
>
> - x = make([]byte, 4+length)
> + x := make([]byte, 4+length)
> x[0] = typeCertificateRequest
> x[1] = uint8(length >> 16)
> x[2] = uint8(length >> 8)
> @@ -1638,7 +1654,7 @@
> }
>
> m.raw = x
> - return
> + return m.raw, nil
> }
>
> func (m *certificateRequestMsg) unmarshal(data []byte) bool {
> @@ -1724,9 +1740,9 @@
> signature []byte
> }
>
> -func (m *certificateVerifyMsg) marshal() (x []byte) {
> +func (m *certificateVerifyMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> var b cryptobyte.Builder
> @@ -1740,8 +1756,9 @@
> })
> })
>
> - m.raw = b.BytesOrPanic()
> - return m.raw
> + var err error
> + m.raw, err = b.Bytes()
> + return m.raw, err
> }
>
> func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
> @@ -1764,15 +1781,15 @@
> ticket []byte
> }
>
> -func (m *newSessionTicketMsg) marshal() (x []byte) {
> +func (m *newSessionTicketMsg) marshal() ([]byte, error) {
> if m.raw != nil {
> - return m.raw
> + return m.raw, nil
> }
>
> // See RFC 5077, Section 3.3.
> ticketLen := len(m.ticket)
> length := 2 + 4 + ticketLen
> - x = make([]byte, 4+length)
> + x := make([]byte, 4+length)
> x[0] = typeNewSessionTicket
> x[1] = uint8(length >> 16)
> x[2] = uint8(length >> 8)
> @@ -1783,7 +1800,7 @@
>
> m.raw = x
>
> - return
> + return m.raw, nil
> }
>
> func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
> @@ -1811,10 +1828,25 @@
> type helloRequestMsg struct {
> }
>
> -func (*helloRequestMsg) marshal() []byte {
> - return []byte{typeHelloRequest, 0, 0, 0}
> +func (*helloRequestMsg) marshal() ([]byte, error) {
> + return []byte{typeHelloRequest, 0, 0, 0}, nil
> }
>
> func (*helloRequestMsg) unmarshal(data []byte) bool {
> return len(data) == 4
> }
> +
> +type transcriptHash interface {
> + Write([]byte) (int, error)
> +}
> +
> +// transcriptMsg is a helper used to marshal and hash messages which typically
> +// are not written to the wire, and as such aren't hashed during Conn.writeRecord.
> +func transcriptMsg(msg handshakeMessage, h transcriptHash) error {
> + data, err := msg.marshal()
> + if err != nil {
> + return err
> + }
> + h.Write(data)
> + return nil
> +}
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_messages_test.go golang-1.19-1.19.6/src/crypto/tls/handshake_messages_test.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_messages_test.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_messages_test.go 2023-02-14 01:38:45.000000000 +0800
> @@ -38,6 +38,15 @@
> &certificateMsgTLS13{},
> }
>
> +func mustMarshal(t *testing.T, msg handshakeMessage) []byte {
> + t.Helper()
> + b, err := msg.marshal()
> + if err != nil {
> + t.Fatal(err)
> + }
> + return b
> +}
> +
> func TestMarshalUnmarshal(t *testing.T) {
> rand := rand.New(rand.NewSource(time.Now().UnixNano()))
>
> @@ -56,7 +65,7 @@
> }
>
> m1 := v.Interface().(handshakeMessage)
> - marshaled := m1.marshal()
> + marshaled := mustMarshal(t, m1)
> m2 := iface.(handshakeMessage)
> if !m2.unmarshal(marshaled) {
> t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
> @@ -409,12 +418,12 @@
>
> var random [32]byte
> sct := []byte{0x42, 0x42, 0x42, 0x42}
> - serverHello := serverHelloMsg{
> + serverHello := &serverHelloMsg{
> vers: VersionTLS12,
> random: random[:],
> scts: [][]byte{sct},
> }
> - serverHelloBytes := serverHello.marshal()
> + serverHelloBytes := mustMarshal(t, serverHello)
>
> var serverHelloCopy serverHelloMsg
> if !serverHelloCopy.unmarshal(serverHelloBytes) {
> @@ -452,12 +461,12 @@
> // not be zero length.
>
> var random [32]byte
> - serverHello := serverHelloMsg{
> + serverHello := &serverHelloMsg{
> vers: VersionTLS12,
> random: random[:],
> scts: [][]byte{nil},
> }
> - serverHelloBytes := serverHello.marshal()
> + serverHelloBytes := mustMarshal(t, serverHello)
>
> var serverHelloCopy serverHelloMsg
> if serverHelloCopy.unmarshal(serverHelloBytes) {
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_server.go golang-1.19-1.19.6/src/crypto/tls/handshake_server.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_server.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_server.go 2023-02-14 01:38:45.000000000 +0800
> @@ -129,7 +129,9 @@
>
> // readClientHello reads a ClientHello message and selects the protocol version.
> func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
> - msg, err := c.readHandshake()
> + // clientHelloMsg is included in the transcript, but we haven't initialized
> + // it yet. The respective handshake functions will record it themselves.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return nil, err
> }
> @@ -463,9 +465,10 @@
> hs.hello.ticketSupported = hs.sessionState.usedOldKey
> hs.finishedHash = newFinishedHash(c.vers, hs.suite)
> hs.finishedHash.discardHandshakeBuffer()
> - hs.finishedHash.Write(hs.clientHello.marshal())
> - hs.finishedHash.Write(hs.hello.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
> + if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
> + return err
> + }
> + if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
> return err
> }
>
> @@ -503,24 +506,23 @@
> // certificates won't be used.
> hs.finishedHash.discardHandshakeBuffer()
> }
> - hs.finishedHash.Write(hs.clientHello.marshal())
> - hs.finishedHash.Write(hs.hello.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
> + if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
> + return err
> + }
> + if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
> return err
> }
>
> certMsg := new(certificateMsg)
> certMsg.certificates = hs.cert.Certificate
> - hs.finishedHash.Write(certMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
> return err
> }
>
> if hs.hello.ocspStapling {
> certStatus := new(certificateStatusMsg)
> certStatus.response = hs.cert.OCSPStaple
> - hs.finishedHash.Write(certStatus.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
> return err
> }
> }
> @@ -532,8 +534,7 @@
> return err
> }
> if skx != nil {
> - hs.finishedHash.Write(skx.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
> return err
> }
> }
> @@ -559,15 +560,13 @@
> if c.config.ClientCAs != nil {
> certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
> }
> - hs.finishedHash.Write(certReq.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
> return err
> }
> }
>
> helloDone := new(serverHelloDoneMsg)
> - hs.finishedHash.Write(helloDone.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
> return err
> }
>
> @@ -577,7 +576,7 @@
>
> var pub crypto.PublicKey // public key for client auth, if any
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -590,7 +589,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(certMsg, msg)
> }
> - hs.finishedHash.Write(certMsg.marshal())
>
> if err := c.processCertsFromClient(Certificate{
> Certificate: certMsg.certificates,
> @@ -601,7 +599,7 @@
> pub = c.peerCertificates[0].PublicKey
> }
>
> - msg, err = c.readHandshake()
> + msg, err = c.readHandshake(&hs.finishedHash)
> if err != nil {
> return err
> }
> @@ -619,7 +617,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(ckx, msg)
> }
> - hs.finishedHash.Write(ckx.marshal())
>
> preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
> if err != nil {
> @@ -639,7 +636,10 @@
> // to the client's certificate. This allows us to verify that the client is in
> // possession of the private key of the certificate.
> if len(c.peerCertificates) > 0 {
> - msg, err = c.readHandshake()
> + // certificateVerifyMsg is included in the transcript, but not until
> + // after we verify the handshake signature, since the state before
> + // this message was sent is used.
> + msg, err = c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -674,7 +674,9 @@
> return errors.New("tls: invalid signature by the client certificate: " + err.Error())
> }
>
> - hs.finishedHash.Write(certVerify.marshal())
> + if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
> + return err
> + }
> }
>
> hs.finishedHash.discardHandshakeBuffer()
> @@ -714,7 +716,10 @@
> return err
> }
>
> - msg, err := c.readHandshake()
> + // finishedMsg is included in the transcript, but not until after we
> + // check the client version, since the state before this message was
> + // sent is used during verification.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -731,7 +736,10 @@
> return errors.New("tls: client's Finished message is incorrect")
> }
>
> - hs.finishedHash.Write(clientFinished.marshal())
> + if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
> + return err
> + }
> +
> copy(out, verify)
> return nil
> }
> @@ -765,14 +773,16 @@
> masterSecret: hs.masterSecret,
> certificates: certsFromClient,
> }
> - var err error
> - m.ticket, err = c.encryptTicket(state.marshal())
> + stateBytes, err := state.marshal()
> + if err != nil {
> + return err
> + }
> + m.ticket, err = c.encryptTicket(stateBytes)
> if err != nil {
> return err
> }
>
> - hs.finishedHash.Write(m.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
> return err
> }
>
> @@ -782,14 +792,13 @@
> func (hs *serverHandshakeState) sendFinished(out []byte) error {
> c := hs.c
>
> - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
> + if err := c.writeChangeCipherRecord(); err != nil {
> return err
> }
>
> finished := new(finishedMsg)
> finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
> - hs.finishedHash.Write(finished.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
> return err
> }
>
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_server_test.go golang-1.19-1.19.6/src/crypto/tls/handshake_server_test.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_server_test.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_server_test.go 2023-02-14 01:38:45.000000000 +0800
> @@ -30,6 +30,13 @@
> testClientHelloFailure(t, serverConfig, m, "")
> }
>
> +// testFatal is a hack to prevent the compiler from complaining that there is a
> +// call to t.Fatal from a non-test goroutine
> +func testFatal(t *testing.T, err error) {
> + t.Helper()
> + t.Fatal(err)
> +}
> +
> func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
> c, s := localPipe(t)
> go func() {
> @@ -37,7 +44,9 @@
> if ch, ok := m.(*clientHelloMsg); ok {
> cli.vers = ch.vers
> }
> - cli.writeRecord(recordTypeHandshake, m.marshal())
> + if _, err := cli.writeHandshakeRecord(m, nil); err != nil {
> + testFatal(t, err)
> + }
> c.Close()
> }()
> ctx := context.Background()
> @@ -194,7 +203,9 @@
> go func() {
> cli := Client(c, testConfig)
> cli.vers = clientHello.vers
> - cli.writeRecord(recordTypeHandshake, clientHello.marshal())
> + if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
> + testFatal(t, err)
> + }
>
> buf := make([]byte, 1024)
> n, err := c.Read(buf)
> @@ -253,8 +264,10 @@
> go func() {
> cli := Client(c, testConfig)
> cli.vers = clientHello.vers
> - cli.writeRecord(recordTypeHandshake, clientHello.marshal())
> - reply, err := cli.readHandshake()
> + if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
> + testFatal(t, err)
> + }
> + reply, err := cli.readHandshake(nil)
> c.Close()
> if err != nil {
> replyChan <- err
> @@ -311,8 +324,10 @@
> go func() {
> cli := Client(c, testConfig)
> cli.vers = clientHello.vers
> - cli.writeRecord(recordTypeHandshake, clientHello.marshal())
> - reply, err := cli.readHandshake()
> + if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
> + testFatal(t, err)
> + }
> + reply, err := cli.readHandshake(nil)
> c.Close()
> if err != nil {
> replyChan <- err
> @@ -1426,7 +1441,9 @@
> go func() {
> cli := Client(c, testConfig)
> cli.vers = clientHello.vers
> - cli.writeRecord(recordTypeHandshake, clientHello.marshal())
> + if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
> + testFatal(t, err)
> + }
> c.Close()
> }()
> conn := Server(s, serverConfig)
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/handshake_server_tls13.go golang-1.19-1.19.6/src/crypto/tls/handshake_server_tls13.go
> --- golang-1.19-1.19.5/src/crypto/tls/handshake_server_tls13.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/handshake_server_tls13.go 2023-02-14 01:38:45.000000000 +0800
> @@ -302,7 +302,12 @@
> c.sendAlert(alertInternalError)
> return errors.New("tls: internal error: failed to clone hash")
> }
> - transcript.Write(hs.clientHello.marshalWithoutBinders())
> + clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
> + if err != nil {
> + c.sendAlert(alertInternalError)
> + return err
> + }
> + transcript.Write(clientHelloBytes)
> pskBinder := hs.suite.finishedHash(binderKey, transcript)
> if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
> c.sendAlert(alertDecryptError)
> @@ -393,8 +398,7 @@
> }
> hs.sentDummyCCS = true
>
> - _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
> - return err
> + return hs.c.writeChangeCipherRecord()
> }
>
> func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
> @@ -402,7 +406,9 @@
>
> // The first ClientHello gets double-hashed into the transcript upon a
> // HelloRetryRequest. See RFC 8446, Section 4.4.1.
> - hs.transcript.Write(hs.clientHello.marshal())
> + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
> + return err
> + }
> chHash := hs.transcript.Sum(nil)
> hs.transcript.Reset()
> hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
> @@ -418,8 +424,7 @@
> selectedGroup: selectedGroup,
> }
>
> - hs.transcript.Write(helloRetryRequest.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
> return err
> }
>
> @@ -427,7 +432,8 @@
> return err
> }
>
> - msg, err := c.readHandshake()
> + // clientHelloMsg is not included in the transcript.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -518,9 +524,10 @@
> func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
> c := hs.c
>
> - hs.transcript.Write(hs.clientHello.marshal())
> - hs.transcript.Write(hs.hello.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
> + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
> + return err
> + }
> + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
> return err
> }
>
> @@ -563,8 +570,7 @@
> encryptedExtensions.alpnProtocol = selectedProto
> c.clientProtocol = selectedProto
>
> - hs.transcript.Write(encryptedExtensions.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil {
> return err
> }
>
> @@ -593,8 +599,7 @@
> certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
> }
>
> - hs.transcript.Write(certReq.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
> return err
> }
> }
> @@ -605,8 +610,7 @@
> certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
> certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
>
> - hs.transcript.Write(certMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
> return err
> }
>
> @@ -637,8 +641,7 @@
> }
> certVerifyMsg.signature = sig
>
> - hs.transcript.Write(certVerifyMsg.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
> return err
> }
>
> @@ -652,8 +655,7 @@
> verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
> }
>
> - hs.transcript.Write(finished.marshal())
> - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
> + if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
> return err
> }
>
> @@ -714,7 +716,9 @@
> finishedMsg := &finishedMsg{
> verifyData: hs.clientFinished,
> }
> - hs.transcript.Write(finishedMsg.marshal())
> + if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
> + return err
> + }
>
> if !hs.shouldSendSessionTickets() {
> return nil
> @@ -739,8 +743,12 @@
> SignedCertificateTimestamps: c.scts,
> },
> }
> - var err error
> - m.label, err = c.encryptTicket(state.marshal())
> + stateBytes, err := state.marshal()
> + if err != nil {
> + c.sendAlert(alertInternalError)
> + return err
> + }
> + m.label, err = c.encryptTicket(stateBytes)
> if err != nil {
> return err
> }
> @@ -759,7 +767,7 @@
> // ticket_nonce, which must be unique per connection, is always left at
> // zero because we only ever send one ticket per connection.
>
> - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
> + if _, err := c.writeHandshakeRecord(m, nil); err != nil {
> return err
> }
>
> @@ -784,7 +792,7 @@
> // If we requested a client certificate, then the client must send a
> // certificate message. If it's empty, no CertificateVerify is sent.
>
> - msg, err := c.readHandshake()
> + msg, err := c.readHandshake(hs.transcript)
> if err != nil {
> return err
> }
> @@ -794,7 +802,6 @@
> c.sendAlert(alertUnexpectedMessage)
> return unexpectedMessageError(certMsg, msg)
> }
> - hs.transcript.Write(certMsg.marshal())
>
> if err := c.processCertsFromClient(certMsg.certificate); err != nil {
> return err
> @@ -808,7 +815,10 @@
> }
>
> if len(certMsg.certificate.Certificate) != 0 {
> - msg, err = c.readHandshake()
> + // certificateVerifyMsg is included in the transcript, but not until
> + // after we verify the handshake signature, since the state before
> + // this message was sent is used.
> + msg, err = c.readHandshake(nil)
> if err != nil {
> return err
> }
> @@ -839,7 +849,9 @@
> return errors.New("tls: invalid signature by the client certificate: " + err.Error())
> }
>
> - hs.transcript.Write(certVerify.marshal())
> + if err := transcriptMsg(certVerify, hs.transcript); err != nil {
> + return err
> + }
> }
>
> // If we waited until the client certificates to send session tickets, we
> @@ -854,7 +866,8 @@
> func (hs *serverHandshakeStateTLS13) readClientFinished() error {
> c := hs.c
>
> - msg, err := c.readHandshake()
> + // finishedMsg is not included in the transcript.
> + msg, err := c.readHandshake(nil)
> if err != nil {
> return err
> }
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/key_schedule.go golang-1.19-1.19.6/src/crypto/tls/key_schedule.go
> --- golang-1.19-1.19.5/src/crypto/tls/key_schedule.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/key_schedule.go 2023-02-14 01:38:45.000000000 +0800
> @@ -8,6 +8,7 @@
> "crypto/elliptic"
> "crypto/hmac"
> "errors"
> + "fmt"
> "hash"
> "io"
> "math/big"
> @@ -42,8 +43,24 @@
> hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
> b.AddBytes(context)
> })
> + hkdfLabelBytes, err := hkdfLabel.Bytes()
> + if err != nil {
> + // Rather than calling BytesOrPanic, we explicitly handle this error, in
> + // order to provide a reasonable error message. It should be basically
> + // impossible for this to panic, and routing errors back through the
> + // tree rooted in this function is quite painful. The labels are fixed
> + // size, and the context is either a fixed-length computed hash, or
> + // parsed from a field which has the same length limitation. As such, an
> + // error here is likely to only be caused during development.
> + //
> + // NOTE: another reasonable approach here might be to return a
> + // randomized slice if we encounter an error, which would break the
> + // connection, but avoid panicking. This would perhaps be safer but
> + // significantly more confusing to users.
> + panic(fmt.Errorf("failed to construct HKDF label: %s", err))
> + }
> out := make([]byte, length)
> - n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
> + n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
> if err != nil || n != length {
> panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
> }
> diff -Nru golang-1.19-1.19.5/src/crypto/tls/ticket.go golang-1.19-1.19.6/src/crypto/tls/ticket.go
> --- golang-1.19-1.19.5/src/crypto/tls/ticket.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/tls/ticket.go 2023-02-14 01:38:45.000000000 +0800
> @@ -32,7 +32,7 @@
> usedOldKey bool
> }
>
> -func (m *sessionState) marshal() []byte {
> +func (m *sessionState) marshal() ([]byte, error) {
> var b cryptobyte.Builder
> b.AddUint16(m.vers)
> b.AddUint16(m.cipherSuite)
> @@ -47,7 +47,7 @@
> })
> }
> })
> - return b.BytesOrPanic()
> + return b.Bytes()
> }
>
> func (m *sessionState) unmarshal(data []byte) bool {
> @@ -86,7 +86,7 @@
> certificate Certificate // CertificateEntry certificate_list<0..2^24-1>;
> }
>
> -func (m *sessionStateTLS13) marshal() []byte {
> +func (m *sessionStateTLS13) marshal() ([]byte, error) {
> var b cryptobyte.Builder
> b.AddUint16(VersionTLS13)
> b.AddUint8(0) // revision
> @@ -96,7 +96,7 @@
> b.AddBytes(m.resumptionSecret)
> })
> marshalCertificate(&b, m.certificate)
> - return b.BytesOrPanic()
> + return b.Bytes()
> }
>
> func (m *sessionStateTLS13) unmarshal(data []byte) bool {
> diff -Nru golang-1.19-1.19.5/src/crypto/x509/boring_test.go golang-1.19-1.19.6/src/crypto/x509/boring_test.go
> --- golang-1.19-1.19.5/src/crypto/x509/boring_test.go 2023-01-10 06:38:14.000000000 +0800
> +++ golang-1.19-1.19.6/src/crypto/x509/boring_test.go 2023-02-14 01:38:45.000000000 +0800
> @@ -54,7 +54,7 @@
>
> func TestBoringAllowCert(t *testing.T) {
> R1 := testBoringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
> - R2 := testBoringCert(t, "R2", boringRSAKey(t, 8192), nil, boringCertCA)
> + R2 := testBoringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA)
> R3 := testBoringCert(t, "R3", boringRSAKey(t, 4096), nil, boringCertCA|boringCertFIPSOK)
>
> M1_R1 := testBoringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
> diff -Nru golang-1.19-1.19.5/src/mime/multipart/formdata.go golang-1.19-1.19.6/src/mime/multipart/formdata.go
> --- golang-1.19-1.19.5/src/mime/multipart/formdata.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/mime/multipart/formdata.go 2023-02-14 01:38:47.000000000 +0800
> @@ -7,6 +7,7 @@
> import (
> "bytes"
> "errors"
> + "internal/godebug"
> "io"
> "math"
> "net/textproto"
> @@ -33,23 +34,58 @@
>
> func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
> form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
> + var (
> + file *os.File
> + fileOff int64
> + )
> + numDiskFiles := 0
> + multipartFiles := godebug.Get("multipartfiles")
> + combineFiles := multipartFiles != "distinct"
> defer func() {
> + if file != nil {
> + if cerr := file.Close(); err == nil {
> + err = cerr
> + }
> + }
> + if combineFiles && numDiskFiles > 1 {
> + for _, fhs := range form.File {
> + for _, fh := range fhs {
> + fh.tmpshared = true
> + }
> + }
> + }
> if err != nil {
> form.RemoveAll()
> + if file != nil {
> + os.Remove(file.Name())
> + }
> }
> }()
>
> - // Reserve an additional 10 MB for non-file parts.
> - maxValueBytes := maxMemory + int64(10<<20)
> - if maxValueBytes <= 0 {
> + // maxFileMemoryBytes is the maximum bytes of file data we will store in memory.
> + // Data past this limit is written to disk.
> + // This limit strictly applies to content, not metadata (filenames, MIME headers, etc.),
> + // since metadata is always stored in memory, not disk.
> + //
> + // maxMemoryBytes is the maximum bytes we will store in memory, including file content,
> + // non-file part values, metdata, and map entry overhead.
> + //
> + // We reserve an additional 10 MB in maxMemoryBytes for non-file data.
> + //
> + // The relationship between these parameters, as well as the overly-large and
> + // unconfigurable 10 MB added on to maxMemory, is unfortunate but difficult to change
> + // within the constraints of the API as documented.
> + maxFileMemoryBytes := maxMemory
> + maxMemoryBytes := maxMemory + int64(10<<20)
> + if maxMemoryBytes <= 0 {
> if maxMemory < 0 {
> - maxValueBytes = 0
> + maxMemoryBytes = 0
> } else {
> - maxValueBytes = math.MaxInt64
> + maxMemoryBytes = math.MaxInt64
> }
> }
> for {
> - p, err := r.NextPart()
> + p, err := r.nextPart(false, maxMemoryBytes)
> if err == io.EOF {
> break
> }
> @@ -63,16 +99,27 @@
> }
> filename := p.FileName()
>
> + // Multiple values for the same key (one map entry, longer slice) are cheaper
> + // than the same number of values for different keys (many map entries), but
> + // using a consistent per-value cost for overhead is simpler.
> + maxMemoryBytes -= int64(len(name))
> + maxMemoryBytes -= 100 // map overhead
> + if maxMemoryBytes < 0 {
> + // We can't actually take this path, since nextPart would already have
> + // rejected the MIME headers for being too large. Check anyway.
> + return nil, ErrMessageTooLarge
> + }
> +
> var b bytes.Buffer
>
> if filename == "" {
> // value, store as string in memory
> - n, err := io.CopyN(&b, p, maxValueBytes+1)
> + n, err := io.CopyN(&b, p, maxMemoryBytes+1)
> if err != nil && err != io.EOF {
> return nil, err
> }
> - maxValueBytes -= n
> - if maxValueBytes < 0 {
> + maxMemoryBytes -= n
> + if maxMemoryBytes < 0 {
> return nil, ErrMessageTooLarge
> }
> form.Value[name] = append(form.Value[name], b.String())
> @@ -80,35 +127,45 @@
> }
>
> // file, store in memory or on disk
> + maxMemoryBytes -= mimeHeaderSize(p.Header)
> + if maxMemoryBytes < 0 {
> + return nil, ErrMessageTooLarge
> + }
> fh := &FileHeader{
> Filename: filename,
> Header: p.Header,
> }
> - n, err := io.CopyN(&b, p, maxMemory+1)
> + n, err := io.CopyN(&b, p, maxFileMemoryBytes+1)
> if err != nil && err != io.EOF {
> return nil, err
> }
> - if n > maxMemory {
> - // too big, write to disk and flush buffer
> - file, err := os.CreateTemp("", "multipart-")
> - if err != nil {
> - return nil, err
> + if n > maxFileMemoryBytes {
> + if file == nil {
> + file, err = os.CreateTemp(r.tempDir, "multipart-")
> + if err != nil {
> + return nil, err
> + }
> }
> + numDiskFiles++
> size, err := io.Copy(file, io.MultiReader(&b, p))
> - if cerr := file.Close(); err == nil {
> - err = cerr
> - }
> if err != nil {
> - os.Remove(file.Name())
> return nil, err
> }
> fh.tmpfile = file.Name()
> fh.Size = size
> + fh.tmpoff = fileOff
> + fileOff += size
> + if !combineFiles {
> + if err := file.Close(); err != nil {
> + return nil, err
> + }
> + file = nil
> + }
> } else {
> fh.content = b.Bytes()
> fh.Size = int64(len(fh.content))
> - maxMemory -= n
> - maxValueBytes -= n
> + maxFileMemoryBytes -= n
> + maxMemoryBytes -= n
> }
> form.File[name] = append(form.File[name], fh)
> }
> @@ -116,6 +173,17 @@
> return form, nil
> }
>
> +func mimeHeaderSize(h textproto.MIMEHeader) (size int64) {
> + for k, vs := range h {
> + size += int64(len(k))
> + size += 100 // map entry overhead
> + for _, v := range vs {
> + size += int64(len(v))
> + }
> + }
> + return size
> +}
> +
> // Form is a parsed multipart form.
> // Its File parts are stored either in memory or on disk,
> // and are accessible via the *FileHeader's Open method.
> @@ -133,7 +201,7 @@
> for _, fh := range fhs {
> if fh.tmpfile != "" {
> e := os.Remove(fh.tmpfile)
> - if e != nil && err == nil {
> + if e != nil && !errors.Is(e, os.ErrNotExist) && err == nil {
> err = e
> }
> }
> @@ -148,15 +216,25 @@
> Header textproto.MIMEHeader
> Size int64
>
> - content []byte
> - tmpfile string
> + content []byte
> + tmpfile string
> + tmpoff int64
> + tmpshared bool
> }
>
> // Open opens and returns the FileHeader's associated File.
> func (fh *FileHeader) Open() (File, error) {
> if b := fh.content; b != nil {
> r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
> - return sectionReadCloser{r}, nil
> + return sectionReadCloser{r, nil}, nil
> + }
> + if fh.tmpshared {
> + f, err := os.Open(fh.tmpfile)
> + if err != nil {
> + return nil, err
> + }
> + r := io.NewSectionReader(f, fh.tmpoff, fh.Size)
> + return sectionReadCloser{r, f}, nil
> }
> return os.Open(fh.tmpfile)
> }
> @@ -175,8 +253,12 @@
>
> type sectionReadCloser struct {
> *io.SectionReader
> + io.Closer
> }
>
> func (rc sectionReadCloser) Close() error {
> + if rc.Closer != nil {
> + return rc.Closer.Close()
> + }
> return nil
> }
> diff -Nru golang-1.19-1.19.5/src/mime/multipart/formdata_test.go golang-1.19-1.19.6/src/mime/multipart/formdata_test.go
> --- golang-1.19-1.19.5/src/mime/multipart/formdata_test.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/mime/multipart/formdata_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -6,8 +6,10 @@
>
> import (
> "bytes"
> + "fmt"
> "io"
> "math"
> + "net/textproto"
> "os"
> "strings"
> "testing"
> @@ -208,8 +210,8 @@
> maxMemory int64
> err error
> }{
> - {"smaller", 50, nil},
> - {"exact-fit", 25, nil},
> + {"smaller", 50 + int64(len("largetext")) + 100, nil},
> + {"exact-fit", 25 + int64(len("largetext")) + 100, nil},
> {"too-large", 0, ErrMessageTooLarge},
> }
> for _, tc := range testCases {
> @@ -224,7 +226,7 @@
> defer f.RemoveAll()
> }
> if tc.err != err {
> - t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err)
> + t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err)
> }
> if err == nil {
> if g := f.Value["largetext"][0]; g != largeTextValue {
> @@ -234,3 +236,135 @@
> })
> }
> }
> +
> +// TestReadForm_MetadataTooLarge verifies that we account for the size of field names,
> +// MIME headers, and map entry overhead while limiting the memory consumption of parsed forms.
> +func TestReadForm_MetadataTooLarge(t *testing.T) {
> + for _, test := range []struct {
> + name string
> + f func(*Writer)
> + }{{
> + name: "large name",
> + f: func(fw *Writer) {
> + name := strings.Repeat("a", 10<<20)
> + w, _ := fw.CreateFormField(name)
> + w.Write([]byte("value"))
> + },
> + }, {
> + name: "large MIME header",
> + f: func(fw *Writer) {
> + h := make(textproto.MIMEHeader)
> + h.Set("Content-Disposition", `form-data; name="a"`)
> + h.Set("X-Foo", strings.Repeat("a", 10<<20))
> + w, _ := fw.CreatePart(h)
> + w.Write([]byte("value"))
> + },
> + }, {
> + name: "many parts",
> + f: func(fw *Writer) {
> + for i := 0; i < 110000; i++ {
> + w, _ := fw.CreateFormField("f")
> + w.Write([]byte("v"))
> + }
> + },
> + }} {
> + t.Run(test.name, func(t *testing.T) {
> + var buf bytes.Buffer
> + fw := NewWriter(&buf)
> + test.f(fw)
> + if err := fw.Close(); err != nil {
> + t.Fatal(err)
> + }
> + fr := NewReader(&buf, fw.Boundary())
> + _, err := fr.ReadForm(0)
> + if err != ErrMessageTooLarge {
> + t.Errorf("fr.ReadForm() = %v, want ErrMessageTooLarge", err)
> + }
> + })
> + }
> +}
> +
> +// TestReadForm_ManyFiles_Combined tests that a multipart form containing many files only
> +// results in a single on-disk file.
> +func TestReadForm_ManyFiles_Combined(t *testing.T) {
> + const distinct = false
> + testReadFormManyFiles(t, distinct)
> +}
> +
> +// TestReadForm_ManyFiles_Distinct tests that setting GODEBUG=multipartfiles=distinct
> +// results in every file in a multipart form being placed in a distinct on-disk file.
> +func TestReadForm_ManyFiles_Distinct(t *testing.T) {
> + t.Setenv("GODEBUG", "multipartfiles=distinct")
> + const distinct = true
> + testReadFormManyFiles(t, distinct)
> +}
> +
> +func testReadFormManyFiles(t *testing.T, distinct bool) {
> + var buf bytes.Buffer
> + fw := NewWriter(&buf)
> + const numFiles = 10
> + for i := 0; i < numFiles; i++ {
> + name := fmt.Sprint(i)
> + w, err := fw.CreateFormFile(name, name)
> + if err != nil {
> + t.Fatal(err)
> + }
> + w.Write([]byte(name))
> + }
> + if err := fw.Close(); err != nil {
> + t.Fatal(err)
> + }
> + fr := NewReader(&buf, fw.Boundary())
> + fr.tempDir = t.TempDir()
> + form, err := fr.ReadForm(0)
> + if err != nil {
> + t.Fatal(err)
> + }
> + for i := 0; i < numFiles; i++ {
> + name := fmt.Sprint(i)
> + if got := len(form.File[name]); got != 1 {
> + t.Fatalf("form.File[%q] has %v entries, want 1", name, got)
> + }
> + fh := form.File[name][0]
> + file, err := fh.Open()
> + if err != nil {
> + t.Fatalf("form.File[%q].Open() = %v", name, err)
> + }
> + if distinct {
> + if _, ok := file.(*os.File); !ok {
> + t.Fatalf("form.File[%q].Open: %T, want *os.File", name, file)
> + }
> + }
> + got, err := io.ReadAll(file)
> + file.Close()
> + if string(got) != name || err != nil {
> + t.Fatalf("read form.File[%q]: %q, %v; want %q, nil", name, string(got), err, name)
> + }
> + }
> + dir, err := os.Open(fr.tempDir)
> + if err != nil {
> + t.Fatal(err)
> + }
> + defer dir.Close()
> + names, err := dir.Readdirnames(0)
> + if err != nil {
> + t.Fatal(err)
> + }
> + wantNames := 1
> + if distinct {
> + wantNames = numFiles
> + }
> + if len(names) != wantNames {
> + t.Fatalf("temp dir contains %v files; want 1", len(names))
> + }
> + if err := form.RemoveAll(); err != nil {
> + t.Fatalf("form.RemoveAll() = %v", err)
> + }
> + names, err = dir.Readdirnames(0)
> + if err != nil {
> + t.Fatal(err)
> + }
> + if len(names) != 0 {
> + t.Fatalf("temp dir contains %v files; want 0", len(names))
> + }
> +}
> diff -Nru golang-1.19-1.19.5/src/mime/multipart/multipart.go golang-1.19-1.19.6/src/mime/multipart/multipart.go
> --- golang-1.19-1.19.5/src/mime/multipart/multipart.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/mime/multipart/multipart.go 2023-02-14 01:38:47.000000000 +0800
> @@ -128,12 +128,12 @@
> return n, r.err
> }
>
> -func newPart(mr *Reader, rawPart bool) (*Part, error) {
> +func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
> bp := &Part{
> Header: make(map[string][]string),
> mr: mr,
> }
> - if err := bp.populateHeaders(); err != nil {
> + if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil {
> return nil, err
> }
> bp.r = partReader{bp}
> @@ -149,12 +149,16 @@
> return bp, nil
> }
>
> -func (p *Part) populateHeaders() error {
> +func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error {
> r := textproto.NewReader(p.mr.bufReader)
> - header, err := r.ReadMIMEHeader()
> + header, err := readMIMEHeader(r, maxMIMEHeaderSize)
> if err == nil {
> p.Header = header
> }
> + // TODO: Add a distinguishable error to net/textproto.
> + if err != nil && err.Error() == "message too large" {
> + err = ErrMessageTooLarge
> + }
> return err
> }
>
> @@ -311,6 +315,7 @@
> // isn't supported.
> type Reader struct {
> bufReader *bufio.Reader
> + tempDir string // used in tests
>
> currentPart *Part
> partsRead int
> @@ -321,6 +326,10 @@
> dashBoundary []byte // "--boundary"
> }
>
> +// maxMIMEHeaderSize is the maximum size of a MIME header we will parse,
> +// including header keys, values, and map overhead.
> +const maxMIMEHeaderSize = 10 << 20
> +
> // NextPart returns the next part in the multipart or an error.
> // When there are no more parts, the error io.EOF is returned.
> //
> @@ -328,7 +337,7 @@
> // has a value of "quoted-printable", that header is instead
> // hidden and the body is transparently decoded during Read calls.
> func (r *Reader) NextPart() (*Part, error) {
> - return r.nextPart(false)
> + return r.nextPart(false, maxMIMEHeaderSize)
> }
>
> // NextRawPart returns the next part in the multipart or an error.
> @@ -337,10 +346,10 @@
> // Unlike NextPart, it does not have special handling for
> // "Content-Transfer-Encoding: quoted-printable".
> func (r *Reader) NextRawPart() (*Part, error) {
> - return r.nextPart(true)
> + return r.nextPart(true, maxMIMEHeaderSize)
> }
>
> -func (r *Reader) nextPart(rawPart bool) (*Part, error) {
> +func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
> if r.currentPart != nil {
> r.currentPart.Close()
> }
> @@ -365,7 +374,7 @@
>
> if r.isBoundaryDelimiterLine(line) {
> r.partsRead++
> - bp, err := newPart(r, rawPart)
> + bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
> if err != nil {
> return nil, err
> }
> diff -Nru golang-1.19-1.19.5/src/mime/multipart/readmimeheader.go golang-1.19-1.19.6/src/mime/multipart/readmimeheader.go
> --- golang-1.19-1.19.5/src/mime/multipart/readmimeheader.go 1970-01-01 08:00:00.000000000 +0800
> +++ golang-1.19-1.19.6/src/mime/multipart/readmimeheader.go 2023-02-14 01:38:47.000000000 +0800
> @@ -0,0 +1,14 @@
> +// Copyright 2023 The Go Authors. All rights reserved.
> +// Use of this source code is governed by a BSD-style
> +// license that can be found in the LICENSE file.
> +package multipart
> +
> +import (
> + "net/textproto"
> + _ "unsafe" // for go:linkname
> +)
> +
> +// readMIMEHeader is defined in package net/textproto.
> +//
> +//go:linkname readMIMEHeader net/textproto.readMIMEHeader
> +func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error)
> diff -Nru golang-1.19-1.19.5/src/net/http/readrequest_test.go golang-1.19-1.19.6/src/net/http/readrequest_test.go
> --- golang-1.19-1.19.5/src/net/http/readrequest_test.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/net/http/readrequest_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -450,16 +450,19 @@
> Content-Length: 4
>
> abc`)},
> - {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
> + {"smuggle_two_content_len_head", reqBytes(`HEAD / HTTP/1.1
> Host: foo
> -Content-Length: 5`)},
> +Content-Length: 4
> +Content-Length: 5
> +
> +1234`)},
>
> // golang.org/issue/22464
> {"leading_space_in_header", reqBytes(`HEAD / HTTP/1.1
> Host: foo
> Content-Length: 5`)},
> {"leading_tab_in_header", reqBytes(`HEAD / HTTP/1.1
> -\tHost: foo
> +` + "\t" + `Host: foo
> Content-Length: 5`)},
> }
>
> diff -Nru golang-1.19-1.19.5/src/net/http/request_test.go golang-1.19-1.19.6/src/net/http/request_test.go
> --- golang-1.19-1.19.5/src/net/http/request_test.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/net/http/request_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -485,10 +485,6 @@
> 1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
> 2: {"", io.EOF.Error(), nil},
> 3: {
> - in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
> - err: "http: method cannot contain a Content-Length",
> - },
> - 4: {
> in: "HEAD / HTTP/1.1\r\n\r\n",
> header: Header{},
> },
> @@ -496,32 +492,32 @@
> // Multiple Content-Length values should either be
> // deduplicated if same or reject otherwise
> // See Issue 16490.
> - 5: {
> + 4: {
> in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
> err: "cannot contain multiple Content-Length headers",
> },
> - 6: {
> + 5: {
> in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
> err: "cannot contain multiple Content-Length headers",
> },
> - 7: {
> + 6: {
> in: "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
> err: "",
> header: Header{"Content-Length": {"6"}},
> },
> - 8: {
> + 7: {
> in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
> err: "cannot contain multiple Content-Length headers",
> },
> - 9: {
> + 8: {
> in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
> err: "cannot contain multiple Content-Length headers",
> },
> - 10: {
> + 9: {
> in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
> header: Header{"Content-Length": {"0"}},
> },
> - 11: {
> + 10: {
> in: "HEAD / HTTP/1.1\r\nHost: foo\r\nHost: bar\r\n\r\n\r\n\r\n",
> err: "too many Host headers",
> },
> @@ -1108,7 +1104,7 @@
> t.Errorf("FormFile file = %v, want nil", f)
> }
> if fh != nil {
> - t.Errorf("FormFile file header = %q, want nil", fh)
> + t.Errorf("FormFile file header = %v, want nil", fh)
> }
> if err != ErrMissingFile {
> t.Errorf("FormFile err = %q, want ErrMissingFile", err)
> diff -Nru golang-1.19-1.19.5/src/net/http/serve_test.go golang-1.19-1.19.6/src/net/http/serve_test.go
> --- golang-1.19-1.19.5/src/net/http/serve_test.go 2023-01-10 06:38:18.000000000 +0800
> +++ golang-1.19-1.19.6/src/net/http/serve_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -6758,3 +6758,73 @@
> t.Errorf("unexpected response; got %q; should start by %q", got, expected)
> }
> }
> +
> +func TestHeadBody(t *testing.T) {
> + const identityMode = false
> + const chunkedMode = true
> + t.Run("h1", func(t *testing.T) {
> + t.Run("identity", func(t *testing.T) { testHeadBody(t, h1Mode, identityMode, "HEAD") })
> + t.Run("chunked", func(t *testing.T) { testHeadBody(t, h1Mode, chunkedMode, "HEAD") })
> + })
> + t.Run("h2", func(t *testing.T) {
> + t.Run("identity", func(t *testing.T) { testHeadBody(t, h2Mode, identityMode, "HEAD") })
> + t.Run("chunked", func(t *testing.T) { testHeadBody(t, h2Mode, chunkedMode, "HEAD") })
> + })
> +}
> +
> +func TestGetBody(t *testing.T) {
> + const identityMode = false
> + const chunkedMode = true
> + t.Run("h1", func(t *testing.T) {
> + t.Run("identity", func(t *testing.T) { testHeadBody(t, h1Mode, identityMode, "GET") })
> + t.Run("chunked", func(t *testing.T) { testHeadBody(t, h1Mode, chunkedMode, "GET") })
> + })
> + t.Run("h2", func(t *testing.T) {
> + t.Run("identity", func(t *testing.T) { testHeadBody(t, h2Mode, identityMode, "GET") })
> + t.Run("chunked", func(t *testing.T) { testHeadBody(t, h2Mode, chunkedMode, "GET") })
> + })
> +}
> +
> +func testHeadBody(t *testing.T, h2, chunked bool, method string) {
> + setParallel(t)
> + defer afterTest(t)
> + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
> + b, err := io.ReadAll(r.Body)
> + if err != nil {
> + t.Errorf("server reading body: %v", err)
> + return
> + }
> + w.Header().Set("X-Request-Body", string(b))
> + w.Header().Set("Content-Length", "0")
> + }))
> + defer cst.close()
> + for _, reqBody := range []string{
> + "",
> + "",
> + "request_body",
> + "",
> + } {
> + var bodyReader io.Reader
> + if reqBody != "" {
> + bodyReader = strings.NewReader(reqBody)
> + if chunked {
> + bodyReader = bufio.NewReader(bodyReader)
> + }
> + }
> + req, err := NewRequest(method, cst.ts.URL, bodyReader)
> + if err != nil {
> + t.Fatal(err)
> + }
> + res, err := cst.c.Do(req)
> + if err != nil {
> + t.Fatal(err)
> + }
> + res.Body.Close()
> + if got, want := res.StatusCode, 200; got != want {
> + t.Errorf("%v request with %d-byte body: StatusCode = %v, want %v", method, len(reqBody), got, want)
> + }
> + if got, want := res.Header.Get("X-Request-Body"), reqBody; got != want {
> + t.Errorf("%v request with %d-byte body: handler read body %q, want %q", method, len(reqBody), got, want)
> + }
> + }
> +}
> diff -Nru golang-1.19-1.19.5/src/net/http/transfer.go golang-1.19-1.19.6/src/net/http/transfer.go
> --- golang-1.19-1.19.5/src/net/http/transfer.go 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/net/http/transfer.go 2023-02-14 01:38:47.000000000 +0800
> @@ -557,7 +557,7 @@
> // or close connection when finished, since multipart is not supported yet
> switch {
> case t.Chunked:
> - if noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode) {
> + if isResponse && (noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode)) {
> t.Body = NoBody
> } else {
> t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
> @@ -691,14 +691,7 @@
> }
>
> // Logic based on response type or status
> - if noResponseBodyExpected(requestMethod) {
> - // For HTTP requests, as part of hardening against request
> - // smuggling (RFC 7230), don't allow a Content-Length header for
> - // methods which don't permit bodies. As an exception, allow
> - // exactly one Content-Length header if its value is "0".
> - if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") {
> - return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens)
> - }
> + if isResponse && noResponseBodyExpected(requestMethod) {
> return 0, nil
> }
> if status/100 == 1 {
> diff -Nru golang-1.19-1.19.5/src/net/textproto/reader.go golang-1.19-1.19.6/src/net/textproto/reader.go
> --- golang-1.19-1.19.5/src/net/textproto/reader.go 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/net/textproto/reader.go 2023-02-14 01:38:47.000000000 +0800
> @@ -7,8 +7,10 @@
> import (
> "bufio"
> "bytes"
> + "errors"
> "fmt"
> "io"
> + "math"
> "strconv"
> "strings"
> "sync"
> @@ -481,6 +483,12 @@
> // "Long-Key": {"Even Longer Value"},
> // }
> func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
> + return readMIMEHeader(r, math.MaxInt64)
> +}
> +
> +// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size.
> +// It is called by the mime/multipart package.
> +func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
> // Avoid lots of small slice allocations later by allocating one
> // large one ahead of time which we'll cut up into smaller
> // slices. If this isn't big enough later, we allocate small ones.
> @@ -522,9 +530,19 @@
> }
>
> // Skip initial spaces in value.
> - value := strings.TrimLeft(string(v), " \t")
> + value := string(bytes.TrimLeft(v, " \t"))
>
> vv := m[key]
> + if vv == nil {
> + lim -= int64(len(key))
> + lim -= 100 // map entry overhead
> + }
> + lim -= int64(len(value))
> + if lim < 0 {
> + // TODO: This should be a distinguishable error (ErrMessageTooLarge)
> + // to allow mime/multipart to detect it.
> + return m, errors.New("message too large")
> + }
> if vv == nil && len(strs) > 0 {
> // More than likely this will be a single-element key.
> // Most headers aren't multi-valued.
> diff -Nru golang-1.19-1.19.5/src/path/filepath/path.go golang-1.19-1.19.6/src/path/filepath/path.go
> --- golang-1.19-1.19.5/src/path/filepath/path.go 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/path/filepath/path.go 2023-02-14 01:38:47.000000000 +0800
> @@ -15,6 +15,7 @@
> "errors"
> "io/fs"
> "os"
> + "runtime"
> "sort"
> "strings"
> )
> @@ -117,21 +118,9 @@
> case os.IsPathSeparator(path[r]):
> // empty path element
> r++
> - case path[r] == '.' && r+1 == n:
> + case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
> // . element
> r++
> - case path[r] == '.' && os.IsPathSeparator(path[r+1]):
> - // ./ element
> - r++
> -
> - for r < len(path) && os.IsPathSeparator(path[r]) {
> - r++
> - }
> - if out.w == 0 && volumeNameLen(path[r:]) > 0 {
> - // When joining prefix "." and an absolute path on Windows,
> - // the prefix should not be removed.
> - out.append('.')
> - }
> case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
> // .. element: remove to last separator
> r += 2
> @@ -157,6 +146,18 @@
> if rooted && out.w != 1 || !rooted && out.w != 0 {
> out.append(Separator)
> }
> + // If a ':' appears in the path element at the start of a Windows path,
> + // insert a .\ at the beginning to avoid converting relative paths
> + // like a/../c: into c:.
> + if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 {
> + for i := r; i < n && !os.IsPathSeparator(path[i]); i++ {
> + if path[i] == ':' {
> + out.append('.')
> + out.append(Separator)
> + break
> + }
> + }
> + }
> // copy element
> for ; r < n && !os.IsPathSeparator(path[r]); r++ {
> out.append(path[r])
> diff -Nru golang-1.19-1.19.5/src/path/filepath/path_test.go golang-1.19-1.19.6/src/path/filepath/path_test.go
> --- golang-1.19-1.19.5/src/path/filepath/path_test.go 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/path/filepath/path_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -96,6 +96,13 @@
> {`.\c:`, `.\c:`},
> {`.\c:\foo`, `.\c:\foo`},
> {`.\c:foo`, `.\c:foo`},
> +
> + // Don't allow cleaning to move an element with a colon to the start of the path.
> + {`a/../c:`, `.\c:`},
> + {`a\..\c:`, `.\c:`},
> + {`a/../c:/a`, `.\c:\a`},
> + {`a/../../c:`, `..\c:`},
> + {`foo:bar`, `foo:bar`},
> }
>
> func TestClean(t *testing.T) {
> diff -Nru golang-1.19-1.19.5/src/path/filepath/path_windows_test.go golang-1.19-1.19.6/src/path/filepath/path_windows_test.go
> --- golang-1.19-1.19.5/src/path/filepath/path_windows_test.go 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/path/filepath/path_windows_test.go 2023-02-14 01:38:47.000000000 +0800
> @@ -542,7 +542,7 @@
> }{
> {`..\.`, `C:`, `..\C:`},
> {`..`, `C:`, `..\C:`},
> - {`.`, `:`, `:`},
> + {`.`, `:`, `.\:`},
> {`.`, `C:`, `.\C:`},
> {`.`, `C:/a/b/../c`, `.\C:\a\c`},
> {`.`, `\C:`, `.\C:`},
> diff -Nru golang-1.19-1.19.5/src/runtime/asm_ppc64x.s golang-1.19-1.19.6/src/runtime/asm_ppc64x.s
> --- golang-1.19-1.19.5/src/runtime/asm_ppc64x.s 2023-01-10 06:38:19.000000000 +0800
> +++ golang-1.19-1.19.6/src/runtime/asm_ppc64x.s 2023-02-14 01:38:47.000000000 +0800
> @@ -339,8 +339,11 @@
> // the caller doesn't save LR on stack but passes it as a
> // register (R5), and the unwinder currently doesn't understand.
> // Make it SPWRITE to stop unwinding. (See issue 54332)
> - MOVD R1, R1
> + // Use OR R0, R1 instead of MOVD R1, R1 as the MOVD instruction
> + // has a special affect on Power8,9,10 by lowering the thread
> + // priority and causing a slowdown in execution time
>
> + OR R0, R1
> MOVD R0, R11
> BR runtime·morestack(SB)
>
> diff -Nru golang-1.19-1.19.5/src/time/zoneinfo_abbrs_windows.go golang-1.19-1.19.6/src/time/zoneinfo_abbrs_windows.go
> --- golang-1.19-1.19.5/src/time/zoneinfo_abbrs_windows.go 2023-01-10 06:38:24.000000000 +0800
> +++ golang-1.19-1.19.6/src/time/zoneinfo_abbrs_windows.go 2023-02-14 01:38:48.000000000 +0800
> @@ -16,10 +16,11 @@
> "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
> "Morocco Standard Time": {"+00", "+01"}, // Africa/Casablanca
> "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
> + "South Sudan Standard Time": {"CAT", "CAT"}, // Africa/Juba
> "Sudan Standard Time": {"CAT", "CAT"}, // Africa/Khartoum
> "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
> "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
> - "Sao Tome Standard Time": {"GMT", "WAT"}, // Africa/Sao_Tome
> + "Sao Tome Standard Time": {"GMT", "GMT"}, // Africa/Sao_Tome
> "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
> "Namibia Standard Time": {"CAT", "CAT"}, // Africa/Windhoek
> "Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
> @@ -33,8 +34,8 @@
> "Venezuela Standard Time": {"-04", "-04"}, // America/Caracas
> "SA Eastern Standard Time": {"-03", "-03"}, // America/Cayenne
> "Central Standard Time": {"CST", "CDT"}, // America/Chicago
> - "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
> - "Central Brazilian Standard Time": {"-04", "-03"}, // America/Cuiaba
> + "Mountain Standard Time (Mexico)": {"CST", "CST"}, // America/Chihuahua
> + "Central Brazilian Standard Time": {"-04", "-04"}, // America/Cuiaba
> "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
> "Greenland Standard Time": {"-03", "-02"}, // America/Godthab
> "Turks And Caicos Standard Time": {"EST", "EDT"}, // America/Grand_Turk
> @@ -44,7 +45,7 @@
> "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
> "SA Western Standard Time": {"-04", "-04"}, // America/La_Paz
> "Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
> - "Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
> + "Central Standard Time (Mexico)": {"CST", "CST"}, // America/Mexico_City
> "Saint Pierre Standard Time": {"-03", "-02"}, // America/Miquelon
> "Montevideo Standard Time": {"-03", "-03"}, // America/Montevideo
> "Eastern Standard Time": {"EST", "EDT"}, // America/New_York
> @@ -53,11 +54,12 @@
> "Magallanes Standard Time": {"-03", "-03"}, // America/Punta_Arenas
> "Canada Central Standard Time": {"CST", "CST"}, // America/Regina
> "Pacific SA Standard Time": {"-04", "-03"}, // America/Santiago
> - "E. South America Standard Time": {"-03", "-02"}, // America/Sao_Paulo
> + "E. South America Standard Time": {"-03", "-03"}, // America/Sao_Paulo
> "Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
> "Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Tijuana
> + "Yukon Standard Time": {"MST", "MST"}, // America/Whitehorse
> "Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty
> - "Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
> + "Jordan Standard Time": {"+03", "+03"}, // Asia/Amman
> "Arabic Standard Time": {"+03", "+03"}, // Asia/Baghdad
> "Azerbaijan Standard Time": {"+04", "+04"}, // Asia/Baku
> "SE Asia Standard Time": {"+07", "+07"}, // Asia/Bangkok
> @@ -66,7 +68,7 @@
> "India Standard Time": {"IST", "IST"}, // Asia/Calcutta
> "Transbaikal Standard Time": {"+09", "+09"}, // Asia/Chita
> "Sri Lanka Standard Time": {"+0530", "+0530"}, // Asia/Colombo
> - "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
> + "Syria Standard Time": {"+03", "+03"}, // Asia/Damascus
> "Bangladesh Standard Time": {"+06", "+06"}, // Asia/Dhaka
> "Arabian Standard Time": {"+04", "+04"}, // Asia/Dubai
> "West Bank Standard Time": {"EET", "EEST"}, // Asia/Hebron
> @@ -82,7 +84,7 @@
> "N. Central Asia Standard Time": {"+07", "+07"}, // Asia/Novosibirsk
> "Omsk Standard Time": {"+06", "+06"}, // Asia/Omsk
> "North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
> - "Qyzylorda Standard Time": {"+05", "+06"}, // Asia/Qyzylorda
> + "Qyzylorda Standard Time": {"+05", "+05"}, // Asia/Qyzylorda
> "Myanmar Standard Time": {"+0630", "+0630"}, // Asia/Rangoon
> "Arab Standard Time": {"+03", "+03"}, // Asia/Riyadh
> "Sakhalin Standard Time": {"+11", "+11"}, // Asia/Sakhalin
> @@ -93,7 +95,7 @@
> "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
> "West Asia Standard Time": {"+05", "+05"}, // Asia/Tashkent
> "Georgian Standard Time": {"+04", "+04"}, // Asia/Tbilisi
> - "Iran Standard Time": {"+0330", "+0430"}, // Asia/Tehran
> + "Iran Standard Time": {"+0330", "+0330"}, // Asia/Tehran
> "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
> "Tomsk Standard Time": {"+07", "+07"}, // Asia/Tomsk
> "Ulaanbaatar Standard Time": {"+08", "+08"}, // Asia/Ulaanbaatar
> @@ -112,7 +114,6 @@
> "Lord Howe Standard Time": {"+1030", "+11"}, // Australia/Lord_Howe
> "W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
> "AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
> - "UTC": {"GMT", "GMT"}, // Etc/GMT
> "UTC-11": {"-11", "-11"}, // Etc/GMT+11
> "Dateline Standard Time": {"-12", "-12"}, // Etc/GMT+12
> "UTC-02": {"-02", "-02"}, // Etc/GMT+2
> @@ -120,6 +121,7 @@
> "UTC-09": {"-09", "-09"}, // Etc/GMT+9
> "UTC+12": {"+12", "+12"}, // Etc/GMT-12
> "UTC+13": {"+13", "+13"}, // Etc/GMT-13
> + "UTC": {"UTC", "UTC"}, // Etc/UTC
> "Astrakhan Standard Time": {"+04", "+04"}, // Europe/Astrakhan
> "W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
> "GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
> @@ -134,20 +136,20 @@
> "Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
> "Russia Time Zone 3": {"+04", "+04"}, // Europe/Samara
> "Saratov Standard Time": {"+04", "+04"}, // Europe/Saratov
> - "Volgograd Standard Time": {"+04", "+04"}, // Europe/Volgograd
> + "Volgograd Standard Time": {"+03", "+03"}, // Europe/Volgograd
> "Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
> "Mauritius Standard Time": {"+04", "+04"}, // Indian/Mauritius
> - "Samoa Standard Time": {"+13", "+14"}, // Pacific/Apia
> + "Samoa Standard Time": {"+13", "+13"}, // Pacific/Apia
> "New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
> "Bougainville Standard Time": {"+11", "+11"}, // Pacific/Bougainville
> "Chatham Islands Standard Time": {"+1245", "+1345"}, // Pacific/Chatham
> "Easter Island Standard Time": {"-06", "-05"}, // Pacific/Easter
> - "Fiji Standard Time": {"+12", "+13"}, // Pacific/Fiji
> + "Fiji Standard Time": {"+12", "+12"}, // Pacific/Fiji
> "Central Pacific Standard Time": {"+11", "+11"}, // Pacific/Guadalcanal
> "Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
> "Line Islands Standard Time": {"+14", "+14"}, // Pacific/Kiritimati
> "Marquesas Standard Time": {"-0930", "-0930"}, // Pacific/Marquesas
> - "Norfolk Standard Time": {"+11", "+11"}, // Pacific/Norfolk
> + "Norfolk Standard Time": {"+11", "+12"}, // Pacific/Norfolk
> "West Pacific Standard Time": {"+10", "+10"}, // Pacific/Port_Moresby
> "Tonga Standard Time": {"+13", "+13"}, // Pacific/Tongatapu
> }
> diff -Nru golang-1.19-1.19.5/src/vendor/golang.org/x/net/http2/hpack/hpack.go golang-1.19-1.19.6/src/vendor/golang.org/x/net/http2/hpack/hpack.go
> --- golang-1.19-1.19.5/src/vendor/golang.org/x/net/http2/hpack/hpack.go 2023-01-10 06:38:24.000000000 +0800
> +++ golang-1.19-1.19.6/src/vendor/golang.org/x/net/http2/hpack/hpack.go 2023-02-14 01:38:48.000000000 +0800
> @@ -359,6 +359,7 @@
>
> var hf HeaderField
> wantStr := d.emitEnabled || it.indexed()
> + var undecodedName undecodedString
> if nameIdx > 0 {
> ihf, ok := d.at(nameIdx)
> if !ok {
> @@ -366,15 +367,27 @@
> }
> hf.Name = ihf.Name
> } else {
> - hf.Name, buf, err = d.readString(buf, wantStr)
> + undecodedName, buf, err = d.readString(buf)
> if err != nil {
> return err
> }
> }
> - hf.Value, buf, err = d.readString(buf, wantStr)
> + undecodedValue, buf, err := d.readString(buf)
> if err != nil {
> return err
> }
> + if wantStr {
> + if nameIdx <= 0 {
> + hf.Name, err = d.decodeString(undecodedName)
> + if err != nil {
> + return err
> + }
> + }
> + hf.Value, err = d.decodeString(undecodedValue)
> + if err != nil {
> + return err
> + }
> + }
> d.buf = buf
> if it.indexed() {
> d.dynTab.add(hf)
> @@ -459,46 +472,52 @@
> return 0, origP, errNeedMore
> }
>
> -// readString decodes an hpack string from p.
> +// readString reads an hpack string from p.
> //
> -// wantStr is whether s will be used. If false, decompression and
> -// []byte->string garbage are skipped if s will be ignored
> -// anyway. This does mean that huffman decoding errors for non-indexed
> -// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
> -// is returning an error anyway, and because they're not indexed, the error
> -// won't affect the decoding state.
> -func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
> +// It returns a reference to the encoded string data to permit deferring decode costs
> +// until after the caller verifies all data is present.
> +func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
> if len(p) == 0 {
> - return "", p, errNeedMore
> + return u, p, errNeedMore
> }
> isHuff := p[0]&128 != 0
> strLen, p, err := readVarInt(7, p)
> if err != nil {
> - return "", p, err
> + return u, p, err
> }
> if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
> - return "", nil, ErrStringLength
> + // Returning an error here means Huffman decoding errors
> + // for non-indexed strings past the maximum string length
> + // are ignored, but the server is returning an error anyway
> + // and because the string is not indexed the error will not
> + // affect the decoding state.
> + return u, nil, ErrStringLength
> }
> if uint64(len(p)) < strLen {
> - return "", p, errNeedMore
> - }
> - if !isHuff {
> - if wantStr {
> - s = string(p[:strLen])
> - }
> - return s, p[strLen:], nil
> + return u, p, errNeedMore
> }
> + u.isHuff = isHuff
> + u.b = p[:strLen]
> + return u, p[strLen:], nil
> +}
>
> - if wantStr {
> - buf := bufPool.Get().(*bytes.Buffer)
> - buf.Reset() // don't trust others
> - defer bufPool.Put(buf)
> - if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
> - buf.Reset()
> - return "", nil, err
> - }
> +type undecodedString struct {
> + isHuff bool
> + b []byte
> +}
> +
> +func (d *Decoder) decodeString(u undecodedString) (string, error) {
> + if !u.isHuff {
> + return string(u.b), nil
> + }
> + buf := bufPool.Get().(*bytes.Buffer)
> + buf.Reset() // don't trust others
> + var s string
> + err := huffmanDecode(buf, d.maxStrLen, u.b)
> + if err == nil {
> s = buf.String()
> - buf.Reset() // be nice to GC
> }
> - return s, p[strLen:], nil
> + buf.Reset() // be nice to GC
> + bufPool.Put(buf)
> + return s, err
> }
> diff -Nru golang-1.19-1.19.5/VERSION golang-1.19-1.19.6/VERSION
> --- golang-1.19-1.19.5/VERSION 2023-01-10 06:38:00.000000000 +0800
> +++ golang-1.19-1.19.6/VERSION 2023-02-14 01:38:41.000000000 +0800
> @@ -1 +1 @@
> -go1.19.5
> \ No newline at end of file
> +go1.19.6
> \ No newline at end of file
--
Sebastian Ramacher
Reply to: