summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.19
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.19')
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-24536_1.patch137
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-24536_2.patch187
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-24536_3.patch349
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-24540.patch93
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-29402.patch194
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-29404.patch78
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-29405.patch109
-rw-r--r--meta/recipes-devtools/go/go-1.19/CVE-2023-29409.patch175
-rw-r--r--meta/recipes-devtools/go/go-1.19/add_godebug.patch84
-rw-r--r--meta/recipes-devtools/go/go-1.19/cve-2022-41724.patch2391
-rw-r--r--meta/recipes-devtools/go/go-1.19/cve-2022-41725.patch652
11 files changed, 4449 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_1.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_1.patch
new file mode 100644
index 0000000000..ff9ba18ec5
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_1.patch
@@ -0,0 +1,137 @@
+From f8d691d335c6ac14bcbae6886b5bf8ca8bf1e6a5 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 16 Mar 2023 14:18:04 -0700
+Subject: [PATCH 1/3] mime/multipart: avoid excessive copy buffer allocations
+ in ReadForm
+
+When copying form data to disk with io.Copy,
+allocate only one copy buffer and reuse it rather than
+creating two buffers per file (one from io.multiReader.WriteTo,
+and a second one from os.File.ReadFrom).
+
+Thanks to Jakob Ackermann (@das7pad) for reporting this issue.
+
+For CVE-2023-24536
+For #59153
+For #59269
+
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802453
+Run-TryBot: Damien Neil <dneil@google.com>
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802395
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Change-Id: Ie405470c92abffed3356913b37d813e982c96c8b
+Reviewed-on: https://go-review.googlesource.com/c/go/+/481983
+Run-TryBot: Michael Knyszek <mknyszek@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+Reviewed-by: Matthew Dempsky <mdempsky@google.com>
+
+CVE: CVE-2023-24536
+Upstream-Status: Backport [ef41a4e2face45e580c5836eaebd51629fc23f15]
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/mime/multipart/formdata.go | 15 +++++++--
+ src/mime/multipart/formdata_test.go | 49 +++++++++++++++++++++++++++++
+ 2 files changed, 61 insertions(+), 3 deletions(-)
+
+diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
+index a7d4ca9..975dcb6 100644
+--- a/src/mime/multipart/formdata.go
++++ b/src/mime/multipart/formdata.go
+@@ -84,6 +84,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ maxMemoryBytes = math.MaxInt64
+ }
+ }
++ var copyBuf []byte
+ for {
+ p, err := r.nextPart(false, maxMemoryBytes)
+ if err == io.EOF {
+@@ -147,14 +148,22 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ }
+ }
+ numDiskFiles++
+- size, err := io.Copy(file, io.MultiReader(&b, p))
++ if _, err := file.Write(b.Bytes()); err != nil {
++ return nil, err
++ }
++ if copyBuf == nil {
++ copyBuf = make([]byte, 32*1024) // same buffer size as io.Copy uses
++ }
++ // os.File.ReadFrom will allocate its own copy buffer if we let io.Copy use it.
++ type writerOnly struct{ io.Writer }
++ remainingSize, err := io.CopyBuffer(writerOnly{file}, p, copyBuf)
+ if err != nil {
+ return nil, err
+ }
+ fh.tmpfile = file.Name()
+- fh.Size = size
++ fh.Size = int64(b.Len()) + remainingSize
+ fh.tmpoff = fileOff
+- fileOff += size
++ fileOff += fh.Size
+ if !combineFiles {
+ if err := file.Close(); err != nil {
+ return nil, err
+diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
+index 5cded71..f5b5608 100644
+--- a/src/mime/multipart/formdata_test.go
++++ b/src/mime/multipart/formdata_test.go
+@@ -368,3 +368,52 @@ func testReadFormManyFiles(t *testing.T, distinct bool) {
+ t.Fatalf("temp dir contains %v files; want 0", len(names))
+ }
+ }
++
++func BenchmarkReadForm(b *testing.B) {
++ for _, test := range []struct {
++ name string
++ form func(fw *Writer, count int)
++ }{{
++ name: "fields",
++ form: func(fw *Writer, count int) {
++ for i := 0; i < count; i++ {
++ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i))
++ fmt.Fprintf(w, "value %v", i)
++ }
++ },
++ }, {
++ name: "files",
++ form: func(fw *Writer, count int) {
++ for i := 0; i < count; i++ {
++ w, _ := fw.CreateFormFile(fmt.Sprintf("field%v", i), fmt.Sprintf("file%v", i))
++ fmt.Fprintf(w, "value %v", i)
++ }
++ },
++ }} {
++ b.Run(test.name, func(b *testing.B) {
++ for _, maxMemory := range []int64{
++ 0,
++ 1 << 20,
++ } {
++ var buf bytes.Buffer
++ fw := NewWriter(&buf)
++ test.form(fw, 10)
++ if err := fw.Close(); err != nil {
++ b.Fatal(err)
++ }
++ b.Run(fmt.Sprintf("maxMemory=%v", maxMemory), func(b *testing.B) {
++ b.ReportAllocs()
++ for i := 0; i < b.N; i++ {
++ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary())
++ form, err := fr.ReadForm(maxMemory)
++ if err != nil {
++ b.Fatal(err)
++ }
++ form.RemoveAll()
++ }
++
++ })
++ }
++ })
++ }
++}
+--
+2.35.5
+
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_2.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_2.patch
new file mode 100644
index 0000000000..704a1fb567
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_2.patch
@@ -0,0 +1,187 @@
+From 4174a87b600c58e8cc00d9d18d0c507c67ca5d41 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 16 Mar 2023 16:56:12 -0700
+Subject: [PATCH 2/3] net/textproto, mime/multipart: improve accounting of
+ non-file data
+
+For requests containing large numbers of small parts,
+memory consumption of a parsed form could be about 250%
+over the estimated size.
+
+When considering the size of parsed forms, account for the size of
+FileHeader structs and increase the estimate of memory consumed by
+map entries.
+
+Thanks to Jakob Ackermann (@das7pad) for reporting this issue.
+
+For CVE-2023-24536
+For #59153
+For #59269
+
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802454
+Run-TryBot: Damien Neil <dneil@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802396
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Change-Id: I31bc50e9346b4eee6fbe51a18c3c57230cc066db
+Reviewed-on: https://go-review.googlesource.com/c/go/+/481984
+Reviewed-by: Matthew Dempsky <mdempsky@google.com>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Run-TryBot: Michael Knyszek <mknyszek@google.com>
+
+CVE: CVE-2023-24536
+Upstream-Status: Backport [7a359a651c7ebdb29e0a1c03102fce793e9f58f0]
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/mime/multipart/formdata.go | 9 +++--
+ src/mime/multipart/formdata_test.go | 55 ++++++++++++-----------------
+ src/net/textproto/reader.go | 8 ++++-
+ 3 files changed, 37 insertions(+), 35 deletions(-)
+
+diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
+index 975dcb6..3f6ff69 100644
+--- a/src/mime/multipart/formdata.go
++++ b/src/mime/multipart/formdata.go
+@@ -103,8 +103,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ // 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.
++ const mapEntryOverhead = 200
+ maxMemoryBytes -= int64(len(name))
+- maxMemoryBytes -= 100 // map overhead
++ maxMemoryBytes -= mapEntryOverhead
+ 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.
+@@ -128,7 +129,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ }
+
+ // file, store in memory or on disk
++ const fileHeaderSize = 100
+ maxMemoryBytes -= mimeHeaderSize(p.Header)
++ maxMemoryBytes -= mapEntryOverhead
++ maxMemoryBytes -= fileHeaderSize
+ if maxMemoryBytes < 0 {
+ return nil, ErrMessageTooLarge
+ }
+@@ -183,9 +187,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ }
+
+ func mimeHeaderSize(h textproto.MIMEHeader) (size int64) {
++ size = 400
+ for k, vs := range h {
+ size += int64(len(k))
+- size += 100 // map entry overhead
++ size += 200 // map entry overhead
+ for _, v := range vs {
+ size += int64(len(v))
+ }
+diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
+index f5b5608..8ed26e0 100644
+--- a/src/mime/multipart/formdata_test.go
++++ b/src/mime/multipart/formdata_test.go
+@@ -192,10 +192,10 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
+ // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied
+ // while processing non-file form data as well as file form data.
+ func TestReadForm_NonFileMaxMemory(t *testing.T) {
+- n := 10<<20 + 25
+ if testing.Short() {
+- n = 10<<10 + 25
++ t.Skip("skipping in -short mode")
+ }
++ n := 10 << 20
+ largeTextValue := strings.Repeat("1", n)
+ message := `--MyBoundary
+ Content-Disposition: form-data; name="largetext"
+@@ -203,38 +203,29 @@ Content-Disposition: form-data; name="largetext"
+ ` + largeTextValue + `
+ --MyBoundary--
+ `
+-
+ testBody := strings.ReplaceAll(message, "\n", "\r\n")
+- testCases := []struct {
+- name string
+- maxMemory int64
+- err error
+- }{
+- {"smaller", 50 + int64(len("largetext")) + 100, nil},
+- {"exact-fit", 25 + int64(len("largetext")) + 100, nil},
+- {"too-large", 0, ErrMessageTooLarge},
+- }
+- for _, tc := range testCases {
+- t.Run(tc.name, func(t *testing.T) {
+- if tc.maxMemory == 0 && testing.Short() {
+- t.Skip("skipping in -short mode")
+- }
+- b := strings.NewReader(testBody)
+- r := NewReader(b, boundary)
+- f, err := r.ReadForm(tc.maxMemory)
+- if err == nil {
+- defer f.RemoveAll()
+- }
+- if 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 {
+- t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue))
+- }
+- }
+- })
++ // Try parsing the form with increasing maxMemory values.
++ // Changes in how we account for non-file form data may cause the exact point
++ // where we change from rejecting the form as too large to accepting it to vary,
++ // but we should see both successes and failures.
++ const failWhenMaxMemoryLessThan = 128
++ for maxMemory := int64(0); maxMemory < failWhenMaxMemoryLessThan*2; maxMemory += 16 {
++ b := strings.NewReader(testBody)
++ r := NewReader(b, boundary)
++ f, err := r.ReadForm(maxMemory)
++ if err != nil {
++ continue
++ }
++ if g := f.Value["largetext"][0]; g != largeTextValue {
++ t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue))
++ }
++ f.RemoveAll()
++ if maxMemory < failWhenMaxMemoryLessThan {
++ t.Errorf("ReadForm(%v): no error, expect to hit memory limit when maxMemory < %v", maxMemory, failWhenMaxMemoryLessThan)
++ }
++ return
+ }
++ t.Errorf("ReadForm(x) failed for x < 1024, expect success")
+ }
+
+ // TestReadForm_MetadataTooLarge verifies that we account for the size of field names,
+diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
+index fcbede8..9af4c49 100644
+--- a/src/net/textproto/reader.go
++++ b/src/net/textproto/reader.go
+@@ -503,6 +503,12 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
+
+ m := make(MIMEHeader, hint)
+
++ // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry.
++ // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large
++ // MIMEHeaders average about 200 bytes per entry.
++ lim -= 400
++ const mapEntryOverhead = 200
++
+ // The first line cannot start with a leading space.
+ if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
+ line, err := r.readLineSlice()
+@@ -552,7 +558,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
+ vv := m[key]
+ if vv == nil {
+ lim -= int64(len(key))
+- lim -= 100 // map entry overhead
++ lim -= mapEntryOverhead
+ }
+ lim -= int64(len(value))
+ if lim < 0 {
+--
+2.35.5
+
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_3.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_3.patch
new file mode 100644
index 0000000000..6de04e9a61
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-24536_3.patch
@@ -0,0 +1,349 @@
+From ec763bc936f76cec0fe71a791c6bb7d4ac5f3e46 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Mon, 20 Mar 2023 10:43:19 -0700
+Subject: [PATCH 3/3] mime/multipart: limit parsed mime message sizes
+
+The parsed forms of MIME headers and multipart forms can consume
+substantially more memory than the size of the input data.
+A malicious input containing a very large number of headers or
+form parts can cause excessively large memory allocations.
+
+Set limits on the size of MIME data:
+
+Reader.NextPart and Reader.NextRawPart limit the the number
+of headers in a part to 10000.
+
+Reader.ReadForm limits the total number of headers in all
+FileHeaders to 10000.
+
+Both of these limits may be set with with
+GODEBUG=multipartmaxheaders=<values>.
+
+Reader.ReadForm limits the number of parts in a form to 1000.
+This limit may be set with GODEBUG=multipartmaxparts=<value>.
+
+Thanks for Jakob Ackermann (@das7pad) for reporting this issue.
+
+For CVE-2023-24536
+For #59153
+For #59269
+
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455
+Run-TryBot: Damien Neil <dneil@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1801087
+Reviewed-by: Damien Neil <dneil@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Change-Id: If134890d75f0d95c681d67234daf191ba08e6424
+Reviewed-on: https://go-review.googlesource.com/c/go/+/481985
+Run-TryBot: Michael Knyszek <mknyszek@google.com>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Reviewed-by: Matthew Dempsky <mdempsky@google.com>
+
+CVE: CVE-2023-24536
+Upstream-Status: Backport [7917b5f31204528ea72e0629f0b7d52b35b27538]
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/mime/multipart/formdata.go | 19 ++++++++-
+ src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++
+ src/mime/multipart/multipart.go | 31 ++++++++++----
+ src/mime/multipart/readmimeheader.go | 2 +-
+ src/net/textproto/reader.go | 19 +++++----
+ 5 files changed, 115 insertions(+), 17 deletions(-)
+
+diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
+index 3f6ff69..4f26aab 100644
+--- a/src/mime/multipart/formdata.go
++++ b/src/mime/multipart/formdata.go
+@@ -12,6 +12,7 @@ import (
+ "math"
+ "net/textproto"
+ "os"
++ "strconv"
+ )
+
+ // ErrMessageTooLarge is returned by ReadForm if the message form
+@@ -41,6 +42,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ numDiskFiles := 0
+ multipartFiles := godebug.Get("multipartfiles")
+ combineFiles := multipartFiles != "distinct"
++ maxParts := 1000
++ multipartMaxParts := godebug.Get("multipartmaxparts")
++ if multipartMaxParts != "" {
++ if v, err := strconv.Atoi(multipartMaxParts); err == nil && v >= 0 {
++ maxParts = v
++ }
++ }
++ maxHeaders := maxMIMEHeaders()
++
+ defer func() {
+ if file != nil {
+ if cerr := file.Close(); err == nil {
+@@ -86,13 +96,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ }
+ var copyBuf []byte
+ for {
+- p, err := r.nextPart(false, maxMemoryBytes)
++ p, err := r.nextPart(false, maxMemoryBytes, maxHeaders)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
++ if maxParts <= 0 {
++ return nil, ErrMessageTooLarge
++ }
++ maxParts--
+
+ name := p.FormName()
+ if name == "" {
+@@ -136,6 +150,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
+ if maxMemoryBytes < 0 {
+ return nil, ErrMessageTooLarge
+ }
++ for _, v := range p.Header {
++ maxHeaders -= int64(len(v))
++ }
+ fh := &FileHeader{
+ Filename: filename,
+ Header: p.Header,
+diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
+index 8ed26e0..c78eeb7 100644
+--- a/src/mime/multipart/formdata_test.go
++++ b/src/mime/multipart/formdata_test.go
+@@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) {
+ }
+ }
+
++func TestReadFormLimits(t *testing.T) {
++ for _, test := range []struct {
++ values int
++ files int
++ extraKeysPerFile int
++ wantErr error
++ godebug string
++ }{
++ {values: 1000},
++ {values: 1001, wantErr: ErrMessageTooLarge},
++ {values: 500, files: 500},
++ {values: 501, files: 500, wantErr: ErrMessageTooLarge},
++ {files: 1000},
++ {files: 1001, wantErr: ErrMessageTooLarge},
++ {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type
++ {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge},
++ {godebug: "multipartmaxparts=100", values: 100},
++ {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge},
++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48},
++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge},
++ } {
++ name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile)
++ if test.godebug != "" {
++ name += fmt.Sprintf("/godebug=%v", test.godebug)
++ }
++ t.Run(name, func(t *testing.T) {
++ if test.godebug != "" {
++ t.Setenv("GODEBUG", test.godebug)
++ }
++ var buf bytes.Buffer
++ fw := NewWriter(&buf)
++ for i := 0; i < test.values; i++ {
++ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i))
++ fmt.Fprintf(w, "value %v", i)
++ }
++ for i := 0; i < test.files; i++ {
++ h := make(textproto.MIMEHeader)
++ h.Set("Content-Disposition",
++ fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i))
++ h.Set("Content-Type", "application/octet-stream")
++ for j := 0; j < test.extraKeysPerFile; j++ {
++ h.Set(fmt.Sprintf("k%v", j), "v")
++ }
++ w, _ := fw.CreatePart(h)
++ fmt.Fprintf(w, "value %v", i)
++ }
++ if err := fw.Close(); err != nil {
++ t.Fatal(err)
++ }
++ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary())
++ form, err := fr.ReadForm(1 << 10)
++ if err == nil {
++ defer form.RemoveAll()
++ }
++ if err != test.wantErr {
++ t.Errorf("ReadForm = %v, want %v", err, test.wantErr)
++ }
++ })
++ }
++}
++
+ func BenchmarkReadForm(b *testing.B) {
+ for _, test := range []struct {
+ name string
+diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
+index 19fe0ea..80acabc 100644
+--- a/src/mime/multipart/multipart.go
++++ b/src/mime/multipart/multipart.go
+@@ -16,11 +16,13 @@ import (
+ "bufio"
+ "bytes"
+ "fmt"
++ "internal/godebug"
+ "io"
+ "mime"
+ "mime/quotedprintable"
+ "net/textproto"
+ "path/filepath"
++ "strconv"
+ "strings"
+ )
+
+@@ -128,12 +130,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
+ return n, r.err
+ }
+
+-func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
++func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) {
+ bp := &Part{
+ Header: make(map[string][]string),
+ mr: mr,
+ }
+- if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil {
++ if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil {
+ return nil, err
+ }
+ bp.r = partReader{bp}
+@@ -149,9 +151,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
+ return bp, nil
+ }
+
+-func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error {
++func (bp *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error {
+ r := textproto.NewReader(bp.mr.bufReader)
+- header, err := readMIMEHeader(r, maxMIMEHeaderSize)
++ header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders)
+ if err == nil {
+ bp.Header = header
+ }
+@@ -313,6 +315,19 @@ type Reader struct {
+ // including header keys, values, and map overhead.
+ const maxMIMEHeaderSize = 10 << 20
+
++func maxMIMEHeaders() int64 {
++ // multipartMaxHeaders is the maximum number of header entries NextPart will return,
++ // as well as the maximum combined total of header entries Reader.ReadForm will return
++ // in FileHeaders.
++ multipartMaxHeaders := godebug.Get("multipartmaxheaders")
++ if multipartMaxHeaders != "" {
++ if v, err := strconv.ParseInt(multipartMaxHeaders, 10, 64); err == nil && v >= 0 {
++ return v
++ }
++ }
++ return 10000
++}
++
+ // NextPart returns the next part in the multipart or an error.
+ // When there are no more parts, the error io.EOF is returned.
+ //
+@@ -320,7 +335,7 @@ const maxMIMEHeaderSize = 10 << 20
+ // 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, maxMIMEHeaderSize)
++ return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders())
+ }
+
+ // NextRawPart returns the next part in the multipart or an error.
+@@ -329,10 +344,10 @@ func (r *Reader) NextPart() (*Part, error) {
+ // Unlike NextPart, it does not have special handling for
+ // "Content-Transfer-Encoding: quoted-printable".
+ func (r *Reader) NextRawPart() (*Part, error) {
+- return r.nextPart(true, maxMIMEHeaderSize)
++ return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders())
+ }
+
+-func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
++func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) {
+ if r.currentPart != nil {
+ r.currentPart.Close()
+ }
+@@ -357,7 +372,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error)
+
+ if r.isBoundaryDelimiterLine(line) {
+ r.partsRead++
+- bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
++ bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders)
+ if err != nil {
+ return nil, err
+ }
+diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go
+index 6836928..25aa6e2 100644
+--- a/src/mime/multipart/readmimeheader.go
++++ b/src/mime/multipart/readmimeheader.go
+@@ -11,4 +11,4 @@ import (
+ // readMIMEHeader is defined in package net/textproto.
+ //
+ //go:linkname readMIMEHeader net/textproto.readMIMEHeader
+-func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error)
++func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error)
+diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
+index 9af4c49..c6569c8 100644
+--- a/src/net/textproto/reader.go
++++ b/src/net/textproto/reader.go
+@@ -483,12 +483,12 @@ func (r *Reader) ReadDotLines() ([]string, error) {
+ // }
+ //
+ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
+- return readMIMEHeader(r, math.MaxInt64)
++ return readMIMEHeader(r, math.MaxInt64, 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) {
++func readMIMEHeader(r *Reader, maxMemory, maxHeaders 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.
+@@ -506,7 +506,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
+ // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry.
+ // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large
+ // MIMEHeaders average about 200 bytes per entry.
+- lim -= 400
++ maxMemory -= 400
+ const mapEntryOverhead = 200
+
+ // The first line cannot start with a leading space.
+@@ -538,6 +538,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
+ continue
+ }
+
++ maxHeaders--
++ if maxHeaders < 0 {
++ return nil, errors.New("message too large")
++ }
++
+ // backport 5c55ac9bf1e5f779220294c843526536605f42ab
+ //
+ // value is computed as
+@@ -557,11 +562,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
+
+ vv := m[key]
+ if vv == nil {
+- lim -= int64(len(key))
+- lim -= mapEntryOverhead
++ maxMemory -= int64(len(key))
++ maxMemory -= mapEntryOverhead
+ }
+- lim -= int64(len(value))
+- if lim < 0 {
++ maxMemory -= int64(len(value))
++ if maxMemory < 0 {
+ // TODO: This should be a distinguishable error (ErrMessageTooLarge)
+ // to allow mime/multipart to detect it.
+ return m, errors.New("message too large")
+--
+2.35.5
+
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-24540.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-24540.patch
new file mode 100644
index 0000000000..7e6e871e38
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-24540.patch
@@ -0,0 +1,93 @@
+From 2305cdb2aa5ac8e9960bd64e548a119c7dd87530 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Tue, 11 Apr 2023 16:27:43 +0100
+Subject: [PATCH] html/template: handle all JS whitespace characters
+
+Rather than just a small set. Character class as defined by \s [0].
+
+Thanks to Juho Nurminen of Mattermost for reporting this.
+
+For #59721
+Fixes #59813
+Fixes CVE-2023-24540
+
+[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
+
+Change-Id: I56d4fa1ef08125b417106ee7dbfb5b0923b901ba
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1821459
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1851497
+Run-TryBot: Damien Neil <dneil@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/491355
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+TryBot-Bypass: Carlos Amedee <carlos@golang.org>
+Run-TryBot: Carlos Amedee <carlos@golang.org>
+
+CVE: CVE-2023-24540
+Upstream-Status: Backport [https://github.com/golang/go/commit/ce7bd33345416e6d8cac901792060591cafc2797]
+
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/html/template/js.go | 8 +++++++-
+ src/html/template/js_test.go | 11 +++++++----
+ 2 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/src/html/template/js.go b/src/html/template/js.go
+index b888eaf..35994f0 100644
+--- a/src/html/template/js.go
++++ b/src/html/template/js.go
+@@ -13,6 +13,11 @@ import (
+ "unicode/utf8"
+ )
+
++// jsWhitespace contains all of the JS whitespace characters, as defined
++// by the \s character class.
++// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes.
++const jsWhitespace = "\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff"
++
+ // nextJSCtx returns the context that determines whether a slash after the
+ // given run of tokens starts a regular expression instead of a division
+ // operator: / or /=.
+@@ -26,7 +31,8 @@ import (
+ // JavaScript 2.0 lexical grammar and requires one token of lookbehind:
+ // https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html
+ func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
+- s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029")
++ // Trim all JS whitespace characters
++ s = bytes.TrimRight(s, jsWhitespace)
+ if len(s) == 0 {
+ return preceding
+ }
+diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
+index d7ee47b..8f5d76d 100644
+--- a/src/html/template/js_test.go
++++ b/src/html/template/js_test.go
+@@ -81,14 +81,17 @@ func TestNextJsCtx(t *testing.T) {
+ {jsCtxDivOp, "0"},
+ // Dots that are part of a number are div preceders.
+ {jsCtxDivOp, "0."},
++ // Some JS interpreters treat NBSP as a normal space, so
++ // we must too in order to properly escape things.
++ {jsCtxRegexp, "=\u00A0"},
+ }
+
+ for _, test := range tests {
+- if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx {
+- t.Errorf("want %s got %q", test.jsCtx, test.s)
++ if ctx := nextJSCtx([]byte(test.s), jsCtxRegexp); ctx != test.jsCtx {
++ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx)
+ }
+- if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx {
+- t.Errorf("want %s got %q", test.jsCtx, test.s)
++ if ctx := nextJSCtx([]byte(test.s), jsCtxDivOp); ctx != test.jsCtx {
++ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx)
+ }
+ }
+
+--
+2.40.0
+
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-29402.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-29402.patch
new file mode 100644
index 0000000000..bf1fbbe0d6
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-29402.patch
@@ -0,0 +1,194 @@
+From 4dae3bbe0e6a5700037bb996ae84d6f457c4f58a Mon Sep 17 00:00:00 2001
+From: Bryan C. Mills <bcmills@google.com>
+Date: Fri, 12 May 2023 14:15:16 -0400
+Subject: [PATCH] cmd/go: disallow package directories containing newlines
+
+Directory or file paths containing newlines may cause tools (such as
+cmd/cgo) that emit "//line" or "#line" -directives to write part of
+the path into non-comment lines in generated source code. If those
+lines contain valid Go code, it may be injected into the resulting
+binary.
+
+(Note that Go import paths and file paths within module zip files
+already could not contain newlines.)
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes #60167.
+Fixes CVE-2023-29402.
+
+Change-Id: I64572e9f454bce7b685d00e2e6a1c96cd33d53df
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1882606
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Russ Cox <rsc@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/501226
+Run-TryBot: David Chase <drchase@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Reviewed-by: Michael Knyszek <mknyszek@google.com>
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/4dae3bbe0e6a5700037bb996ae84d6f457c4f58a]
+CVE: CVE-2023-29402
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ src/cmd/go/internal/load/pkg.go | 4 +
+ src/cmd/go/internal/work/exec.go | 6 ++
+ src/cmd/go/script_test.go | 1 +
+ .../go/testdata/script/build_cwd_newline.txt | 100 ++++++++++++++++++
+ 4 files changed, 111 insertions(+)
+ create mode 100644 src/cmd/go/testdata/script/build_cwd_newline.txt
+
+diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
+index a83cc9a..d4da86d 100644
+--- a/src/cmd/go/internal/load/pkg.go
++++ b/src/cmd/go/internal/load/pkg.go
+@@ -1897,6 +1897,10 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
+ setError(fmt.Errorf("invalid input directory name %q", name))
+ return
+ }
++ if strings.ContainsAny(p.Dir, "\r\n") {
++ setError(fmt.Errorf("invalid package directory %q", p.Dir))
++ return
++ }
+
+ // Build list of imported packages and full dependency list.
+ imports := make([]*Package, 0, len(p.Imports))
+diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
+index b35caa4..b1bf347 100644
+--- a/src/cmd/go/internal/work/exec.go
++++ b/src/cmd/go/internal/work/exec.go
+@@ -505,6 +505,12 @@ func (b *Builder) build(ctx context.Context, a *Action) (err error) {
+ b.Print(a.Package.ImportPath + "\n")
+ }
+
++ if p.Error != nil {
++ // Don't try to build anything for packages with errors. There may be a
++ // problem with the inputs that makes the package unsafe to build.
++ return p.Error
++ }
++
+ if a.Package.BinaryOnly {
+ p.Stale = true
+ p.StaleReason = "binary-only packages are no longer supported"
+diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
+index c0156d0..ce4ff37 100644
+--- a/src/cmd/go/script_test.go
++++ b/src/cmd/go/script_test.go
+@@ -182,6 +182,7 @@ func (ts *testScript) setup() {
+ "devnull=" + os.DevNull,
+ "goversion=" + goVersion(ts),
+ ":=" + string(os.PathListSeparator),
++ "newline=\n",
+ }
+ if !testenv.HasExternalNetwork() {
+ ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")
+diff --git a/src/cmd/go/testdata/script/build_cwd_newline.txt b/src/cmd/go/testdata/script/build_cwd_newline.txt
+new file mode 100644
+index 0000000..61c6966
+--- /dev/null
++++ b/src/cmd/go/testdata/script/build_cwd_newline.txt
+@@ -0,0 +1,100 @@
++[windows] skip 'filesystem normalizes / to \'
++[plan9] skip 'filesystem disallows \n in paths'
++
++# If the directory path containing a package to be built includes a newline,
++# the go command should refuse to even try to build the package.
++
++env DIR=$WORK${/}${newline}'package main'${newline}'func main() { panic("uh-oh")'${newline}'/*'
++
++mkdir $DIR
++cd $DIR
++exec pwd
++cp $WORK/go.mod ./go.mod
++cp $WORK/main.go ./main.go
++cp $WORK/main_test.go ./main_test.go
++
++! go build -o $devnull .
++stderr 'package example: invalid package directory .*uh-oh'
++
++! go build -o $devnull main.go
++stderr 'package command-line-arguments: invalid package directory .*uh-oh'
++
++! go run .
++stderr 'package example: invalid package directory .*uh-oh'
++
++! go run main.go
++stderr 'package command-line-arguments: invalid package directory .*uh-oh'
++
++! go test .
++stderr 'package example: invalid package directory .*uh-oh'
++
++! go test -v main.go main_test.go
++stderr 'package command-line-arguments: invalid package directory .*uh-oh'
++
++
++# Since we do preserve $PWD (or set it appropriately) for commands, and we do
++# not resolve symlinks unnecessarily, referring to the contents of the unsafe
++# directory via a safe symlink should be ok, and should not inject the data from
++# the symlink target path.
++
++[!symlink] stop 'remainder of test checks symlink behavior'
++[short] stop 'links and runs binaries'
++
++symlink $WORK${/}link -> $DIR
++
++go run $WORK${/}link${/}main.go
++! stdout panic
++! stderr panic
++stderr '^ok$'
++
++go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go
++! stdout panic
++! stderr panic
++stdout '^ok$' # 'go test' combines the test's stdout into stderr
++
++cd $WORK/link
++
++! go run $DIR${/}main.go
++stderr 'package command-line-arguments: invalid package directory .*uh-oh'
++
++go run .
++! stdout panic
++! stderr panic
++stderr '^ok$'
++
++go run main.go
++! stdout panic
++! stderr panic
++stderr '^ok$'
++
++go test -v
++! stdout panic
++! stderr panic
++stdout '^ok$' # 'go test' combines the test's stdout into stderr
++
++go test -v .
++! stdout panic
++! stderr panic
++stdout '^ok$' # 'go test' combines the test's stdout into stderr
++
++
++-- $WORK/go.mod --
++module example
++go 1.19
++-- $WORK/main.go --
++package main
++
++import "C"
++
++func main() {
++ /* nothing here */
++ println("ok")
++}
++-- $WORK/main_test.go --
++package main
++
++import "testing"
++
++func TestMain(*testing.M) {
++ main()
++}
+--
+2.40.0
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-29404.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-29404.patch
new file mode 100644
index 0000000000..c6beced884
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-29404.patch
@@ -0,0 +1,78 @@
+From bbeb55f5faf93659e1cfd6ab073ab3c9d126d195 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Fri, 5 May 2023 13:10:34 -0700
+Subject: [PATCH] cmd/go: enforce flags with non-optional arguments
+
+Enforce that linker flags which expect arguments get them, otherwise it
+may be possible to smuggle unexpected flags through as the linker can
+consume what looks like a flag as an argument to a preceding flag (i.e.
+"-Wl,-O -Wl,-R,-bad-flag" is interpreted as "-O=-R -bad-flag"). Also be
+somewhat more restrictive in the general format of some flags.
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes #60305
+Fixes CVE-2023-29404
+
+Change-Id: I913df78a692cee390deefc3cd7d8f5b031524fc9
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1876275
+Reviewed-by: Ian Lance Taylor <iant@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/501225
+Run-TryBot: David Chase <drchase@google.com>
+Reviewed-by: Michael Knyszek <mknyszek@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/bbeb55f5faf93659e1cfd6ab073ab3c9d126d195]
+CVE: CVE-2023-29404
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ src/cmd/go/internal/work/security.go | 6 +++---
+ src/cmd/go/internal/work/security_test.go | 5 +++++
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
+index e9b9f6c..91e6e4c 100644
+--- a/src/cmd/go/internal/work/security.go
++++ b/src/cmd/go/internal/work/security.go
+@@ -179,10 +179,10 @@ var validLinkerFlags = []*lazyregexp.Regexp{
+ re(`-Wl,-berok`),
+ re(`-Wl,-Bstatic`),
+ re(`-Wl,-Bsymbolic-functions`),
+- re(`-Wl,-O([^@,\-][^,]*)?`),
++ re(`-Wl,-O[0-9]+`),
+ re(`-Wl,-d[ny]`),
+ re(`-Wl,--disable-new-dtags`),
+- re(`-Wl,-e[=,][a-zA-Z0-9]*`),
++ re(`-Wl,-e[=,][a-zA-Z0-9]+`),
+ re(`-Wl,--enable-new-dtags`),
+ re(`-Wl,--end-group`),
+ re(`-Wl,--(no-)?export-dynamic`),
+@@ -191,7 +191,7 @@ var validLinkerFlags = []*lazyregexp.Regexp{
+ re(`-Wl,--hash-style=(sysv|gnu|both)`),
+ re(`-Wl,-headerpad_max_install_names`),
+ re(`-Wl,--no-undefined`),
+- re(`-Wl,-R([^@\-][^,@]*$)`),
++ re(`-Wl,-R,?([^@\-,][^,@]*$)`),
+ re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`),
+ re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
+ re(`-Wl,-s`),
+diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
+index 8d4be0a..3616548 100644
+--- a/src/cmd/go/internal/work/security_test.go
++++ b/src/cmd/go/internal/work/security_test.go
+@@ -227,6 +227,11 @@ var badLinkerFlags = [][]string{
+ {"-Wl,-R,@foo"},
+ {"-Wl,--just-symbols,@foo"},
+ {"../x.o"},
++ {"-Wl,-R,"},
++ {"-Wl,-O"},
++ {"-Wl,-e="},
++ {"-Wl,-e,"},
++ {"-Wl,-R,-flag"},
+ }
+
+ func TestCheckLinkerFlags(t *testing.T) {
+--
+2.40.0
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-29405.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-29405.patch
new file mode 100644
index 0000000000..d806e1e67d
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-29405.patch
@@ -0,0 +1,109 @@
+From 6d8af00a630aa51134e54f0f321658621c6410f0 Mon Sep 17 00:00:00 2001
+From: Ian Lance Taylor <iant@golang.org>
+Date: Thu, 4 May 2023 14:06:39 -0700
+Subject: [PATCH] cmd/go,cmd/cgo: in _cgo_flags use one line per flag
+
+The flags that we recorded in _cgo_flags did not use any quoting,
+so a flag containing embedded spaces was mishandled.
+Change the _cgo_flags format to put each flag on a separate line.
+That is a simple format that does not require any quoting.
+
+As far as I can tell only cmd/go uses _cgo_flags, and it is only
+used for gccgo. If this patch doesn't cause any trouble, then
+in the next release we can change to only using _cgo_flags for gccgo.
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes #60306
+Fixes CVE-2023-29405
+
+Change-Id: I81fb5337db8a22e1f4daca22ceff4b79b96d0b4f
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1875094
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/501224
+Reviewed-by: Ian Lance Taylor <iant@google.com>
+Run-TryBot: David Chase <drchase@google.com>
+Reviewed-by: Michael Knyszek <mknyszek@google.com>
+Reviewed-by: Roland Shoemaker <roland@golang.org>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/6d8af00a630aa51134e54f0f321658621c6410f0]
+CVE: CVE-2023-29405
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ src/cmd/cgo/out.go | 4 +++-
+ src/cmd/go/internal/work/gccgo.go | 14 ++++++-------
+ .../go/testdata/script/gccgo_link_ldflags.txt | 20 +++++++++++++++++++
+ 3 files changed, 29 insertions(+), 9 deletions(-)
+ create mode 100644 src/cmd/go/testdata/script/gccgo_link_ldflags.txt
+
+diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
+index 94152f4..62e6528 100644
+--- a/src/cmd/cgo/out.go
++++ b/src/cmd/cgo/out.go
+@@ -47,7 +47,9 @@ func (p *Package) writeDefs() {
+
+ fflg := creat(*objDir + "_cgo_flags")
+ for k, v := range p.CgoFlags {
+- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
++ for _, arg := range v {
++ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, arg)
++ }
+ if k == "LDFLAGS" && !*gccgo {
+ for _, arg := range v {
+ fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
+diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go
+index 1499536..bb4be2f 100644
+--- a/src/cmd/go/internal/work/gccgo.go
++++ b/src/cmd/go/internal/work/gccgo.go
+@@ -283,14 +283,12 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
+ const ldflagsPrefix = "_CGO_LDFLAGS="
+ for _, line := range strings.Split(string(flags), "\n") {
+ if strings.HasPrefix(line, ldflagsPrefix) {
+- newFlags := strings.Fields(line[len(ldflagsPrefix):])
+- for _, flag := range newFlags {
+- // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
+- // but they don't mean anything to the linker so filter
+- // them out.
+- if flag != "-g" && !strings.HasPrefix(flag, "-O") {
+- cgoldflags = append(cgoldflags, flag)
+- }
++ flag := line[len(ldflagsPrefix):]
++ // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
++ // but they don't mean anything to the linker so filter
++ // them out.
++ if flag != "-g" && !strings.HasPrefix(flag, "-O") {
++ cgoldflags = append(cgoldflags, flag)
+ }
+ }
+ }
+diff --git a/src/cmd/go/testdata/script/gccgo_link_ldflags.txt b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt
+new file mode 100644
+index 0000000..4e91ae5
+--- /dev/null
++++ b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt
+@@ -0,0 +1,20 @@
++# Test that #cgo LDFLAGS are properly quoted.
++# The #cgo LDFLAGS below should pass a string with spaces to -L,
++# as though searching a directory with a space in its name.
++# It should not pass --nosuchoption to the external linker.
++
++[!cgo] skip
++
++go build
++
++[!exec:gccgo] skip
++
++go build -compiler gccgo
++
++-- go.mod --
++module m
++-- cgo.go --
++package main
++// #cgo LDFLAGS: -L "./ -Wl,--nosuchoption"
++import "C"
++func main() {}
+--
+2.40.0
diff --git a/meta/recipes-devtools/go/go-1.19/CVE-2023-29409.patch b/meta/recipes-devtools/go/go-1.19/CVE-2023-29409.patch
new file mode 100644
index 0000000000..38451f7555
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/CVE-2023-29409.patch
@@ -0,0 +1,175 @@
+From 2300f7ef07718f6be4d8aa8486c7de99836e233f Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Wed, 23 Aug 2023 12:03:43 +0000
+Subject: [PATCH] crypto/tls: restrict RSA keys in certificates to <= 8192 bits
+
+Extremely large RSA keys in certificate chains can cause a client/server
+to expend significant CPU time verifying signatures. Limit this by
+restricting the size of RSA keys transmitted during handshakes to <=
+8192 bits.
+
+Based on a survey of publicly trusted RSA keys, there are currently only
+three certificates in circulation with keys larger than this, and all
+three appear to be test certificates that are not actively deployed. It
+is possible there are larger keys in use in private PKIs, but we target
+the web PKI, so causing breakage here in the interests of increasing the
+default safety of users of crypto/tls seems reasonable.
+
+Thanks to Mateusz Poliwczak for reporting this issue.
+
+Updates #61460
+Fixes #61579
+Fixes CVE-2023-29409
+
+Change-Id: Ie35038515a649199a36a12fc2c5df3af855dca6c
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1912161
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+(cherry picked from commit d865c715d92887361e4bd5596e19e513f27781b7)
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1965487
+Reviewed-on: https://go-review.googlesource.com/c/go/+/514915
+Run-TryBot: David Chase <drchase@google.com>
+Reviewed-by: Matthew Dempsky <mdempsky@google.com>
+TryBot-Bypass: David Chase <drchase@google.com>
+
+CVE: CVE-2023-29409
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/2300f7ef07718f6be4d8aa8486c7de99836e233f]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ src/crypto/tls/handshake_client.go | 8 +++
+ src/crypto/tls/handshake_client_test.go | 78 +++++++++++++++++++++++++
+ src/crypto/tls/handshake_server.go | 4 ++
+ 3 files changed, 90 insertions(+)
+
+diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
+index 85622f1..828d2cb 100644
+--- a/src/crypto/tls/handshake_client.go
++++ b/src/crypto/tls/handshake_client.go
+@@ -852,6 +852,10 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
+ return nil
+ }
+
++// maxRSAKeySize is the maximum RSA key size in bits that we are willing
++// to verify the signatures of during a TLS handshake.
++const maxRSAKeySize = 8192
++
+ // verifyServerCertificate parses and verifies the provided chain, setting
+ // c.verifiedChains and c.peerCertificates or sending the appropriate alert.
+ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
+@@ -862,6 +866,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ }
++ if cert.PublicKeyAlgorithm == x509.RSA && cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
++ c.sendAlert(alertBadCertificate)
++ return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
++ }
+ certs[i] = cert
+ }
+
+diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
+index 0228745..d581cb1 100644
+--- a/src/crypto/tls/handshake_client_test.go
++++ b/src/crypto/tls/handshake_client_test.go
+@@ -2595,3 +2595,81 @@ func TestClientHandshakeContextCancellation(t *testing.T) {
+ t.Error("Client connection was not closed when the context was canceled")
+ }
+ }
++
++// discardConn wraps a net.Conn but discards all writes, but reports that they happened.
++type discardConn struct {
++ net.Conn
++}
++
++func (dc *discardConn) Write(data []byte) (int, error) {
++ return len(data), nil
++}
++
++// largeRSAKeyCertPEM contains a 8193 bit RSA key
++const largeRSAKeyCertPEM = `-----BEGIN CERTIFICATE-----
++MIIInjCCBIWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0
++aW5nMB4XDTIzMDYwNzIxMjMzNloXDTIzMDYwNzIzMjMzNlowEjEQMA4GA1UEAxMH
++dGVzdGluZzCCBCIwDQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBAWdHsf6Rh2Ca
++n2SQwn4t4OQrOjbLLdGE1pM6TBKKrHUFy62uEL8atNjlcfXIsa4aEu3xNGiqxqur
++ZectlkZbm0FkaaQ1Wr9oikDY3KfjuaXdPdO/XC/h8AKNxlDOylyXwUSK/CuYb+1j
++gy8yF5QFvVfwW/xwTlHmhUeSkVSQPosfQ6yXNNsmMzkd+ZPWLrfq4R+wiNtwYGu0
++WSBcI/M9o8/vrNLnIppoiBJJ13j9CR1ToEAzOFh9wwRWLY10oZhoh1ONN1KQURx4
++qedzvvP2DSjZbUccdvl2rBGvZpzfOiFdm1FCnxB0c72Cqx+GTHXBFf8bsa7KHky9
++sNO1GUanbq17WoDNgwbY6H51bfShqv0CErxatwWox3we4EcAmFHPVTCYL1oWVMGo
++a3Eth91NZj+b/nGhF9lhHKGzXSv9brmLLkfvM1jA6XhNhA7BQ5Vz67lj2j3XfXdh
++t/BU5pBXbL4Ut4mIhT1YnKXAjX2/LF5RHQTE8Vwkx5JAEKZyUEGOReD/B+7GOrLp
++HduMT9vZAc5aR2k9I8qq1zBAzsL69lyQNAPaDYd1BIAjUety9gAYaSQffCgAgpRO
++Gt+DYvxS+7AT/yEd5h74MU2AH7KrAkbXOtlwupiGwhMVTstncDJWXMJqbBhyHPF8
++3UmZH0hbL4PYmzSj9LDWQQXI2tv6vrCpfts3Cqhqxz9vRpgY7t1Wu6l/r+KxYYz3
++1pcGpPvRmPh0DJm7cPTiXqPnZcPt+ulSaSdlxmd19OnvG5awp0fXhxryZVwuiT8G
++VDkhyARrxYrdjlINsZJZbQjO0t8ketXAELJOnbFXXzeCOosyOHkLwsqOO96AVJA8
++45ZVL5m95ClGy0RSrjVIkXsxTAMVG6SPAqKwk6vmTdRGuSPS4rhgckPVDHmccmuq
++dfnT2YkX+wB2/M3oCgU+s30fAHGkbGZ0pCdNbFYFZLiH0iiMbTDl/0L/z7IdK0nH
++GLHVE7apPraKC6xl6rPWsD2iSfrmtIPQa0+rqbIVvKP5JdfJ8J4alI+OxFw/znQe
++V0/Rez0j22Fe119LZFFSXhRv+ZSvcq20xDwh00mzcumPWpYuCVPozA18yIhC9tNn
++ALHndz0tDseIdy9vC71jQWy9iwri3ueN0DekMMF8JGzI1Z6BAFzgyAx3DkHtwHg7
++B7qD0jPG5hJ5+yt323fYgJsuEAYoZ8/jzZ01pkX8bt+UsVN0DGnSGsI2ktnIIk3J
++l+8krjmUy6EaW79nITwoOqaeHOIp8m3UkjEcoKOYrzHRKqRy+A09rY+m/cAQaafW
++4xp0Zv7qZPLwnu0jsqB4jD8Ll9yPB02ndsoV6U5PeHzTkVhPml19jKUAwFfs7TJg
++kXy+/xFhYVUCAwEAATANBgkqhkiG9w0BAQsFAAOCBAIAAQnZY77pMNeypfpba2WK
++aDasT7dk2JqP0eukJCVPTN24Zca+xJNPdzuBATm/8SdZK9lddIbjSnWRsKvTnO2r
++/rYdlPf3jM5uuJtb8+Uwwe1s+gszelGS9G/lzzq+ehWicRIq2PFcs8o3iQMfENiv
++qILJ+xjcrvms5ZPDNahWkfRx3KCg8Q+/at2n5p7XYjMPYiLKHnDC+RE2b1qT20IZ
++FhuK/fTWLmKbfYFNNga6GC4qcaZJ7x0pbm4SDTYp0tkhzcHzwKhidfNB5J2vNz6l
++Ur6wiYwamFTLqcOwWo7rdvI+sSn05WQBv0QZlzFX+OAu0l7WQ7yU+noOxBhjvHds
++14+r9qcQZg2q9kG+evopYZqYXRUNNlZKo9MRBXhfrISulFAc5lRFQIXMXnglvAu+
++Ipz2gomEAOcOPNNVldhKAU94GAMJd/KfN0ZP7gX3YvPzuYU6XDhag5RTohXLm18w
++5AF+ES3DOQ6ixu3DTf0D+6qrDuK+prdX8ivcdTQVNOQ+MIZeGSc6NWWOTaMGJ3lg
++aZIxJUGdo6E7GBGiC1YTjgFKFbHzek1LRTh/LX3vbSudxwaG0HQxwsU9T4DWiMqa
++Fkf2KteLEUA6HrR+0XlAZrhwoqAmrJ+8lCFX3V0gE9lpENfVHlFXDGyx10DpTB28
++DdjnY3F7EPWNzwf9P3oNT69CKW3Bk6VVr3ROOJtDxVu1ioWo3TaXltQ0VOnap2Pu
++sa5wfrpfwBDuAS9JCDg4ttNp2nW3F7tgXC6xPqw5pvGwUppEw9XNrqV8TZrxduuv
++rQ3NyZ7KSzIpmFlD3UwV/fGfz3UQmHS6Ng1evrUID9DjfYNfRqSGIGjDfxGtYD+j
++Z1gLJZuhjJpNtwBkKRtlNtrCWCJK2hidK/foxwD7kwAPo2I9FjpltxCRywZUs07X
++KwXTfBR9v6ij1LV6K58hFS+8ezZyZ05CeVBFkMQdclTOSfuPxlMkQOtjp8QWDj+F
++j/MYziT5KBkHvcbrjdRtUJIAi4N7zCsPZtjik918AK1WBNRVqPbrgq/XSEXMfuvs
++6JbfK0B76vdBDRtJFC1JsvnIrGbUztxXzyQwFLaR/AjVJqpVlysLWzPKWVX6/+SJ
++u1NQOl2E8P6ycyBsuGnO89p0S4F8cMRcI2X1XQsZ7/q0NBrOMaEp5T3SrWo9GiQ3
++o2SBdbs3Y6MBPBtTu977Z/0RO63J3M5i2tjUiDfrFy7+VRLKr7qQ7JibohyB8QaR
++9tedgjn2f+of7PnP/PEl1cCphUZeHM7QKUMPT8dbqwmKtlYY43EHXcvNOT5IBk3X
++9lwJoZk/B2i+ZMRNSP34ztAwtxmasPt6RAWGQpWCn9qmttAHAnMfDqe7F7jVR6rS
++u58=
++-----END CERTIFICATE-----`
++
++func TestHandshakeRSATooBig(t *testing.T) {
++ testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM))
++
++ c := &Conn{conn: &discardConn{}, config: testConfig.Clone()}
++
++ expectedErr := "tls: server sent certificate containing RSA key larger than 8192 bits"
++ err := c.verifyServerCertificate([][]byte{testCert.Bytes})
++ if err == nil || err.Error() != expectedErr {
++ t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", expectedErr, err)
++ }
++
++ expectedErr = "tls: client sent certificate containing RSA key larger than 8192 bits"
++ err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}})
++ if err == nil || err.Error() != expectedErr {
++ t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", expectedErr, err)
++ }
++}
+diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
+index 8d51e7e..a5d8f4a 100644
+--- a/src/crypto/tls/handshake_server.go
++++ b/src/crypto/tls/handshake_server.go
+@@ -812,6 +812,10 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse client certificate: " + err.Error())
+ }
++ if certs[i].PublicKeyAlgorithm == x509.RSA && certs[i].PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
++ c.sendAlert(alertBadCertificate)
++ return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
++ }
+ }
+
+ if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
+--
+2.40.0
diff --git a/meta/recipes-devtools/go/go-1.19/add_godebug.patch b/meta/recipes-devtools/go/go-1.19/add_godebug.patch
new file mode 100644
index 0000000000..0c3d2d2855
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/add_godebug.patch
@@ -0,0 +1,84 @@
+
+Upstream-Status: Backport [see text]
+
+https://github.com/golong/go.git as of commit 22c1d18a27...
+Copy src/internal/godebug from go 1.19 since it does not
+exist in 1.17.
+
+Signed-off-by: Joe Slater <joe.slater@windriver.com>
+---
+
+--- /dev/null
++++ go/src/internal/godebug/godebug.go
+@@ -0,0 +1,34 @@
++// Copyright 2021 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 godebug parses the GODEBUG environment variable.
++package godebug
++
++import "os"
++
++// Get returns the value for the provided GODEBUG key.
++func Get(key string) string {
++ return get(os.Getenv("GODEBUG"), key)
++}
++
++// get returns the value part of key=value in s (a GODEBUG value).
++func get(s, key string) string {
++ for i := 0; i < len(s)-len(key)-1; i++ {
++ if i > 0 && s[i-1] != ',' {
++ continue
++ }
++ afterKey := s[i+len(key):]
++ if afterKey[0] != '=' || s[i:i+len(key)] != key {
++ continue
++ }
++ val := afterKey[1:]
++ for i, b := range val {
++ if b == ',' {
++ return val[:i]
++ }
++ }
++ return val
++ }
++ return ""
++}
+--- /dev/null
++++ go/src/internal/godebug/godebug_test.go
+@@ -0,0 +1,34 @@
++// Copyright 2021 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 godebug
++
++import "testing"
++
++func TestGet(t *testing.T) {
++ tests := []struct {
++ godebug string
++ key string
++ want string
++ }{
++ {"", "", ""},
++ {"", "foo", ""},
++ {"foo=bar", "foo", "bar"},
++ {"foo=bar,after=x", "foo", "bar"},
++ {"before=x,foo=bar,after=x", "foo", "bar"},
++ {"before=x,foo=bar", "foo", "bar"},
++ {",,,foo=bar,,,", "foo", "bar"},
++ {"foodecoy=wrong,foo=bar", "foo", "bar"},
++ {"foo=", "foo", ""},
++ {"foo", "foo", ""},
++ {",foo", "foo", ""},
++ {"foo=bar,baz", "loooooooong", ""},
++ }
++ for _, tt := range tests {
++ got := get(tt.godebug, tt.key)
++ if got != tt.want {
++ t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.key, got, tt.want)
++ }
++ }
++}
diff --git a/meta/recipes-devtools/go/go-1.19/cve-2022-41724.patch b/meta/recipes-devtools/go/go-1.19/cve-2022-41724.patch
new file mode 100644
index 0000000000..aacffbffcd
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/cve-2022-41724.patch
@@ -0,0 +1,2391 @@
+From 00b256e9e3c0fa02a278ec9dfc3e191e02ceaf80 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <roland@golang.org>
+Date: Wed, 14 Dec 2022 09:43:16 -0800
+Subject: [PATCH] [release-branch.go1.19] crypto/tls: replace all usages of
+ BytesOrPanic
+
+Message marshalling makes use of BytesOrPanic a lot, under the
+assumption that it will never panic. This assumption was incorrect, and
+specifically crafted handshakes could trigger panics. Rather than just
+surgically replacing the usages of BytesOrPanic in paths that could
+panic, replace all usages of it with proper error returns in case there
+are other ways of triggering panics which we didn't find.
+
+In one specific case, the tree routed by expandLabel, we replace the
+usage of BytesOrPanic, but retain a panic. This function already
+explicitly panicked elsewhere, and returning an error from it becomes
+rather painful because it requires changing a large number of APIs.
+The marshalling is unlikely to ever panic, as the inputs are all either
+fixed length, or already limited to the sizes required. If it were to
+panic, it'd likely only be during development. A close inspection shows
+no paths for a user to cause a panic currently.
+
+This patches ends up being rather large, since it requires routing
+errors back through functions which previously had no error returns.
+Where possible I've tried to use helpers that reduce the verbosity
+of frequently repeated stanzas, and to make the diffs as minimal as
+possible.
+
+Thanks to Marten Seemann for reporting this issue.
+
+Updates #58001
+Fixes #58358
+Fixes CVE-2022-41724
+
+Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+(cherry picked from commit 0f3a44ad7b41cc89efdfad25278953e17d9c1e04)
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728204
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/468117
+Auto-Submit: Michael Pratt <mpratt@google.com>
+Run-TryBot: Michael Pratt <mpratt@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Reviewed-by: Than McIntosh <thanm@google.com>
+---
+
+CVE: CVE-2022-41724
+
+Upstream-Status: Backport [see text]
+
+https://github.com/golong/go.git commit 00b256e9e3c0fa...
+boring_test.go does not exist
+modified for conn.go and handshake_messages.go
+
+Signed-off-by: Joe Slater <joe.slater@windriver.com>
+
+---
+ src/crypto/tls/boring_test.go | 2 +-
+ src/crypto/tls/common.go | 2 +-
+ src/crypto/tls/conn.go | 46 +-
+ src/crypto/tls/handshake_client.go | 95 +--
+ src/crypto/tls/handshake_client_test.go | 4 +-
+ src/crypto/tls/handshake_client_tls13.go | 74 ++-
+ src/crypto/tls/handshake_messages.go | 716 +++++++++++-----------
+ src/crypto/tls/handshake_messages_test.go | 19 +-
+ src/crypto/tls/handshake_server.go | 73 ++-
+ src/crypto/tls/handshake_server_test.go | 31 +-
+ src/crypto/tls/handshake_server_tls13.go | 71 ++-
+ src/crypto/tls/key_schedule.go | 19 +-
+ src/crypto/tls/ticket.go | 8 +-
+ 13 files changed, 657 insertions(+), 503 deletions(-)
+
+--- go.orig/src/crypto/tls/common.go
++++ go/src/crypto/tls/common.go
+@@ -1357,7 +1357,7 @@ func (c *Certificate) leaf() (*x509.Cert
+ }
+
+ type handshakeMessage interface {
+- marshal() []byte
++ marshal() ([]byte, error)
+ unmarshal([]byte) bool
+ }
+
+--- go.orig/src/crypto/tls/conn.go
++++ go/src/crypto/tls/conn.go
+@@ -994,18 +994,46 @@ func (c *Conn) writeRecordLocked(typ rec
+ 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() (interface{}, error) {
++// the record layer. If transcript is non-nil, the message
++// is written to the passed transcriptHash.
++
++// backport 00b256e9e3c0fa02a278ec9dfc3e191e02ceaf80
++//
++// Commit wants to set this to
++//
++// func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
++//
++// but that does not compile. Retain the original interface{} argument.
++//
++func (c *Conn) readHandshake(transcript transcriptHash) (interface{}, error) {
+ for c.hand.Len() < 4 {
+ if err := c.readRecord(); err != nil {
+ return nil, err
+@@ -1084,6 +1112,11 @@ func (c *Conn) readHandshake() (interfac
+ if !m.unmarshal(data) {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
++
++ if transcript != nil {
++ transcript.Write(data)
++ }
++
+ return m, nil
+ }
+
+@@ -1159,7 +1192,7 @@ func (c *Conn) handleRenegotiation() err
+ return errors.New("tls: internal error: unexpected renegotiation")
+ }
+
+- msg, err := c.readHandshake()
++ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+@@ -1205,7 +1238,7 @@ func (c *Conn) handlePostHandshakeMessag
+ return c.handleRenegotiation()
+ }
+
+- msg, err := c.readHandshake()
++ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+@@ -1241,7 +1274,11 @@ func (c *Conn) handleKeyUpdate(keyUpdate
+ 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)
+--- go.orig/src/crypto/tls/handshake_client.go
++++ go/src/crypto/tls/handshake_client.go
+@@ -157,7 +157,10 @@ func (c *Conn) clientHandshake(ctx conte
+ }
+ 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
+@@ -172,11 +175,12 @@ func (c *Conn) clientHandshake(ctx conte
+ }()
+ }
+
+- 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
+ }
+@@ -241,9 +245,9 @@ func (c *Conn) clientHandshake(ctx conte
+ }
+
+ 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
+@@ -258,14 +262,14 @@ func (c *Conn) loadSession(hello *client
+ // 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.
+@@ -277,7 +281,7 @@ func (c *Conn) loadSession(hello *client
+ }
+ }
+ 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
+@@ -286,16 +290,16 @@ func (c *Conn) loadSession(hello *client
+ 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
+ }
+ }
+
+@@ -303,7 +307,7 @@ func (c *Conn) loadSession(hello *client
+ // 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
+@@ -313,14 +317,14 @@ func (c *Conn) loadSession(hello *client
+ // 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 {
+@@ -331,7 +335,7 @@ func (c *Conn) loadSession(hello *client
+ }
+ }
+ 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.
+@@ -349,9 +353,15 @@ func (c *Conn) loadSession(hello *client
+ 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
+ }
+@@ -396,8 +406,12 @@ func (hs *clientHandshakeState) handshak
+ 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
+@@ -468,7 +482,7 @@ func (hs *clientHandshakeState) pickCiph
+ func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+- msg, err := c.readHandshake()
++ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+@@ -477,9 +491,8 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+ }
+@@ -497,11 +510,10 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+ }
+@@ -530,14 +542,13 @@ func (hs *clientHandshakeState) doFullHa
+
+ 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
+ }
+@@ -548,7 +559,6 @@ func (hs *clientHandshakeState) doFullHa
+ 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 {
+@@ -556,7 +566,7 @@ func (hs *clientHandshakeState) doFullHa
+ return err
+ }
+
+- msg, err = c.readHandshake()
++ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+@@ -567,7 +577,6 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+@@ -575,8 +584,7 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+ }
+ }
+@@ -587,8 +595,7 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+ }
+ }
+@@ -635,8 +642,7 @@ func (hs *clientHandshakeState) doFullHa
+ 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
+ }
+ }
+@@ -771,7 +777,10 @@ func (hs *clientHandshakeState) readFini
+ 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
+ }
+@@ -787,7 +796,11 @@ func (hs *clientHandshakeState) readFini
+ 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
+ }
+@@ -798,7 +811,7 @@ func (hs *clientHandshakeState) readSess
+ }
+
+ c := hs.c
+- msg, err := c.readHandshake()
++ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+@@ -807,7 +820,6 @@ func (hs *clientHandshakeState) readSess
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+- hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+ hs.session = &ClientSessionState{
+ sessionTicket: sessionTicketMsg.ticket,
+@@ -827,14 +839,13 @@ func (hs *clientHandshakeState) readSess
+ 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)
+--- go.orig/src/crypto/tls/handshake_client_test.go
++++ go/src/crypto/tls/handshake_client_test.go
+@@ -1257,7 +1257,7 @@ func TestServerSelectingUnconfiguredAppl
+ 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 @@ func TestServerSelectingUnconfiguredCiph
+ random: make([]byte, 32),
+ cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
+ }
+- serverHelloBytes := serverHello.marshal()
++ serverHelloBytes := mustMarshal(t, serverHello)
+
+ s.Write([]byte{
+ byte(recordTypeHandshake),
+--- go.orig/src/crypto/tls/handshake_client_tls13.go
++++ go/src/crypto/tls/handshake_client_tls13.go
+@@ -58,7 +58,10 @@ func (hs *clientHandshakeStateTLS13) han
+ }
+
+ 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 {
+@@ -69,7 +72,9 @@ func (hs *clientHandshakeStateTLS13) han
+ }
+ }
+
+- 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 {
+@@ -168,8 +173,7 @@ func (hs *clientHandshakeStateTLS13) sen
+ }
+ 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
+@@ -184,7 +188,9 @@ func (hs *clientHandshakeStateTLS13) pro
+ 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
+@@ -249,10 +255,18 @@ func (hs *clientHandshakeStateTLS13) pro
+ 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
+@@ -260,12 +274,12 @@ func (hs *clientHandshakeStateTLS13) pro
+ }
+ }
+
+- 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
+ }
+@@ -354,6 +368,7 @@ func (hs *clientHandshakeStateTLS13) est
+ if !hs.usingPSK {
+ earlySecret = hs.suite.extract(nil, nil)
+ }
++
+ handshakeSecret := hs.suite.extract(sharedKey,
+ hs.suite.deriveSecret(earlySecret, "derived", nil))
+
+@@ -384,7 +399,7 @@ func (hs *clientHandshakeStateTLS13) est
+ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
+ c := hs.c
+
+- msg, err := c.readHandshake()
++ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+@@ -394,7 +409,6 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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)
+@@ -423,18 +437,16 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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
+ }
+@@ -449,7 +461,6 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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
+@@ -458,7 +469,10 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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
+ }
+@@ -489,7 +503,9 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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
+ }
+@@ -497,7 +513,10 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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
+ }
+@@ -514,7 +533,9 @@ func (hs *clientHandshakeStateTLS13) rea
+ 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.
+
+@@ -563,8 +584,7 @@ func (hs *clientHandshakeStateTLS13) sen
+ 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
+ }
+
+@@ -601,8 +621,7 @@ func (hs *clientHandshakeStateTLS13) sen
+ }
+ 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
+ }
+
+@@ -616,8 +635,7 @@ func (hs *clientHandshakeStateTLS13) sen
+ 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
+ }
+
+--- go.orig/src/crypto/tls/handshake_messages.go
++++ go/src/crypto/tls/handshake_messages.go
+@@ -5,6 +5,7 @@
+ package tls
+
+ import (
++ "errors"
+ "fmt"
+ "strings"
+
+@@ -94,9 +95,181 @@ type clientHelloMsg struct {
+ 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 @@ func (m *clientHelloMsg) marshal() []byt
+ 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)
+ // TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported.
+ b := cryptobyte.NewBuilder(m.raw[:lenWithoutBinders])
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+@@ -339,9 +346,11 @@ func (m *clientHelloMsg) updateBinders(p
+ }
+ })
+ if len(b.BytesOrPanic()) != 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 {
+@@ -613,9 +622,98 @@ type serverHelloMsg struct {
+ 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
+@@ -629,104 +727,15 @@ func (m *serverHelloMsg) marshal() []byt
+ 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 {
+@@ -844,9 +853,9 @@ type encryptedExtensionsMsg struct {
+ 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
+@@ -866,8 +875,9 @@ func (m *encryptedExtensionsMsg) marshal
+ })
+ })
+
+- 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 {
+@@ -915,10 +925,10 @@ func (m *encryptedExtensionsMsg) unmarsh
+
+ 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 {
+@@ -930,9 +940,9 @@ type keyUpdateMsg struct {
+ 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
+@@ -945,8 +955,9 @@ func (m *keyUpdateMsg) marshal() []byte
+ }
+ })
+
+- 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 {
+@@ -978,9 +989,9 @@ type newSessionTicketMsgTLS13 struct {
+ 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
+@@ -1005,8 +1016,9 @@ func (m *newSessionTicketMsgTLS13) marsh
+ })
+ })
+
+- 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 {
+@@ -1059,9 +1071,9 @@ type certificateRequestMsgTLS13 struct {
+ 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
+@@ -1120,8 +1132,9 @@ func (m *certificateRequestMsgTLS13) mar
+ })
+ })
+
+- 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 {
+@@ -1205,9 +1218,9 @@ type certificateMsg struct {
+ 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
+@@ -1216,7 +1229,7 @@ func (m *certificateMsg) marshal() (x []
+ }
+
+ 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)
+@@ -1237,7 +1250,7 @@ func (m *certificateMsg) marshal() (x []
+ }
+
+ m.raw = x
+- return
++ return m.raw, nil
+ }
+
+ func (m *certificateMsg) unmarshal(data []byte) bool {
+@@ -1284,9 +1297,9 @@ type certificateMsgTLS13 struct {
+ 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
+@@ -1304,8 +1317,9 @@ func (m *certificateMsgTLS13) marshal()
+ 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) {
+@@ -1428,9 +1442,9 @@ type serverKeyExchangeMsg struct {
+ 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)
+@@ -1441,7 +1455,7 @@ func (m *serverKeyExchangeMsg) marshal()
+ copy(x[4:], m.key)
+
+ m.raw = x
+- return x
++ return x, nil
+ }
+
+ func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+@@ -1458,9 +1472,9 @@ type certificateStatusMsg struct {
+ 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
+@@ -1472,8 +1486,9 @@ func (m *certificateStatusMsg) marshal()
+ })
+ })
+
+- 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 {
+@@ -1492,10 +1507,10 @@ func (m *certificateStatusMsg) unmarshal
+
+ 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 {
+@@ -1507,9 +1522,9 @@ type clientKeyExchangeMsg struct {
+ 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)
+@@ -1520,7 +1535,7 @@ func (m *clientKeyExchangeMsg) marshal()
+ copy(x[4:], m.ciphertext)
+
+ m.raw = x
+- return x
++ return x, nil
+ }
+
+ func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+@@ -1541,9 +1556,9 @@ type finishedMsg struct {
+ 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
+@@ -1552,8 +1567,9 @@ func (m *finishedMsg) marshal() []byte {
+ 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 {
+@@ -1575,9 +1591,9 @@ type certificateRequestMsg struct {
+ 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.
+@@ -1592,7 +1608,7 @@ func (m *certificateRequestMsg) marshal(
+ 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)
+@@ -1627,7 +1643,7 @@ func (m *certificateRequestMsg) marshal(
+ }
+
+ m.raw = x
+- return
++ return m.raw, nil
+ }
+
+ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+@@ -1713,9 +1729,9 @@ type certificateVerifyMsg struct {
+ 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
+@@ -1729,8 +1745,9 @@ func (m *certificateVerifyMsg) marshal()
+ })
+ })
+
+- 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 {
+@@ -1753,15 +1770,15 @@ type newSessionTicketMsg struct {
+ 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)
+@@ -1772,7 +1789,7 @@ func (m *newSessionTicketMsg) marshal()
+
+ m.raw = x
+
+- return
++ return m.raw, nil
+ }
+
+ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+@@ -1800,10 +1817,25 @@ func (m *newSessionTicketMsg) unmarshal(
+ 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
++}
+--- go.orig/src/crypto/tls/handshake_messages_test.go
++++ go/src/crypto/tls/handshake_messages_test.go
+@@ -37,6 +37,15 @@ var tests = []interface{}{
+ &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()))
+
+@@ -55,7 +64,7 @@ func TestMarshalUnmarshal(t *testing.T)
+ }
+
+ 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)
+@@ -408,12 +417,12 @@ func TestRejectEmptySCTList(t *testing.T
+
+ 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) {
+@@ -451,12 +460,12 @@ func TestRejectEmptySCT(t *testing.T) {
+ // 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) {
+--- go.orig/src/crypto/tls/handshake_server.go
++++ go/src/crypto/tls/handshake_server.go
+@@ -129,7 +129,9 @@ func (hs *serverHandshakeState) handshak
+
+ // 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
+ }
+@@ -456,9 +458,10 @@ func (hs *serverHandshakeState) doResume
+ 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
+ }
+
+@@ -496,24 +499,23 @@ func (hs *serverHandshakeState) doFullHa
+ // 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
+ }
+ }
+@@ -525,8 +527,7 @@ func (hs *serverHandshakeState) doFullHa
+ 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
+ }
+ }
+@@ -552,15 +553,13 @@ func (hs *serverHandshakeState) doFullHa
+ 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
+ }
+
+@@ -570,7 +569,7 @@ func (hs *serverHandshakeState) doFullHa
+
+ 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
+ }
+@@ -583,7 +582,6 @@ func (hs *serverHandshakeState) doFullHa
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+- hs.finishedHash.Write(certMsg.marshal())
+
+ if err := c.processCertsFromClient(Certificate{
+ Certificate: certMsg.certificates,
+@@ -594,7 +592,7 @@ func (hs *serverHandshakeState) doFullHa
+ pub = c.peerCertificates[0].PublicKey
+ }
+
+- msg, err = c.readHandshake()
++ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+@@ -612,7 +610,6 @@ func (hs *serverHandshakeState) doFullHa
+ 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 {
+@@ -632,7 +629,10 @@ func (hs *serverHandshakeState) doFullHa
+ // 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
+ }
+@@ -667,7 +667,9 @@ func (hs *serverHandshakeState) doFullHa
+ 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()
+@@ -707,7 +709,10 @@ func (hs *serverHandshakeState) readFini
+ 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
+ }
+@@ -724,7 +729,10 @@ func (hs *serverHandshakeState) readFini
+ 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
+ }
+@@ -758,14 +766,16 @@ func (hs *serverHandshakeState) sendSess
+ 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
+ }
+
+@@ -775,14 +785,13 @@ func (hs *serverHandshakeState) sendSess
+ 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
+ }
+
+--- go.orig/src/crypto/tls/handshake_server_test.go
++++ go/src/crypto/tls/handshake_server_test.go
+@@ -30,6 +30,13 @@ func testClientHello(t *testing.T, serve
+ 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 @@ func testClientHelloFailure(t *testing.T
+ 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 @@ func TestRenegotiationExtension(t *testi
+ 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 @@ func TestTLS12OnlyCipherSuites(t *testin
+ 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
+@@ -308,8 +321,10 @@ func TestTLSPointFormats(t *testing.T) {
+ 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
+@@ -1425,7 +1440,9 @@ func TestSNIGivenOnFailure(t *testing.T)
+ 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)
+--- go.orig/src/crypto/tls/handshake_server_tls13.go
++++ go/src/crypto/tls/handshake_server_tls13.go
+@@ -298,7 +298,12 @@ func (hs *serverHandshakeStateTLS13) che
+ 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)
+@@ -389,8 +394,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ }
+ hs.sentDummyCCS = true
+
+- _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+- return err
++ return hs.c.writeChangeCipherRecord()
+ }
+
+ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
+@@ -398,7 +402,9 @@ func (hs *serverHandshakeStateTLS13) doH
+
+ // 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))})
+@@ -414,8 +420,7 @@ func (hs *serverHandshakeStateTLS13) doH
+ 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
+ }
+
+@@ -423,7 +428,8 @@ func (hs *serverHandshakeStateTLS13) doH
+ return err
+ }
+
+- msg, err := c.readHandshake()
++ // clientHelloMsg is not included in the transcript.
++ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+@@ -514,9 +520,10 @@ func illegalClientHelloChange(ch, ch1 *c
+ 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
+ }
+
+@@ -559,8 +566,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+ }
+
+@@ -589,8 +595,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+ }
+ }
+@@ -601,8 +606,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+ }
+
+@@ -633,8 +637,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ }
+ 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
+ }
+
+@@ -648,8 +651,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+ }
+
+@@ -710,7 +712,9 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+@@ -735,8 +739,12 @@ func (hs *serverHandshakeStateTLS13) sen
+ 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
+ }
+@@ -755,7 +763,7 @@ func (hs *serverHandshakeStateTLS13) sen
+ // 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
+ }
+
+@@ -780,7 +788,7 @@ func (hs *serverHandshakeStateTLS13) rea
+ // 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
+ }
+@@ -790,7 +798,6 @@ func (hs *serverHandshakeStateTLS13) rea
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+- hs.transcript.Write(certMsg.marshal())
+
+ if err := c.processCertsFromClient(certMsg.certificate); err != nil {
+ return err
+@@ -804,7 +811,10 @@ func (hs *serverHandshakeStateTLS13) rea
+ }
+
+ 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
+ }
+@@ -835,7 +845,9 @@ func (hs *serverHandshakeStateTLS13) rea
+ 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
+@@ -850,7 +862,8 @@ func (hs *serverHandshakeStateTLS13) rea
+ 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
+ }
+--- go.orig/src/crypto/tls/key_schedule.go
++++ go/src/crypto/tls/key_schedule.go
+@@ -8,6 +8,7 @@ import (
+ "crypto/elliptic"
+ "crypto/hmac"
+ "errors"
++ "fmt"
+ "hash"
+ "io"
+ "math/big"
+@@ -42,8 +43,24 @@ func (c *cipherSuiteTLS13) expandLabel(s
+ 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")
+ }
+--- go.orig/src/crypto/tls/ticket.go
++++ go/src/crypto/tls/ticket.go
+@@ -32,7 +32,7 @@ type sessionState struct {
+ 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 @@ func (m *sessionState) marshal() []byte
+ })
+ }
+ })
+- return b.BytesOrPanic()
++ return b.Bytes()
+ }
+
+ func (m *sessionState) unmarshal(data []byte) bool {
+@@ -86,7 +86,7 @@ type sessionStateTLS13 struct {
+ 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 @@ func (m *sessionStateTLS13) marshal() []
+ b.AddBytes(m.resumptionSecret)
+ })
+ marshalCertificate(&b, m.certificate)
+- return b.BytesOrPanic()
++ return b.Bytes()
+ }
+
+ func (m *sessionStateTLS13) unmarshal(data []byte) bool {
diff --git a/meta/recipes-devtools/go/go-1.19/cve-2022-41725.patch b/meta/recipes-devtools/go/go-1.19/cve-2022-41725.patch
new file mode 100644
index 0000000000..a71d07e3f1
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.19/cve-2022-41725.patch
@@ -0,0 +1,652 @@
+From 5c55ac9bf1e5f779220294c843526536605f42ab Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Wed, 25 Jan 2023 09:27:01 -0800
+Subject: [PATCH] [release-branch.go1.19] mime/multipart: limit memory/inode
+ consumption of ReadForm
+
+Reader.ReadForm is documented as storing "up to maxMemory bytes + 10MB"
+in memory. Parsed forms can consume substantially more memory than
+this limit, since ReadForm does not account for map entry overhead
+and MIME headers.
+
+In addition, while the amount of disk memory consumed by ReadForm can
+be constrained by limiting the size of the parsed input, ReadForm will
+create one temporary file per form part stored on disk, potentially
+consuming a large number of inodes.
+
+Update ReadForm's memory accounting to include part names,
+MIME headers, and map entry overhead.
+
+Update ReadForm to store all on-disk file parts in a single
+temporary file.
+
+Files returned by FileHeader.Open are documented as having a concrete
+type of *os.File when a file is stored on disk. The change to use a
+single temporary file for all parts means that this is no longer the
+case when a form contains more than a single file part stored on disk.
+
+The previous behavior of storing each file part in a separate disk
+file may be reenabled with GODEBUG=multipartfiles=distinct.
+
+Update Reader.NextPart and Reader.NextRawPart to set a 10MiB cap
+on the size of MIME headers.
+
+Thanks to Jakob Ackermann (@das7pad) for reporting this issue.
+
+Updates #58006
+Fixes #58362
+Fixes CVE-2022-41725
+
+Change-Id: Ibd780a6c4c83ac8bcfd3cbe344f042e9940f2eab
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1714276
+Reviewed-by: Julie Qiu <julieqiu@google.com>
+TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Run-TryBot: Damien Neil <dneil@google.com>
+(cherry picked from commit ed4664330edcd91b24914c9371c377c132dbce8c)
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728949
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/468116
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Reviewed-by: Than McIntosh <thanm@google.com>
+Run-TryBot: Michael Pratt <mpratt@google.com>
+Auto-Submit: Michael Pratt <mpratt@google.com>
+---
+
+CVE: CVE-2022-41725
+
+Upstream-Status: Backport [see text]
+
+https://github.com/golong/go.git commit 5c55ac9bf1e5...
+modified for reader.go
+
+Signed-off-by: Joe Slater <joe.slater@windriver.com>
+
+___
+ src/mime/multipart/formdata.go | 132 ++++++++++++++++++++-----
+ src/mime/multipart/formdata_test.go | 140 ++++++++++++++++++++++++++-
+ src/mime/multipart/multipart.go | 25 +++--
+ src/mime/multipart/readmimeheader.go | 14 +++
+ src/net/http/request_test.go | 2 +-
+ src/net/textproto/reader.go | 20 +++-
+ 6 files changed, 295 insertions(+), 38 deletions(-)
+ create mode 100644 src/mime/multipart/readmimeheader.go
+
+--- go.orig/src/mime/multipart/formdata.go
++++ go/src/mime/multipart/formdata.go
+@@ -7,6 +7,7 @@ package multipart
+ import (
+ "bytes"
+ "errors"
++ "internal/godebug"
+ "io"
+ "math"
+ "net/textproto"
+@@ -33,23 +34,58 @@ func (r *Reader) ReadForm(maxMemory int6
+
+ 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 @@ func (r *Reader) readForm(maxMemory int6
+ }
+ 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 @@ func (r *Reader) readForm(maxMemory int6
+ }
+
+ // 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 @@ func (r *Reader) readForm(maxMemory int6
+ 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 @@ func (f *Form) RemoveAll() error {
+ 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 @@ type FileHeader struct {
+ 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 File interface {
+
+ type sectionReadCloser struct {
+ *io.SectionReader
++ io.Closer
+ }
+
+ func (rc sectionReadCloser) Close() error {
++ if rc.Closer != nil {
++ return rc.Closer.Close()
++ }
+ return nil
+ }
+--- go.orig/src/mime/multipart/formdata_test.go
++++ go/src/mime/multipart/formdata_test.go
+@@ -6,8 +6,10 @@ package multipart
+
+ import (
+ "bytes"
++ "fmt"
+ "io"
+ "math"
++ "net/textproto"
+ "os"
+ "strings"
+ "testing"
+@@ -208,8 +210,8 @@ Content-Disposition: form-data; name="la
+ 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 @@ Content-Disposition: form-data; name="la
+ 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 @@ Content-Disposition: form-data; name="la
+ })
+ }
+ }
++
++// 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))
++ }
++}
+--- go.orig/src/mime/multipart/multipart.go
++++ go/src/mime/multipart/multipart.go
+@@ -128,12 +128,12 @@ func (r *stickyErrorReader) Read(p []byt
+ 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 @@ func newPart(mr *Reader, rawPart bool) (
+ return bp, nil
+ }
+
+-func (bp *Part) populateHeaders() error {
++func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error {
+ r := textproto.NewReader(bp.mr.bufReader)
+- header, err := r.ReadMIMEHeader()
++ header, err := readMIMEHeader(r, maxMIMEHeaderSize)
+ if err == nil {
+ bp.Header = header
+ }
++ // TODO: Add a distinguishable error to net/textproto.
++ if err != nil && err.Error() == "message too large" {
++ err = ErrMessageTooLarge
++ }
+ return err
+ }
+
+@@ -294,6 +298,7 @@ func (p *Part) Close() error {
+ // isn't supported.
+ type Reader struct {
+ bufReader *bufio.Reader
++ tempDir string // used in tests
+
+ currentPart *Part
+ partsRead int
+@@ -304,6 +309,10 @@ type Reader struct {
+ 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.
+ //
+@@ -311,7 +320,7 @@ type Reader struct {
+ // 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.
+@@ -320,10 +329,10 @@ func (r *Reader) NextPart() (*Part, erro
+ // 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()
+ }
+@@ -348,7 +357,7 @@ func (r *Reader) nextPart(rawPart bool)
+
+ if r.isBoundaryDelimiterLine(line) {
+ r.partsRead++
+- bp, err := newPart(r, rawPart)
++ bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
+ if err != nil {
+ return nil, err
+ }
+--- /dev/null
++++ go/src/mime/multipart/readmimeheader.go
+@@ -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)
+--- go.orig/src/net/http/request_test.go
++++ go/src/net/http/request_test.go
+@@ -1110,7 +1110,7 @@ func testMissingFile(t *testing.T, req *
+ 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)
+--- go.orig/src/net/textproto/reader.go
++++ go/src/net/textproto/reader.go
+@@ -7,8 +7,10 @@ package textproto
+ import (
+ "bufio"
+ "bytes"
++ "errors"
+ "fmt"
+ "io"
++ "math"
+ "strconv"
+ "strings"
+ "sync"
+@@ -481,6 +483,12 @@ func (r *Reader) ReadDotLines() ([]strin
+ // }
+ //
+ 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.
+@@ -521,6 +529,16 @@ func (r *Reader) ReadMIMEHeader() (MIMEH
+ continue
+ }
+
++ // backport 5c55ac9bf1e5f779220294c843526536605f42ab
++ //
++ // value is computed as
++ //
++ // value := string(bytes.TrimLeft(v, " \t"))
++ //
++ // in the original patch from 1.19. This relies on
++ // 'v' which does not exist in 1.17. We leave the
++ // 1.17 method unchanged.
++
+ // Skip initial spaces in value.
+ i++ // skip colon
+ for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
+@@ -529,6 +547,16 @@ func (r *Reader) ReadMIMEHeader() (MIMEH
+ value := string(kv[i:])
+
+ 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.