mirror of
https://github.com/golang/go.git
synced 2026-01-30 23:52:05 +03:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aee9a19c55 | ||
|
|
26eeaec89c | ||
|
|
9629fa1874 | ||
|
|
3243f93747 | ||
|
|
d2d0ee2049 | ||
|
|
230765a11a | ||
|
|
bdd86bda09 | ||
|
|
aef8a8cd42 | ||
|
|
ef793801f8 | ||
|
|
aaace6dda7 | ||
|
|
0f4483cfdc | ||
|
|
1362737f50 | ||
|
|
602eeaab38 | ||
|
|
ac556f35a2 | ||
|
|
1acd39cc92 | ||
|
|
7b398b1ff7 | ||
|
|
2d01f3695b | ||
|
|
965e9ba0fb | ||
|
|
85ded85b78 | ||
|
|
828b05cc64 | ||
|
|
202a1a5706 | ||
|
|
8e02cffd8e | ||
|
|
5286ac4ed8 | ||
|
|
53b43607d9 | ||
|
|
bdf07c2e16 | ||
|
|
3a04b6e12e | ||
|
|
00f5d3001a | ||
|
|
7628627cb2 | ||
|
|
1fa2deb1b1 | ||
|
|
a943fd0ccc | ||
|
|
fbba58a0a4 | ||
|
|
9987cb6cf3 | ||
|
|
90b06002c4 | ||
|
|
487be3f90b | ||
|
|
7302f83d87 | ||
|
|
de4748c47c | ||
|
|
52bd3b186b | ||
|
|
be7e4fee4b | ||
|
|
b68d699aa7 | ||
|
|
10124c2631 | ||
|
|
5adb0ca8e9 | ||
|
|
8b34676710 | ||
|
|
d7c6da8bac | ||
|
|
9eed826bf9 | ||
|
|
670ce9b8a8 | ||
|
|
b3160e8bce | ||
|
|
9efc2e7f95 | ||
|
|
32593a9192 | ||
|
|
eb598248ba | ||
|
|
9f02342144 | ||
|
|
0480336414 |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.20
|
||||
parent-branch: master
|
||||
|
||||
@@ -1200,9 +1200,8 @@ proxyHandler := &httputil.ReverseProxy{
|
||||
</p>
|
||||
|
||||
<p><!-- CL 444277 -->
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> and
|
||||
<a href="/pkg/time/#Time.UnmarshalJSON"><code>Time.UnmarshalJSON</code></a> methods
|
||||
are now more strict about adherence to RFC 3339.
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> method
|
||||
is now more strict about adherence to RFC 3339.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- time -->
|
||||
|
||||
@@ -167,7 +167,7 @@ func ParseFlags() {
|
||||
|
||||
Debug.ConcurrentOk = true
|
||||
Debug.InlFuncsWithClosures = 1
|
||||
Debug.InlStaticInit = 1
|
||||
Debug.InlStaticInit = 0
|
||||
if buildcfg.Experiment.Unified {
|
||||
Debug.Unified = 1
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
||||
var init ir.Nodes
|
||||
e.callCommon(ks, call, &init, nil)
|
||||
if len(init) != 0 {
|
||||
call.(*ir.CallExpr).PtrInit().Append(init...)
|
||||
call.(ir.InitNode).PtrInit().Append(init...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,18 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argumentFunc(nil, k, argp)
|
||||
}
|
||||
|
||||
argumentRType := func(rtypep *ir.Node) {
|
||||
rtype := *rtypep
|
||||
if rtype == nil {
|
||||
return
|
||||
}
|
||||
// common case: static rtype/itab argument, which can be evaluated within the wrapper instead.
|
||||
if addr, ok := rtype.(*ir.AddrExpr); ok && addr.Op() == ir.OADDR && addr.X.Op() == ir.OLINKSYMOFFSET {
|
||||
return
|
||||
}
|
||||
e.wrapExpr(rtype.Pos(), rtypep, init, call, wrapper)
|
||||
}
|
||||
|
||||
switch call.Op() {
|
||||
default:
|
||||
ir.Dump("esc", call)
|
||||
@@ -153,6 +165,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argument(e.heapHole(), &args[i])
|
||||
}
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OCOPY:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
@@ -163,6 +176,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
copiedK = e.heapHole().deref(call, "copied slice")
|
||||
}
|
||||
argument(copiedK, &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OPANIC:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
@@ -179,15 +193,21 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
for i := range call.Args {
|
||||
argument(e.discardHole(), &call.Args[i])
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(e.discardHole(), &call.X)
|
||||
|
||||
case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
|
||||
case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
argument(e.discardHole(), &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,9 +147,10 @@ func NewFunc(pos src.XPos) *Func {
|
||||
|
||||
func (f *Func) isStmt() {}
|
||||
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
|
||||
func (f *Func) Type() *types.Type { return f.Nname.Type() }
|
||||
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
|
||||
|
||||
@@ -256,18 +256,24 @@ func processType(t *ast.TypeSpec) {
|
||||
var copyBody strings.Builder
|
||||
var doChildrenBody strings.Builder
|
||||
var editChildrenBody strings.Builder
|
||||
var editChildrenWithHiddenBody strings.Builder
|
||||
for _, f := range fields {
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
hidden := false
|
||||
if f.Tag != nil {
|
||||
tag := f.Tag.Value[1 : len(f.Tag.Value)-1]
|
||||
if strings.HasPrefix(tag, "mknode:") {
|
||||
if tag[7:] == "\"-\"" {
|
||||
continue
|
||||
if !isNamedType(ft, "Node") {
|
||||
continue
|
||||
}
|
||||
hidden = true
|
||||
} else {
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
}
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
if isNamedType(ft, "Nodes") {
|
||||
// Nodes == []Node
|
||||
ft = &ast.ArrayType{Elt: &ast.Ident{Name: "Node"}}
|
||||
@@ -286,6 +292,20 @@ func processType(t *ast.TypeSpec) {
|
||||
continue
|
||||
}
|
||||
for _, name := range names {
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"edit%ss(n.%s, edit)\n", ft, name)
|
||||
} else {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
if hidden {
|
||||
continue
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(©Body, "c.%s = copy%ss(c.%s)\n", name, ft, name)
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
@@ -295,10 +315,6 @@ func processType(t *ast.TypeSpec) {
|
||||
} else {
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
"if n.%s != nil && do(n.%s) {\nreturn true\n}\n", name, name)
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
fmt.Fprintf(&editChildrenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
@@ -313,6 +329,9 @@ func processType(t *ast.TypeSpec) {
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildrenWithHidden(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenWithHiddenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
}
|
||||
|
||||
func generateHelpers() {
|
||||
|
||||
@@ -134,9 +134,10 @@ type Name struct {
|
||||
|
||||
func (n *Name) isExpr() {}
|
||||
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) editChildrenWithHidden(edit func(Node) Node) {}
|
||||
|
||||
// RecordFrameOffset records the frame offset for the name.
|
||||
// It is used by package types when laying out function arguments.
|
||||
|
||||
@@ -30,6 +30,7 @@ type Node interface {
|
||||
|
||||
doChildren(func(Node) bool) bool
|
||||
editChildren(func(Node) Node)
|
||||
editChildrenWithHidden(func(Node) Node)
|
||||
|
||||
// Abstract graph structure, for generic traversals.
|
||||
Op() Op
|
||||
|
||||
@@ -30,6 +30,13 @@ func (n *AddStringExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddStringExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AddrExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AddrExpr) copy() Node {
|
||||
@@ -58,6 +65,15 @@ func (n *AddrExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddrExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignListStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignListStmt) copy() Node {
|
||||
@@ -84,6 +100,11 @@ func (n *AssignListStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
func (n *AssignListStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
|
||||
func (n *AssignOpStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignOpStmt) copy() Node {
|
||||
@@ -112,6 +133,15 @@ func (n *AssignOpStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignOpStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignStmt) copy() Node {
|
||||
@@ -140,6 +170,15 @@ func (n *AssignStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BasicLit) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BasicLit) copy() Node {
|
||||
@@ -156,6 +195,9 @@ func (n *BasicLit) doChildren(do func(Node) bool) bool {
|
||||
func (n *BasicLit) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BasicLit) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *BinaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BinaryExpr) copy() Node {
|
||||
@@ -184,6 +226,18 @@ func (n *BinaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *BinaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BlockStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BlockStmt) copy() Node {
|
||||
@@ -205,6 +259,10 @@ func (n *BlockStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
func (n *BlockStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
|
||||
func (n *BranchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BranchStmt) copy() Node {
|
||||
@@ -221,6 +279,9 @@ func (n *BranchStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *BranchStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BranchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *CallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CallExpr) copy() Node {
|
||||
@@ -253,6 +314,17 @@ func (n *CallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Args, edit)
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
func (n *CallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNodes(n.Args, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
|
||||
func (n *CaseClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CaseClause) copy() Node {
|
||||
@@ -290,6 +362,15 @@ func (n *CaseClause) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CaseClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Var != nil {
|
||||
n.Var = edit(n.Var).(*Name)
|
||||
}
|
||||
editNodes(n.List, edit)
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *ClosureExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ClosureExpr) copy() Node {
|
||||
@@ -312,6 +393,12 @@ func (n *ClosureExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *ClosureExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *CommClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CommClause) copy() Node {
|
||||
@@ -339,6 +426,13 @@ func (n *CommClause) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CommClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Comm != nil {
|
||||
n.Comm = edit(n.Comm).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *CompLitExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CompLitExpr) copy() Node {
|
||||
@@ -366,6 +460,16 @@ func (n *CompLitExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *CompLitExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ConstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConstExpr) copy() Node {
|
||||
@@ -382,6 +486,9 @@ func (n *ConstExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ConstExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ConstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ConvExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConvExpr) copy() Node {
|
||||
@@ -404,6 +511,24 @@ func (n *ConvExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ConvExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.TypeWord != nil {
|
||||
n.TypeWord = edit(n.TypeWord).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.ElemRType != nil {
|
||||
n.ElemRType = edit(n.ElemRType).(Node)
|
||||
}
|
||||
if n.ElemElemRType != nil {
|
||||
n.ElemElemRType = edit(n.ElemElemRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Decl) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Decl) copy() Node {
|
||||
@@ -421,6 +546,11 @@ func (n *Decl) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *Decl) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicType) copy() Node {
|
||||
@@ -449,6 +579,15 @@ func (n *DynamicType) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicType) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicTypeAssertExpr) copy() Node {
|
||||
@@ -489,6 +628,21 @@ func (n *DynamicTypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicTypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ForStmt) copy() Node {
|
||||
@@ -522,6 +676,16 @@ func (n *ForStmt) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *ForStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
if n.Post != nil {
|
||||
n.Post = edit(n.Post).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *Func) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -546,6 +710,12 @@ func (n *GoDeferStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
func (n *GoDeferStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Ident) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Ident) copy() Node {
|
||||
@@ -562,6 +732,9 @@ func (n *Ident) doChildren(do func(Node) bool) bool {
|
||||
func (n *Ident) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *Ident) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *IfStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IfStmt) copy() Node {
|
||||
@@ -594,6 +767,14 @@ func (n *IfStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
func (n *IfStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
|
||||
func (n *IndexExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IndexExpr) copy() Node {
|
||||
@@ -622,6 +803,18 @@ func (n *IndexExpr) editChildren(edit func(Node) Node) {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
}
|
||||
func (n *IndexExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Index != nil {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlineMarkStmt) copy() Node {
|
||||
@@ -638,6 +831,9 @@ func (n *InlineMarkStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *InlineMarkStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *InlineMarkStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *InlinedCallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlinedCallExpr) copy() Node {
|
||||
@@ -664,6 +860,11 @@ func (n *InlinedCallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
func (n *InlinedCallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
|
||||
func (n *InstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InstExpr) copy() Node {
|
||||
@@ -691,6 +892,13 @@ func (n *InstExpr) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
func (n *InstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
|
||||
func (n *JumpTableStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *JumpTableStmt) copy() Node {
|
||||
@@ -713,6 +921,12 @@ func (n *JumpTableStmt) editChildren(edit func(Node) Node) {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
func (n *JumpTableStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Idx != nil {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *KeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *KeyExpr) copy() Node {
|
||||
@@ -741,6 +955,15 @@ func (n *KeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *KeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *LabelStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LabelStmt) copy() Node {
|
||||
@@ -757,6 +980,9 @@ func (n *LabelStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *LabelStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LabelStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LinksymOffsetExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LinksymOffsetExpr) copy() Node {
|
||||
@@ -773,6 +999,9 @@ func (n *LinksymOffsetExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *LinksymOffsetExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LinksymOffsetExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LogicalExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LogicalExpr) copy() Node {
|
||||
@@ -801,6 +1030,15 @@ func (n *LogicalExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *LogicalExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *MakeExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *MakeExpr) copy() Node {
|
||||
@@ -829,6 +1067,18 @@ func (n *MakeExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *MakeExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Name) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -847,6 +1097,9 @@ func (n *NilExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *NilExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *NilExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ParenExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ParenExpr) copy() Node {
|
||||
@@ -869,6 +1122,12 @@ func (n *ParenExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ParenExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RangeStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RangeStmt) copy() Node {
|
||||
@@ -914,6 +1173,37 @@ func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *RangeStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
if n.KeyTypeWord != nil {
|
||||
n.KeyTypeWord = edit(n.KeyTypeWord).(Node)
|
||||
}
|
||||
if n.KeySrcRType != nil {
|
||||
n.KeySrcRType = edit(n.KeySrcRType).(Node)
|
||||
}
|
||||
if n.ValueTypeWord != nil {
|
||||
n.ValueTypeWord = edit(n.ValueTypeWord).(Node)
|
||||
}
|
||||
if n.ValueSrcRType != nil {
|
||||
n.ValueSrcRType = edit(n.ValueSrcRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RawOrigExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RawOrigExpr) copy() Node {
|
||||
@@ -930,6 +1220,9 @@ func (n *RawOrigExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *RawOrigExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *RawOrigExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ResultExpr) copy() Node {
|
||||
@@ -946,6 +1239,9 @@ func (n *ResultExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ResultExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ResultExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ReturnStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ReturnStmt) copy() Node {
|
||||
@@ -967,6 +1263,10 @@ func (n *ReturnStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
func (n *ReturnStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
|
||||
func (n *SelectStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectStmt) copy() Node {
|
||||
@@ -993,6 +1293,11 @@ func (n *SelectStmt) editChildren(edit func(Node) Node) {
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SelectStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *SelectorExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectorExpr) copy() Node {
|
||||
@@ -1021,6 +1326,15 @@ func (n *SelectorExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *SelectorExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SendStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SendStmt) copy() Node {
|
||||
@@ -1049,6 +1363,15 @@ func (n *SendStmt) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SendStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Chan != nil {
|
||||
n.Chan = edit(n.Chan).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceExpr) copy() Node {
|
||||
@@ -1089,6 +1412,21 @@ func (n *SliceExpr) editChildren(edit func(Node) Node) {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Low != nil {
|
||||
n.Low = edit(n.Low).(Node)
|
||||
}
|
||||
if n.High != nil {
|
||||
n.High = edit(n.High).(Node)
|
||||
}
|
||||
if n.Max != nil {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceHeaderExpr) copy() Node {
|
||||
@@ -1123,6 +1461,18 @@ func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StarExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StarExpr) copy() Node {
|
||||
@@ -1145,6 +1495,12 @@ func (n *StarExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StarExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StringHeaderExpr) copy() Node {
|
||||
@@ -1173,6 +1529,15 @@ func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StringHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StructKeyExpr) copy() Node {
|
||||
@@ -1195,6 +1560,12 @@ func (n *StructKeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StructKeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SwitchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SwitchStmt) copy() Node {
|
||||
@@ -1227,6 +1598,14 @@ func (n *SwitchStmt) editChildren(edit func(Node) Node) {
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SwitchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(Node)
|
||||
}
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *TailCallStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TailCallStmt) copy() Node {
|
||||
@@ -1249,6 +1628,12 @@ func (n *TailCallStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
func (n *TailCallStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeAssertExpr) copy() Node {
|
||||
@@ -1271,6 +1656,15 @@ func (n *TypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeSwitchGuard) copy() Node {
|
||||
@@ -1294,6 +1688,14 @@ func (n *TypeSwitchGuard) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeSwitchGuard) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(*Ident)
|
||||
}
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *UnaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *UnaryExpr) copy() Node {
|
||||
@@ -1316,6 +1718,12 @@ func (n *UnaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *UnaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *typeNode) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *typeNode) copy() Node {
|
||||
@@ -1327,6 +1735,8 @@ func (n *typeNode) doChildren(do func(Node) bool) bool {
|
||||
}
|
||||
func (n *typeNode) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
func (n *typeNode) editChildrenWithHidden(edit func(Node) Node) {
|
||||
}
|
||||
|
||||
func copyCaseClauses(list []*CaseClause) []*CaseClause {
|
||||
if list == nil {
|
||||
|
||||
@@ -184,3 +184,15 @@ func EditChildren(n Node, edit func(Node) Node) {
|
||||
}
|
||||
n.editChildren(edit)
|
||||
}
|
||||
|
||||
// EditChildrenWithHidden is like EditChildren, but also edits
|
||||
// Node-typed fields tagged with `mknode:"-"`.
|
||||
//
|
||||
// TODO(mdempsky): Remove the `mknode:"-"` tags so this function can
|
||||
// go away.
|
||||
func EditChildrenWithHidden(n Node, edit func(Node) Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
n.editChildrenWithHidden(edit)
|
||||
}
|
||||
|
||||
@@ -231,6 +231,16 @@ func (r *reader) pos() src.XPos {
|
||||
return base.Ctxt.PosTable.XPos(r.pos0())
|
||||
}
|
||||
|
||||
// origPos reads a position from the bitstream, and returns both the
|
||||
// original raw position and an inlining-adjusted position.
|
||||
func (r *reader) origPos() (origPos, inlPos src.XPos) {
|
||||
r.suppressInlPos++
|
||||
origPos = r.pos()
|
||||
r.suppressInlPos--
|
||||
inlPos = r.inlPos(origPos)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) pos0() src.Pos {
|
||||
r.Sync(pkgbits.SyncPos)
|
||||
if !r.Bool() {
|
||||
@@ -517,13 +527,33 @@ func (r *reader) doTyp() *types.Type {
|
||||
}
|
||||
|
||||
func (r *reader) unionType() *types.Type {
|
||||
terms := make([]*types.Type, r.Len())
|
||||
tildes := make([]bool, len(terms))
|
||||
for i := range terms {
|
||||
tildes[i] = r.Bool()
|
||||
terms[i] = r.typ()
|
||||
// In the types1 universe, we only need to handle value types.
|
||||
// Impure interfaces (i.e., interfaces with non-trivial type sets
|
||||
// like "int | string") can only appear as type parameter bounds,
|
||||
// and this is enforced by the types2 type checker.
|
||||
//
|
||||
// However, type unions can still appear in pure interfaces if the
|
||||
// type union is equivalent to "any". E.g., typeparam/issue52124.go
|
||||
// declares variables with the type "interface { any | int }".
|
||||
//
|
||||
// To avoid needing to represent type unions in types1 (since we
|
||||
// don't have any uses for that today anyway), we simply fold them
|
||||
// to "any". As a consistency check, we still read the union terms
|
||||
// to make sure this substitution is safe.
|
||||
|
||||
pure := false
|
||||
for i, n := 0, r.Len(); i < n; i++ {
|
||||
_ = r.Bool() // tilde
|
||||
term := r.typ()
|
||||
if term.IsEmptyInterface() {
|
||||
pure = true
|
||||
}
|
||||
}
|
||||
return types.NewUnion(terms, tildes)
|
||||
if !pure {
|
||||
base.Fatalf("impure type set used in value type")
|
||||
}
|
||||
|
||||
return types.Types[types.TINTER]
|
||||
}
|
||||
|
||||
func (r *reader) interfaceType() *types.Type {
|
||||
@@ -2097,12 +2127,12 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Callee(r.obj())
|
||||
|
||||
case exprFuncInst:
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.funcInst(pos)
|
||||
if wrapperFn != nil {
|
||||
return wrapperFn
|
||||
}
|
||||
return r.curry(pos, false, baseFn, dictPtr, nil)
|
||||
return r.curry(origPos, false, baseFn, dictPtr, nil)
|
||||
|
||||
case exprConst:
|
||||
pos := r.pos()
|
||||
@@ -2132,7 +2162,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
case exprMethodVal:
|
||||
recv := r.expr()
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// For simple wrapperFn values, the existing machinery for creating
|
||||
@@ -2164,7 +2194,18 @@ func (r *reader) expr() (res ir.Node) {
|
||||
}
|
||||
|
||||
n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr)
|
||||
assert(n.Selection == wrapperFn.Selection)
|
||||
|
||||
// As a consistency check here, we make sure "n" selected the
|
||||
// same method (represented by a types.Field) that wrapperFn
|
||||
// selected. However, for anonymous receiver types, there can be
|
||||
// multiple such types.Field instances (#58563). So we may need
|
||||
// to fallback to making sure Sym and Type (including the
|
||||
// receiver parameter's type) match.
|
||||
if n.Selection != wrapperFn.Selection {
|
||||
assert(n.Selection.Sym == wrapperFn.Selection.Sym)
|
||||
assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type))
|
||||
assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type))
|
||||
}
|
||||
|
||||
wrapper := methodValueWrapper{
|
||||
rcvr: n.X.Type(),
|
||||
@@ -2181,7 +2222,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
// For more complicated method expressions, we construct a
|
||||
// function literal wrapper.
|
||||
return r.curry(pos, true, baseFn, recv, dictPtr)
|
||||
return r.curry(origPos, true, baseFn, recv, dictPtr)
|
||||
|
||||
case exprMethodExpr:
|
||||
recv := r.typ()
|
||||
@@ -2197,7 +2238,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
addr = true
|
||||
}
|
||||
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// If we already have a wrapper and don't need to do anything with
|
||||
@@ -2220,7 +2261,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), method.Sel)).(*ir.SelectorExpr)
|
||||
}
|
||||
|
||||
return r.methodExprWrap(pos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
|
||||
case exprIndex:
|
||||
x := r.expr()
|
||||
@@ -2550,7 +2591,7 @@ func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*type
|
||||
// If nilCheck is true and arg0 is an interface value, then it's
|
||||
// checked to be non-nil as an initial step at the point of evaluating
|
||||
// the function literal itself.
|
||||
func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(fun, arg0)
|
||||
if arg1 != nil {
|
||||
@@ -2574,13 +2615,13 @@ func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.
|
||||
r.syntheticTailCall(pos, fun, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, ifaceHack, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody)
|
||||
}
|
||||
|
||||
// methodExprWrap returns a function literal that changes method's
|
||||
// first parameter's type to recv, and uses implicits/deref/addr to
|
||||
// select the appropriate receiver parameter to pass to method.
|
||||
func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(method)
|
||||
|
||||
@@ -2631,12 +2672,13 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
r.syntheticTailCall(pos, fn, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, false, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, false, captured, addBody)
|
||||
}
|
||||
|
||||
// syntheticClosure constructs a synthetic function literal for
|
||||
// currying dictionary arguments. pos is the position used for the
|
||||
// closure. typ is the function literal's signature type.
|
||||
// currying dictionary arguments. origPos is the position used for the
|
||||
// closure, which must be a non-inlined position. typ is the function
|
||||
// literal's signature type.
|
||||
//
|
||||
// captures is a list of expressions that need to be evaluated at the
|
||||
// point of function literal evaluation and captured by the function
|
||||
@@ -2647,7 +2689,7 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
// list of captured values passed back has the captured variables for
|
||||
// use within the function literal, corresponding to the expressions
|
||||
// in captures.
|
||||
func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
// isSafe reports whether n is an expression that we can safely
|
||||
// defer to evaluating inside the closure instead, to avoid storing
|
||||
// them into the closure.
|
||||
@@ -2664,9 +2706,15 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
return false
|
||||
}
|
||||
|
||||
fn := ir.NewClosureFunc(pos, r.curfn != nil)
|
||||
// The ODCLFUNC and its body need to use the original position, but
|
||||
// the OCLOSURE node and any Init statements should use the inlined
|
||||
// position instead. See also the explanation in reader.funcLit.
|
||||
inlPos := r.inlPos(origPos)
|
||||
|
||||
fn := ir.NewClosureFunc(origPos, r.curfn != nil)
|
||||
fn.SetWrapper(true)
|
||||
clo := fn.OClosure
|
||||
clo.SetPos(inlPos)
|
||||
ir.NameClosure(clo, r.curfn)
|
||||
|
||||
setType(fn.Nname, typ)
|
||||
@@ -2679,13 +2727,13 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
continue // skip capture; can reference directly
|
||||
}
|
||||
|
||||
tmp := r.tempCopy(pos, n, &init)
|
||||
ir.NewClosureVar(pos, fn, tmp)
|
||||
tmp := r.tempCopy(inlPos, n, &init)
|
||||
ir.NewClosureVar(origPos, fn, tmp)
|
||||
|
||||
// We need to nil check interface receivers at the point of method
|
||||
// value evaluation, ugh.
|
||||
if ifaceHack && i == 1 && n.Type().IsInterface() {
|
||||
check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp))
|
||||
check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp))
|
||||
init.Append(typecheck.Stmt(check))
|
||||
}
|
||||
}
|
||||
@@ -2703,7 +2751,7 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
}
|
||||
assert(next == len(r.closureVars))
|
||||
|
||||
addBody(pos, r, captured)
|
||||
addBody(origPos, r, captured)
|
||||
}}
|
||||
bodyReader[fn] = pri
|
||||
pri.funcBody(fn)
|
||||
|
||||
@@ -140,9 +140,30 @@ func New(profileFile string) *Profile {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(profile.Sample) == 0 {
|
||||
// We accept empty profiles, but there is nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
valueIndex := -1
|
||||
for i, s := range profile.SampleType {
|
||||
// Samples count is the raw data collected, and CPU nanoseconds is just
|
||||
// a scaled version of it, so either one we can find is fine.
|
||||
if (s.Type == "samples" && s.Unit == "count") ||
|
||||
(s.Type == "cpu" && s.Unit == "nanoseconds") {
|
||||
valueIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valueIndex == -1 {
|
||||
log.Fatal("failed to find CPU samples count or CPU nanoseconds value-types in profile.")
|
||||
return nil
|
||||
}
|
||||
|
||||
g := newGraph(profile, &Options{
|
||||
CallTree: false,
|
||||
SampleValue: func(v []int64) int64 { return v[1] },
|
||||
SampleValue: func(v []int64) int64 { return v[valueIndex] },
|
||||
})
|
||||
|
||||
p := &Profile{
|
||||
|
||||
@@ -856,9 +856,6 @@ func prove(f *Func) {
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
||||
case OpOr64, OpOr32, OpOr16, OpOr8:
|
||||
ft.update(b, v, v.Args[1], unsigned, gt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, gt|eq)
|
||||
case OpPhi:
|
||||
// Determine the min and max value of OpPhi composed entirely of integer constants.
|
||||
//
|
||||
|
||||
@@ -615,6 +615,9 @@ func (s *Schedule) staticAssignInlinedCall(l *ir.Name, loff int64, call *ir.Inli
|
||||
// Build tree with args substituted for params and try it.
|
||||
args := make(map[*ir.Name]ir.Node)
|
||||
for i, v := range as2init.Lhs {
|
||||
if ir.IsBlank(v) {
|
||||
continue
|
||||
}
|
||||
args[v.(*ir.Name)] = as2init.Rhs[i]
|
||||
}
|
||||
r, ok := subst(as2body.Rhs[0], args)
|
||||
@@ -838,7 +841,7 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
|
||||
return x
|
||||
}
|
||||
x = ir.Copy(x)
|
||||
ir.EditChildren(x, edit)
|
||||
ir.EditChildrenWithHidden(x, edit)
|
||||
if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
|
||||
// A conversion of variable or expression involving variables
|
||||
// may become a conversion of constant after inlining the parameters
|
||||
|
||||
@@ -7,6 +7,7 @@ package test
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"internal/profile"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
@@ -213,6 +214,73 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
|
||||
testPGOIntendedInlining(t, dir)
|
||||
}
|
||||
|
||||
// TestPGOSingleIndex tests that the sample index can not be 1 and compilation
|
||||
// will not fail. All it should care about is that the sample type is either
|
||||
// CPU nanoseconds or samples count, whichever it finds first.
|
||||
func TestPGOSingleIndex(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
originalIndex int
|
||||
}{{
|
||||
// The `testdata/pgo/inline/inline_hot.pprof` file is a standard CPU
|
||||
// profile as the runtime would generate. The 0 index contains the
|
||||
// value-type samples and value-unit count. The 1 index contains the
|
||||
// value-type cpu and value-unit nanoseconds. These tests ensure that
|
||||
// the compiler can work with profiles that only have a single index,
|
||||
// but are either samples count or CPU nanoseconds.
|
||||
originalIndex: 0,
|
||||
}, {
|
||||
originalIndex: 1,
|
||||
}} {
|
||||
t.Run(fmt.Sprintf("originalIndex=%d", tc.originalIndex), func(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata/pgo/inline")
|
||||
|
||||
// Copy the module to a scratch location so we can add a go.mod.
|
||||
dir := t.TempDir()
|
||||
|
||||
originalPprofFile, err := os.Open(filepath.Join(srcDir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error opening inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer originalPprofFile.Close()
|
||||
|
||||
p, err := profile.Parse(originalPprofFile)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
// Move the samples count value-type to the 0 index.
|
||||
p.SampleType = []*profile.ValueType{p.SampleType[tc.originalIndex]}
|
||||
|
||||
// Ensure we only have a single set of sample values.
|
||||
for _, s := range p.Sample {
|
||||
s.Value = []int64{s.Value[tc.originalIndex]}
|
||||
}
|
||||
|
||||
modifiedPprofFile, err := os.Create(filepath.Join(dir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer modifiedPprofFile.Close()
|
||||
|
||||
if err := p.Write(modifiedPprofFile); err != nil {
|
||||
t.Fatalf("error writing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s: %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
testPGOIntendedInlining(t, dir)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -34,10 +34,7 @@ func roundFloat(v constant.Value, sz int64) constant.Value {
|
||||
// truncate float literal fv to 32-bit or 64-bit precision
|
||||
// according to type; return truncated value.
|
||||
func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -48,10 +45,7 @@ func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
// precision, according to type; return truncated value. In case of
|
||||
// overflow, calls Errorf but does not truncate the input value.
|
||||
func trunccmplxlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -251,7 +245,6 @@ func convertVal(v constant.Value, t *types.Type, explicit bool) constant.Value {
|
||||
switch {
|
||||
case t.IsInteger():
|
||||
v = toint(v)
|
||||
overflow(v, t)
|
||||
return v
|
||||
case t.IsFloat():
|
||||
v = toflt(v)
|
||||
@@ -273,9 +266,6 @@ func tocplx(v constant.Value) constant.Value {
|
||||
|
||||
func toflt(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to real", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -284,9 +274,6 @@ func toflt(v constant.Value) constant.Value {
|
||||
|
||||
func toint(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to integer", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -321,25 +308,6 @@ func toint(v constant.Value) constant.Value {
|
||||
return constant.MakeInt64(1)
|
||||
}
|
||||
|
||||
// overflow reports whether constant value v is too large
|
||||
// to represent with type t, and emits an error message if so.
|
||||
func overflow(v constant.Value, t *types.Type) bool {
|
||||
// v has already been converted
|
||||
// to appropriate form for t.
|
||||
if t.IsUntyped() {
|
||||
return false
|
||||
}
|
||||
if v.Kind() == constant.Int && constant.BitLen(v) > ir.ConstPrec {
|
||||
base.Errorf("integer too large")
|
||||
return true
|
||||
}
|
||||
if ir.ConstOverflow(v, t) {
|
||||
base.Errorf("constant %v overflows %v", types.FmtConst(v, false), t)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tostr(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Int {
|
||||
r := unicode.ReplacementChar
|
||||
|
||||
@@ -288,6 +288,7 @@ func (d *dstate) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) {
|
||||
}
|
||||
fmt.Printf("\nFunc: %s\n", fd.Funcname)
|
||||
fmt.Printf("Srcfile: %s\n", fd.Srcfile)
|
||||
fmt.Printf("Literal: %v\n", fd.Lit)
|
||||
}
|
||||
for i := 0; i < len(fd.Units); i++ {
|
||||
u := fd.Units[i]
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.3.0
|
||||
golang.org/x/term v0.2.0
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe
|
||||
)
|
||||
|
||||
require github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 // indirect
|
||||
|
||||
@@ -12,5 +12,5 @@ golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674 h1:Lv0Y+JVwLQF2YThz8ImE7rP2FSv/IzV9lS2k7bvua6U=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe h1:1B2tjdkEp2f885xTfSsY+7mi5fNZHRxWciDl8Hz3EXg=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
|
||||
@@ -404,18 +404,6 @@ var codeRepoTests = []codeRepoTest{
|
||||
zipSum: "h1:YJYZRsM9BHFTlVr8YADjT0cJH8uFIDtoc5NLiVqZEx8=",
|
||||
zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
rev: "latest",
|
||||
version: "v2.0.0-20170531160350-a96e63847dc3",
|
||||
name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
|
||||
short: "a96e63847dc3",
|
||||
time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
|
||||
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
|
||||
zipSum: "h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI=",
|
||||
zipFileHash: "b5de0da7bbbec76709eef1ac71b6c9ff423b9fbf3bb97b56743450d4937b06d5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
@@ -818,11 +806,6 @@ var codeRepoVersionsTests = []struct {
|
||||
path: "swtch.com/testmod",
|
||||
versions: []string{"v1.0.0", "v1.1.1"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
versions: []string{"v2.0.0"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/odd-tags.git",
|
||||
|
||||
@@ -432,21 +432,37 @@ func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd {
|
||||
}
|
||||
|
||||
func startCommand(s *State, name, path string, args []string, cancel func(*exec.Cmd) error, waitDelay time.Duration) (WaitFunc, error) {
|
||||
var stdoutBuf, stderrBuf strings.Builder
|
||||
cmd := exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdoutBuf, stderrBuf strings.Builder
|
||||
)
|
||||
for {
|
||||
cmd = exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
err := cmd.Start()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if isETXTBSY(err) {
|
||||
// If the script (or its host process) just wrote the executable we're
|
||||
// trying to run, a fork+exec in another thread may be holding open the FD
|
||||
// that we used to write the executable (see https://go.dev/issue/22315).
|
||||
// Since the descriptor should have CLOEXEC set, the problem should
|
||||
// resolve as soon as the forked child reaches its exec call.
|
||||
// Keep retrying until that happens.
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
wait := func(s *State) (stdout, stderr string, err error) {
|
||||
|
||||
11
src/cmd/go/internal/script/cmds_other.go
Normal file
11
src/cmd/go/internal/script/cmds_other.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
//go:build !(unix || windows)
|
||||
|
||||
package script
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return false
|
||||
}
|
||||
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
//go:build unix || windows
|
||||
|
||||
package script
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return errors.Is(err, syscall.ETXTBSY)
|
||||
}
|
||||
@@ -66,6 +66,7 @@ var passAnalyzersToVet = map[string]bool{
|
||||
"structtag": true,
|
||||
"testinggoroutine": true,
|
||||
"tests": true,
|
||||
"timeformat": true,
|
||||
"unmarshal": true,
|
||||
"unreachable": true,
|
||||
"unsafeptr": true,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"cmd/go/internal/test/internal/genflags"
|
||||
"flag"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg.SetGOROOT(testenv.GOROOT(nil), false)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
@@ -48,6 +50,8 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVetAnalyzersSetIsCorrect(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // runs 'go tool vet -flags'
|
||||
|
||||
vetAns, err := genflags.VetAnalyzers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -75,7 +75,7 @@ func testFlags() []string {
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker":
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker", "gocoverdir":
|
||||
// These flags are only for use by cmd/go.
|
||||
default:
|
||||
names = append(names, name)
|
||||
|
||||
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# This test checks that external linking with --gc-sections does not strip version information.
|
||||
|
||||
[short] skip
|
||||
[!cgo] skip
|
||||
[GOOS:aix] skip # no --gc-sections
|
||||
[GOOS:darwin] skip # no --gc-sections
|
||||
|
||||
go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections'
|
||||
go version hello$GOEXE
|
||||
! stdout 'not a Go executable'
|
||||
! stderr 'not a Go executable'
|
||||
|
||||
-- go.mod --
|
||||
module hello
|
||||
-- hello.go --
|
||||
package main
|
||||
|
||||
/*
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println("hello")
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (r *MReader) Read(p []byte) (int, error) {
|
||||
r.off += int64(amt)
|
||||
return amt, nil
|
||||
}
|
||||
return r.rdr.Read(p)
|
||||
return io.ReadFull(r.rdr, p)
|
||||
}
|
||||
|
||||
func (r *MReader) ReadByte() (byte, error) {
|
||||
|
||||
98
src/cmd/internal/cov/read_test.go
Normal file
98
src/cmd/internal/cov/read_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2022 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 cov_test
|
||||
|
||||
import (
|
||||
"cmd/internal/cov"
|
||||
"fmt"
|
||||
"internal/coverage"
|
||||
"internal/coverage/decodecounter"
|
||||
"internal/coverage/decodemeta"
|
||||
"internal/coverage/pods"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// visitor implements the CovDataVisitor interface in a very stripped
|
||||
// down way, just keeps track of interesting events.
|
||||
type visitor struct {
|
||||
metaFileCount int
|
||||
counterFileCount int
|
||||
funcCounterData int
|
||||
metaFuncCount int
|
||||
}
|
||||
|
||||
func (v *visitor) BeginPod(p pods.Pod) {}
|
||||
func (v *visitor) EndPod(p pods.Pod) {}
|
||||
func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) {
|
||||
v.metaFileCount++
|
||||
}
|
||||
func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {
|
||||
v.counterFileCount++
|
||||
}
|
||||
func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {}
|
||||
func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ }
|
||||
func (v *visitor) EndCounters() {}
|
||||
func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ }
|
||||
func (v *visitor) Finish() {}
|
||||
|
||||
func TestIssue58411(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// Build a tiny test program with -cover. Smallness is important;
|
||||
// it is one of the factors that triggers issue 58411.
|
||||
d := t.TempDir()
|
||||
exepath := filepath.Join(d, "small.exe")
|
||||
path := filepath.Join("testdata", "small.go")
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build",
|
||||
"-o", exepath, "-cover", path)
|
||||
b, err := cmd.CombinedOutput()
|
||||
if len(b) != 0 {
|
||||
t.Logf("## build output:\n%s", b)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
// Run to produce coverage data. Note the large argument; we need a large
|
||||
// argument (more than 4k) to trigger the bug, but the overall file
|
||||
// has to remain small (since large files will be read with mmap).
|
||||
covdir := filepath.Join(d, "covdata")
|
||||
if err = os.Mkdir(covdir, 0777); err != nil {
|
||||
t.Fatalf("creating covdir: %v", err)
|
||||
}
|
||||
large := fmt.Sprintf("%07999d", 0)
|
||||
cmd = testenv.Command(t, exepath, "1", "2", "3", large)
|
||||
cmd.Dir = covdir
|
||||
cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir)
|
||||
b, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("## run output:\n%s", b)
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
vis := &visitor{}
|
||||
|
||||
// Read resulting coverage data. Without the fix, this would
|
||||
// yield a "short read" error.
|
||||
const verbosityLevel = 0
|
||||
const flags = 0
|
||||
cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil)
|
||||
err = cdr.Visit()
|
||||
if err != nil {
|
||||
t.Fatalf("visit failed: %v", err)
|
||||
}
|
||||
|
||||
// make sure we saw a few things just for grins
|
||||
const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}"
|
||||
got := fmt.Sprintf("%+v", *vis)
|
||||
if want != got {
|
||||
t.Errorf("visitor contents: want %v got %v\n", want, got)
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,7 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("unable to open meta-file %s", p.MetaFile)
|
||||
}
|
||||
defer f.Close()
|
||||
br := bio.NewReader(f)
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
@@ -209,6 +210,9 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("opening counter data file %s: %s", cdf, err)
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
f.Close()
|
||||
}(cf)
|
||||
var mr *MReader
|
||||
mr, err = NewMreader(cf)
|
||||
if err != nil {
|
||||
|
||||
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
println(len(os.Args))
|
||||
}
|
||||
@@ -396,9 +396,26 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
|
||||
// in dependency order.
|
||||
if ldr.SymValue(rs) != 0 {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
// Workaround for issue #58425: it appears that the
|
||||
// external linker doesn't always take into account the
|
||||
// relocation addend when doing reachability checks. This
|
||||
// means that if you have a call from function XYZ at
|
||||
// offset 8 to runtime.duffzero with addend 800 (for
|
||||
// example), where the distance between the start of XYZ
|
||||
// and the start of runtime.duffzero is just over the
|
||||
// limit (by 100 bytes, say), you can get "relocation
|
||||
// doesn't fit" errors from the external linker. To deal
|
||||
// with this, ignore the addend when performing the
|
||||
// distance calculation (this assumes that we're only
|
||||
// handling backward jumps; ideally we might want to check
|
||||
// both with and without the addend).
|
||||
if ctxt.IsExternal() {
|
||||
t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
} else {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
}
|
||||
}
|
||||
if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
// direct call too far, need to insert trampoline.
|
||||
|
||||
@@ -1669,6 +1669,9 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) {
|
||||
func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section {
|
||||
ldr := state.ctxt.loader
|
||||
sname := ldr.SymName(s)
|
||||
if strings.HasPrefix(sname, "go:") {
|
||||
sname = ".go." + sname[len("go:"):]
|
||||
}
|
||||
sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
|
||||
sect.Align = symalign(ldr, s)
|
||||
state.datsize = Rnd(state.datsize, int64(sect.Align))
|
||||
@@ -2254,7 +2257,7 @@ func (ctxt *Link) buildinfo() {
|
||||
// Write the buildinfo symbol, which go version looks for.
|
||||
// The code reading this data is in package debug/buildinfo.
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(".go.buildinfo", 0)
|
||||
s := ldr.CreateSymForUpdate("go:buildinfo", 0)
|
||||
s.SetType(sym.SBUILDINFO)
|
||||
s.SetAlign(16)
|
||||
// The \xff is invalid UTF-8, meant to make it less likely
|
||||
@@ -2276,6 +2279,14 @@ func (ctxt *Link) buildinfo() {
|
||||
}
|
||||
s.SetData(data)
|
||||
s.SetSize(int64(len(data)))
|
||||
|
||||
// Add reference to go:buildinfo from the rodata section,
|
||||
// so that external linking with -Wl,--gc-sections does not
|
||||
// delete the build info.
|
||||
sr := ldr.CreateSymForUpdate("go:buildinfo.ref", 0)
|
||||
sr.SetType(sym.SRODATA)
|
||||
sr.SetAlign(int32(ctxt.Arch.PtrSize))
|
||||
sr.AddAddr(ctxt.Arch, s.Sym())
|
||||
}
|
||||
|
||||
// appendString appends s to data, prefixed by its varint-encoded length.
|
||||
|
||||
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
@@ -303,6 +303,11 @@ func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(call.Args) != 2 {
|
||||
// Ignore calls such as t.Run(fn()).
|
||||
return nil
|
||||
}
|
||||
|
||||
lit, _ := call.Args[1].(*ast.FuncLit)
|
||||
if lit == nil {
|
||||
return nil
|
||||
|
||||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
@@ -910,7 +910,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
|
||||
if reason != "" {
|
||||
details = " (" + reason + ")"
|
||||
}
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s, see also https://pkg.go.dev/fmt#hdr-Printing", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
return false
|
||||
}
|
||||
if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) {
|
||||
|
||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
@@ -46,7 +46,7 @@ golang.org/x/sys/windows
|
||||
# golang.org/x/term v0.2.0
|
||||
## explicit; go 1.17
|
||||
golang.org/x/term
|
||||
# golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674
|
||||
# golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe
|
||||
## explicit; go 1.18
|
||||
golang.org/x/tools/cover
|
||||
golang.org/x/tools/go/analysis
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"crypto"
|
||||
"crypto/internal/boring"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
@@ -109,7 +110,8 @@ type PrivateKey struct {
|
||||
publicKeyOnce sync.Once
|
||||
}
|
||||
|
||||
// ECDH performs a ECDH exchange and returns the shared secret.
|
||||
// ECDH performs a ECDH exchange and returns the shared secret. The PrivateKey
|
||||
// and PublicKey must use the same curve.
|
||||
//
|
||||
// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
|
||||
// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
|
||||
@@ -118,6 +120,9 @@ type PrivateKey struct {
|
||||
// For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
|
||||
// the result is the all-zero value, ECDH returns an error.
|
||||
func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
|
||||
if k.curve != remote.curve {
|
||||
return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
|
||||
}
|
||||
return k.curve.ecdh(k, remote)
|
||||
}
|
||||
|
||||
|
||||
@@ -487,3 +487,39 @@ func TestLinker(t *testing.T) {
|
||||
t.Error("no P384 symbols found in program using ecdh.P384, test is broken")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMismatchedCurves(t *testing.T) {
|
||||
curves := []struct {
|
||||
name string
|
||||
curve ecdh.Curve
|
||||
}{
|
||||
{"P256", ecdh.P256()},
|
||||
{"P384", ecdh.P384()},
|
||||
{"P521", ecdh.P521()},
|
||||
{"X25519", ecdh.X25519()},
|
||||
}
|
||||
|
||||
for _, privCurve := range curves {
|
||||
priv, err := privCurve.curve.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test key: %s", err)
|
||||
}
|
||||
|
||||
for _, pubCurve := range curves {
|
||||
if privCurve == pubCurve {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%s/%s", privCurve.name, pubCurve.name), func(t *testing.T) {
|
||||
pub, err := pubCurve.curve.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test key: %s", err)
|
||||
}
|
||||
expected := "crypto/ecdh: private key and public key curves do not match"
|
||||
_, err = priv.ECDH(pub.PublicKey())
|
||||
if err.Error() != expected {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expected, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ func main() {
|
||||
ConstraintExpr("amd64,gc,!purego")
|
||||
|
||||
Implement("montgomeryLoop")
|
||||
Pragma("noescape")
|
||||
|
||||
size := Load(Param("d").Len(), GP64())
|
||||
d := Mem{Base: Load(Param("d").Base(), GP64())}
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
|
||||
package bigmod
|
||||
|
||||
//go:noescape
|
||||
func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/internal/nistec"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
@@ -165,6 +166,86 @@ func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMult(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
G := newPoint().SetGenerator()
|
||||
checkScalar := func(t *testing.T, scalar []byte) {
|
||||
p1, err := newPoint().ScalarBaseMult(scalar)
|
||||
fatalIfErr(t, err)
|
||||
p2, err := newPoint().ScalarMult(G, scalar)
|
||||
fatalIfErr(t, err)
|
||||
if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
|
||||
t.Error("[k]G != ScalarBaseMult(k)")
|
||||
}
|
||||
|
||||
d := new(big.Int).SetBytes(scalar)
|
||||
d.Sub(c.Params().N, d)
|
||||
d.Mod(d, c.Params().N)
|
||||
g1, err := newPoint().ScalarBaseMult(d.FillBytes(make([]byte, len(scalar))))
|
||||
fatalIfErr(t, err)
|
||||
g1.Add(g1, p1)
|
||||
if !bytes.Equal(g1.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("[N - k]G + [k]G != ∞")
|
||||
}
|
||||
}
|
||||
|
||||
byteLen := len(c.Params().N.Bytes())
|
||||
bitLen := c.Params().N.BitLen()
|
||||
t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) })
|
||||
t.Run("1", func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
t.Run("N-1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("N", func(t *testing.T) { checkScalar(t, c.Params().N.Bytes()) })
|
||||
t.Run("N+1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("all1s", func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen))
|
||||
s.Sub(s, big.NewInt(1))
|
||||
checkScalar(t, s.Bytes())
|
||||
})
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
for i := 0; i < bitLen; i++ {
|
||||
t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(i))
|
||||
checkScalar(t, s.FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
// Test N+1...N+32 since they risk overlapping with precomputed table values
|
||||
// in the final additions.
|
||||
for i := int64(2); i <= 32; i++ {
|
||||
t.Run(fmt.Sprintf("N+%d", i), func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(i)).Bytes())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fatalIfErr(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarMult(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28)
|
||||
|
||||
@@ -364,6 +364,21 @@ func p256PointDoubleAsm(res, in *P256Point)
|
||||
// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order.
|
||||
type p256OrdElement [4]uint64
|
||||
|
||||
// p256OrdReduce ensures s is in the range [0, ord(G)-1].
|
||||
func p256OrdReduce(s *p256OrdElement) {
|
||||
// Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G),
|
||||
// keeping the result if it doesn't underflow.
|
||||
t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
|
||||
t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
|
||||
t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
|
||||
t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
|
||||
tMask := b - 1 // zero if subtraction underflowed
|
||||
s[0] ^= (t0 ^ s[0]) & tMask
|
||||
s[1] ^= (t1 ^ s[1]) & tMask
|
||||
s[2] ^= (t2 ^ s[2]) & tMask
|
||||
s[3] ^= (t3 ^ s[3]) & tMask
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P256Point) Add(r1, r2 *P256Point) *P256Point {
|
||||
var sum, double P256Point
|
||||
@@ -393,6 +408,7 @@ func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.p256BaseMult(scalarReversed)
|
||||
return r, nil
|
||||
@@ -407,6 +423,7 @@ func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error)
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.Set(q).p256ScalarMult(scalarReversed)
|
||||
return r, nil
|
||||
|
||||
@@ -25,6 +25,7 @@ func P256OrdInverse(k []byte) ([]byte, error) {
|
||||
|
||||
x := new(p256OrdElement)
|
||||
p256OrdBigToLittle(x, (*[32]byte)(k))
|
||||
p256OrdReduce(x)
|
||||
|
||||
// Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem.
|
||||
//
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/internal/boring"
|
||||
"crypto/rand"
|
||||
. "crypto/rsa"
|
||||
"crypto/sha1"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -129,6 +131,31 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocations(t *testing.T) {
|
||||
if boring.Enabled {
|
||||
t.Skip("skipping allocations test with BoringCrypto")
|
||||
}
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
|
||||
m := []byte("Hello Gophers")
|
||||
c, err := EncryptPKCS1v15(rand.Reader, &test2048Key.PublicKey, m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if allocs := testing.AllocsPerRun(100, func() {
|
||||
p, err := DecryptPKCS1v15(nil, test2048Key, c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(p, m) {
|
||||
t.Fatalf("unexpected output: %q", p)
|
||||
}
|
||||
}); allocs > 10 {
|
||||
t.Errorf("expected less than 10 allocations, got %0.1f", allocs)
|
||||
}
|
||||
}
|
||||
|
||||
var allFlag = flag.Bool("all", false, "test all key sizes up to 2048")
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestBoringClientHello(t *testing.T) {
|
||||
|
||||
go Client(c, clientConfig).Handshake()
|
||||
srv := Server(s, testConfig)
|
||||
msg, err := srv.readHandshake()
|
||||
msg, err := srv.readHandshake(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1394,7 +1394,7 @@ func (c *Certificate) leaf() (*x509.Certificate, error) {
|
||||
}
|
||||
|
||||
type handshakeMessage interface {
|
||||
marshal() []byte
|
||||
marshal() ([]byte, error)
|
||||
unmarshal([]byte) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -1004,18 +1004,37 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// writeRecord writes a TLS record with the given type and payload to the
|
||||
// connection and updates the record layer state.
|
||||
func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
|
||||
// writeHandshakeRecord writes a handshake message to the connection and updates
|
||||
// the record layer state. If transcript is non-nil the marshalled message is
|
||||
// written to it.
|
||||
func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
|
||||
return c.writeRecordLocked(typ, data)
|
||||
data, err := msg.marshal()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if transcript != nil {
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
return c.writeRecordLocked(recordTypeHandshake, data)
|
||||
}
|
||||
|
||||
// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
|
||||
// updates the record layer state.
|
||||
func (c *Conn) writeChangeCipherRecord() error {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
_, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
}
|
||||
|
||||
// readHandshake reads the next handshake message from
|
||||
// the record layer.
|
||||
func (c *Conn) readHandshake() (any, error) {
|
||||
// the record layer. If transcript is non-nil, the message
|
||||
// is written to the passed transcriptHash.
|
||||
func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
|
||||
for c.hand.Len() < 4 {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return nil, err
|
||||
@@ -1094,6 +1113,11 @@ func (c *Conn) readHandshake() (any, error) {
|
||||
if !m.unmarshal(data) {
|
||||
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
|
||||
if transcript != nil {
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -1169,7 +1193,7 @@ func (c *Conn) handleRenegotiation() error {
|
||||
return errors.New("tls: internal error: unexpected renegotiation")
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1215,7 +1239,7 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
return c.handleRenegotiation()
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1251,7 +1275,11 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
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)
|
||||
|
||||
@@ -162,7 +162,10 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}
|
||||
c.serverName = hello.serverName
|
||||
|
||||
cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
|
||||
cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cacheKey != "" && session != nil {
|
||||
defer func() {
|
||||
// If we got a handshake failure when resuming a session, throw away
|
||||
@@ -177,11 +180,12 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}()
|
||||
}
|
||||
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
|
||||
if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// serverHelloMsg is not included in the transcript
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -246,9 +250,9 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
session *ClientSessionState, earlySecret, binderKey []byte) {
|
||||
session *ClientSessionState, earlySecret, binderKey []byte, err error) {
|
||||
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
|
||||
return "", nil, nil, nil
|
||||
return "", nil, nil, nil, nil
|
||||
}
|
||||
|
||||
hello.ticketSupported = true
|
||||
@@ -263,14 +267,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// renegotiation is primarily used to allow a client to send a client
|
||||
// certificate, which would be skipped if session resumption occurred.
|
||||
if c.handshakes != 0 {
|
||||
return "", nil, nil, nil
|
||||
return "", nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Try to resume a previously negotiated TLS session, if available.
|
||||
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
session, ok := c.config.ClientSessionCache.Get(cacheKey)
|
||||
if !ok || session == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Check that version used for the previous session is still valid.
|
||||
@@ -282,7 +286,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
}
|
||||
}
|
||||
if !versOk {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Check that the cached server certificate is not expired, and that it's
|
||||
@@ -291,16 +295,16 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
if !c.config.InsecureSkipVerify {
|
||||
if len(session.verifiedChains) == 0 {
|
||||
// The original connection had InsecureSkipVerify, while this doesn't.
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
serverCert := session.serverCertificates[0]
|
||||
if c.config.time().After(serverCert.NotAfter) {
|
||||
// Expired certificate, delete the entry.
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +312,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// In TLS 1.2 the cipher suite must match the resumed session. Ensure we
|
||||
// are still offering it.
|
||||
if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
hello.sessionTicket = session.sessionTicket
|
||||
@@ -318,14 +322,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// Check that the session ticket is not expired.
|
||||
if c.config.time().After(session.useBy) {
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// In TLS 1.3 the KDF hash must match the resumed session. Ensure we
|
||||
// offer at least one cipher suite with that hash.
|
||||
cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
|
||||
if cipherSuite == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
cipherSuiteOk := false
|
||||
for _, offeredID := range hello.cipherSuites {
|
||||
@@ -336,7 +340,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
}
|
||||
}
|
||||
if !cipherSuiteOk {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
|
||||
@@ -354,9 +358,15 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
earlySecret = cipherSuite.extract(psk, nil)
|
||||
binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
|
||||
transcript := cipherSuite.hash.New()
|
||||
transcript.Write(hello.marshalWithoutBinders())
|
||||
helloBytes, err := hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
transcript.Write(helloBytes)
|
||||
pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
|
||||
hello.updateBinders(pskBinders)
|
||||
if err := hello.updateBinders(pskBinders); err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -401,8 +411,12 @@ func (hs *clientHandshakeState) handshake() error {
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(hs.hello.marshal())
|
||||
hs.finishedHash.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.buffering = true
|
||||
c.didResume = isResume
|
||||
@@ -473,7 +487,7 @@ func (hs *clientHandshakeState) pickCipherSuite() error {
|
||||
func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -482,9 +496,8 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -502,11 +515,10 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return errors.New("tls: received unexpected CertificateStatus message")
|
||||
}
|
||||
hs.finishedHash.Write(cs.marshal())
|
||||
|
||||
c.ocspResponse = cs.response
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -535,14 +547,13 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
|
||||
skx, ok := msg.(*serverKeyExchangeMsg)
|
||||
if ok {
|
||||
hs.finishedHash.Write(skx.marshal())
|
||||
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
|
||||
if err != nil {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -553,7 +564,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
certReq, ok := msg.(*certificateRequestMsg)
|
||||
if ok {
|
||||
certRequested = true
|
||||
hs.finishedHash.Write(certReq.marshal())
|
||||
|
||||
cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
|
||||
if chainToSend, err = c.getClientCertificate(cri); err != nil {
|
||||
@@ -561,7 +571,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -572,7 +582,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(shd, msg)
|
||||
}
|
||||
hs.finishedHash.Write(shd.marshal())
|
||||
|
||||
// If the server requested a certificate then we have to send a
|
||||
// Certificate message, even if it's empty because we don't have a
|
||||
@@ -580,8 +589,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
if certRequested {
|
||||
certMsg = new(certificateMsg)
|
||||
certMsg.certificates = chainToSend.Certificate
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -592,8 +600,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
if ckx != nil {
|
||||
hs.finishedHash.Write(ckx.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -640,8 +647,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(certVerify.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -776,7 +782,10 @@ func (hs *clientHandshakeState) readFinished(out []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// finishedMsg is included in the transcript, but not until after we
|
||||
// check the client version, since the state before this message was
|
||||
// sent is used during verification.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -792,7 +801,11 @@ func (hs *clientHandshakeState) readFinished(out []byte) error {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: server's Finished message was incorrect")
|
||||
}
|
||||
hs.finishedHash.Write(serverFinished.marshal())
|
||||
|
||||
if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(out, verify)
|
||||
return nil
|
||||
}
|
||||
@@ -803,7 +816,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
}
|
||||
|
||||
c := hs.c
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -812,7 +825,6 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(sessionTicketMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(sessionTicketMsg.marshal())
|
||||
|
||||
hs.session = &ClientSessionState{
|
||||
sessionTicket: sessionTicketMsg.ticket,
|
||||
@@ -832,14 +844,13 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
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)
|
||||
|
||||
@@ -1257,7 +1257,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) {
|
||||
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 TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
|
||||
random: make([]byte, 32),
|
||||
cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
serverHelloBytes := serverHello.marshal()
|
||||
serverHelloBytes := mustMarshal(t, serverHello)
|
||||
|
||||
s.Write([]byte{
|
||||
byte(recordTypeHandshake),
|
||||
|
||||
@@ -62,7 +62,10 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
}
|
||||
|
||||
hs.transcript = hs.suite.hash.New()
|
||||
hs.transcript.Write(hs.hello.marshal())
|
||||
|
||||
if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
@@ -73,7 +76,9 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
}
|
||||
}
|
||||
|
||||
hs.transcript.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.buffering = true
|
||||
if err := hs.processServerHello(); err != nil {
|
||||
@@ -172,8 +177,7 @@ func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
|
||||
@@ -188,7 +192,9 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
hs.transcript.Reset()
|
||||
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
hs.transcript.Write(chHash)
|
||||
hs.transcript.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The only HelloRetryRequest extensions we support are key_share and
|
||||
// cookie, and clients must abort the handshake if the HRR would not result
|
||||
@@ -253,10 +259,18 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
transcript := hs.suite.hash.New()
|
||||
transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
transcript.Write(chHash)
|
||||
transcript.Write(hs.serverHello.marshal())
|
||||
transcript.Write(hs.hello.marshalWithoutBinders())
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
helloBytes, err := hs.hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transcript.Write(helloBytes)
|
||||
pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
|
||||
hs.hello.updateBinders(pskBinders)
|
||||
if err := hs.hello.updateBinders(pskBinders); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Server selected a cipher suite incompatible with the PSK.
|
||||
hs.hello.pskIdentities = nil
|
||||
@@ -264,12 +278,12 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -363,6 +377,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
if !hs.usingPSK {
|
||||
earlySecret = hs.suite.extract(nil, nil)
|
||||
}
|
||||
|
||||
handshakeSecret := hs.suite.extract(sharedKey,
|
||||
hs.suite.deriveSecret(earlySecret, "derived", nil))
|
||||
|
||||
@@ -393,7 +408,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -403,7 +418,6 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
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)
|
||||
@@ -432,18 +446,16 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
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
|
||||
}
|
||||
@@ -458,7 +470,6 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
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
|
||||
@@ -467,7 +478,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
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
|
||||
}
|
||||
@@ -498,7 +512,9 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
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
|
||||
}
|
||||
@@ -506,7 +522,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
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
|
||||
}
|
||||
@@ -523,7 +542,9 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||||
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.
|
||||
|
||||
@@ -572,8 +593,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -610,8 +630,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -625,8 +644,7 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -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() []byte {
|
||||
b.AddBytes(m.compressionMethods)
|
||||
})
|
||||
|
||||
// If extensions aren't present, omit them.
|
||||
var extensionsPresent bool
|
||||
bWithoutExtensions := *b
|
||||
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
if len(m.serverName) > 0 {
|
||||
// RFC 6066, Section 3
|
||||
b.AddUint16(extensionServerName)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8(0) // name_type = host_name
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(m.serverName))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ocspStapling {
|
||||
// RFC 4366, Section 3.6
|
||||
b.AddUint16(extensionStatusRequest)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8(1) // status_type = ocsp
|
||||
b.AddUint16(0) // empty responder_id_list
|
||||
b.AddUint16(0) // empty request_extensions
|
||||
})
|
||||
}
|
||||
if len(m.supportedCurves) > 0 {
|
||||
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
|
||||
b.AddUint16(extensionSupportedCurves)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, curve := range m.supportedCurves {
|
||||
b.AddUint16(uint16(curve))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
// RFC 4492, Section 5.1.2
|
||||
b.AddUint16(extensionSupportedPoints)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ticketSupported {
|
||||
// RFC 5077, Section 3.2
|
||||
b.AddUint16(extensionSessionTicket)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.sessionTicket)
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithms) > 0 {
|
||||
// RFC 5246, Section 7.4.1.4.1
|
||||
b.AddUint16(extensionSignatureAlgorithms)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithms {
|
||||
b.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithmsCert) > 0 {
|
||||
// RFC 8446, Section 4.2.3
|
||||
b.AddUint16(extensionSignatureAlgorithmsCert)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
|
||||
b.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
// RFC 5746, Section 3.2
|
||||
b.AddUint16(extensionRenegotiationInfo)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocols) > 0 {
|
||||
// RFC 7301, Section 3.1
|
||||
b.AddUint16(extensionALPN)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, proto := range m.alpnProtocols {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(proto))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.scts {
|
||||
// RFC 6962, Section 3.3.1
|
||||
b.AddUint16(extensionSCT)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.supportedVersions) > 0 {
|
||||
// RFC 8446, Section 4.2.1
|
||||
b.AddUint16(extensionSupportedVersions)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, vers := range m.supportedVersions {
|
||||
b.AddUint16(vers)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.cookie) > 0 {
|
||||
// RFC 8446, Section 4.2.2
|
||||
b.AddUint16(extensionCookie)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.keyShares) > 0 {
|
||||
// RFC 8446, Section 4.2.8
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, ks := range m.keyShares {
|
||||
b.AddUint16(uint16(ks.group))
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(ks.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.earlyData {
|
||||
// RFC 8446, Section 4.2.10
|
||||
b.AddUint16(extensionEarlyData)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.pskModes) > 0 {
|
||||
// RFC 8446, Section 4.2.9
|
||||
b.AddUint16(extensionPSKModes)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.pskModes)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
|
||||
// RFC 8446, Section 4.2.11
|
||||
b.AddUint16(extensionPreSharedKey)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, psk := range m.pskIdentities {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(psk.label)
|
||||
})
|
||||
b.AddUint32(psk.obfuscatedTicketAge)
|
||||
}
|
||||
})
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, binder := range m.pskBinders {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(binder)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
extensionsPresent = len(b.BytesOrPanic()) > 2
|
||||
})
|
||||
|
||||
if !extensionsPresent {
|
||||
*b = bWithoutExtensions
|
||||
if len(extBytes) > 0 {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(extBytes)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
// marshalWithoutBinders returns the ClientHello through the
|
||||
// PreSharedKeyExtension.identities field, according to RFC 8446, Section
|
||||
// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
|
||||
func (m *clientHelloMsg) marshalWithoutBinders() []byte {
|
||||
func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) {
|
||||
bindersLen := 2 // uint16 length prefix
|
||||
for _, binder := range m.pskBinders {
|
||||
bindersLen += 1 // uint8 length prefix
|
||||
bindersLen += len(binder)
|
||||
}
|
||||
|
||||
fullMessage := m.marshal()
|
||||
return fullMessage[:len(fullMessage)-bindersLen]
|
||||
fullMessage, err := m.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fullMessage[:len(fullMessage)-bindersLen], nil
|
||||
}
|
||||
|
||||
// updateBinders updates the m.pskBinders field, if necessary updating the
|
||||
// cached marshaled representation. The supplied binders must have the same
|
||||
// length as the current m.pskBinders.
|
||||
func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
|
||||
func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error {
|
||||
if len(pskBinders) != len(m.pskBinders) {
|
||||
panic("tls: internal error: pskBinders length mismatch")
|
||||
return errors.New("tls: internal error: pskBinders length mismatch")
|
||||
}
|
||||
for i := range m.pskBinders {
|
||||
if len(pskBinders[i]) != len(m.pskBinders[i]) {
|
||||
panic("tls: internal error: pskBinders length mismatch")
|
||||
return errors.New("tls: internal error: pskBinders length mismatch")
|
||||
}
|
||||
}
|
||||
m.pskBinders = pskBinders
|
||||
if m.raw != nil {
|
||||
lenWithoutBinders := len(m.marshalWithoutBinders())
|
||||
helloBytes, err := m.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lenWithoutBinders := len(helloBytes)
|
||||
b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, binder := range m.pskBinders {
|
||||
@@ -338,9 +345,11 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
|
||||
}
|
||||
})
|
||||
if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
|
||||
panic("tls: internal error: failed to update binders")
|
||||
return errors.New("tls: internal error: failed to update binders")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
@@ -618,9 +627,98 @@ 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
|
||||
@@ -634,104 +732,15 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
b.AddUint16(m.cipherSuite)
|
||||
b.AddUint8(m.compressionMethod)
|
||||
|
||||
// If extensions aren't present, omit them.
|
||||
var extensionsPresent bool
|
||||
bWithoutExtensions := *b
|
||||
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
if m.ocspStapling {
|
||||
b.AddUint16(extensionStatusRequest)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.ticketSupported {
|
||||
b.AddUint16(extensionSessionTicket)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
b.AddUint16(extensionRenegotiationInfo)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocol) > 0 {
|
||||
b.AddUint16(extensionALPN)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(m.alpnProtocol))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.scts) > 0 {
|
||||
b.AddUint16(extensionSCT)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sct := range m.scts {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(sct)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.supportedVersion != 0 {
|
||||
b.AddUint16(extensionSupportedVersions)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(m.supportedVersion)
|
||||
})
|
||||
}
|
||||
if m.serverShare.group != 0 {
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(uint16(m.serverShare.group))
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.serverShare.data)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedIdentityPresent {
|
||||
b.AddUint16(extensionPreSharedKey)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(m.selectedIdentity)
|
||||
})
|
||||
}
|
||||
|
||||
if len(m.cookie) > 0 {
|
||||
b.AddUint16(extensionCookie)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedGroup != 0 {
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(uint16(m.selectedGroup))
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
b.AddUint16(extensionSupportedPoints)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
extensionsPresent = len(b.BytesOrPanic()) > 2
|
||||
})
|
||||
|
||||
if !extensionsPresent {
|
||||
*b = bWithoutExtensions
|
||||
if len(extBytes) > 0 {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(extBytes)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
@@ -855,9 +864,9 @@ 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
|
||||
@@ -877,8 +886,9 @@ func (m *encryptedExtensionsMsg) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
@@ -926,10 +936,10 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
|
||||
type endOfEarlyDataMsg struct{}
|
||||
|
||||
func (m *endOfEarlyDataMsg) marshal() []byte {
|
||||
func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
|
||||
x := make([]byte, 4)
|
||||
x[0] = typeEndOfEarlyData
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
|
||||
@@ -941,9 +951,9 @@ 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
|
||||
@@ -956,8 +966,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 {
|
||||
@@ -989,9 +1000,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
|
||||
@@ -1016,8 +1027,9 @@ func (m *newSessionTicketMsgTLS13) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
|
||||
@@ -1070,9 +1082,9 @@ 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
|
||||
@@ -1131,8 +1143,9 @@ func (m *certificateRequestMsgTLS13) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
|
||||
@@ -1216,9 +1229,9 @@ 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
|
||||
@@ -1227,7 +1240,7 @@ func (m *certificateMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
length := 3 + 3*len(m.certificates) + i
|
||||
x = make([]byte, 4+length)
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeCertificate
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
@@ -1248,7 +1261,7 @@ func (m *certificateMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *certificateMsg) unmarshal(data []byte) bool {
|
||||
@@ -1295,9 +1308,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
|
||||
@@ -1315,8 +1328,9 @@ func (m *certificateMsgTLS13) marshal() []byte {
|
||||
marshalCertificate(b, certificate)
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
|
||||
@@ -1439,9 +1453,9 @@ 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)
|
||||
@@ -1452,7 +1466,7 @@ func (m *serverKeyExchangeMsg) marshal() []byte {
|
||||
copy(x[4:], m.key)
|
||||
|
||||
m.raw = x
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
|
||||
@@ -1469,9 +1483,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
|
||||
@@ -1483,8 +1497,9 @@ func (m *certificateStatusMsg) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateStatusMsg) unmarshal(data []byte) bool {
|
||||
@@ -1503,10 +1518,10 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool {
|
||||
|
||||
type serverHelloDoneMsg struct{}
|
||||
|
||||
func (m *serverHelloDoneMsg) marshal() []byte {
|
||||
func (m *serverHelloDoneMsg) marshal() ([]byte, error) {
|
||||
x := make([]byte, 4)
|
||||
x[0] = typeServerHelloDone
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
|
||||
@@ -1518,9 +1533,9 @@ 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)
|
||||
@@ -1531,7 +1546,7 @@ func (m *clientKeyExchangeMsg) marshal() []byte {
|
||||
copy(x[4:], m.ciphertext)
|
||||
|
||||
m.raw = x
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
|
||||
@@ -1552,9 +1567,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
|
||||
@@ -1563,8 +1578,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 {
|
||||
@@ -1586,9 +1602,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.
|
||||
@@ -1603,7 +1619,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
|
||||
length += 2 + 2*len(m.supportedSignatureAlgorithms)
|
||||
}
|
||||
|
||||
x = make([]byte, 4+length)
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeCertificateRequest
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
@@ -1638,7 +1654,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg) unmarshal(data []byte) bool {
|
||||
@@ -1724,9 +1740,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
|
||||
@@ -1740,8 +1756,9 @@ func (m *certificateVerifyMsg) marshal() (x []byte) {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
|
||||
@@ -1764,15 +1781,15 @@ 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)
|
||||
@@ -1783,7 +1800,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) {
|
||||
|
||||
m.raw = x
|
||||
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
|
||||
@@ -1811,10 +1828,25 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -38,6 +38,15 @@ var tests = []any{
|
||||
&certificateMsgTLS13{},
|
||||
}
|
||||
|
||||
func mustMarshal(t *testing.T, msg handshakeMessage) []byte {
|
||||
t.Helper()
|
||||
b, err := msg.marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
@@ -56,7 +65,7 @@ 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)
|
||||
@@ -409,12 +418,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) {
|
||||
@@ -452,12 +461,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) {
|
||||
|
||||
@@ -128,7 +128,9 @@ func (hs *serverHandshakeState) handshake() error {
|
||||
|
||||
// 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
|
||||
}
|
||||
@@ -462,9 +464,10 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -502,24 +505,23 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -531,8 +533,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -558,15 +559,13 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -576,7 +575,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -589,7 +588,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
|
||||
if err := c.processCertsFromClient(Certificate{
|
||||
Certificate: certMsg.certificates,
|
||||
@@ -600,7 +598,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
pub = c.peerCertificates[0].PublicKey
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -618,7 +616,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
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 {
|
||||
@@ -638,7 +635,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
// 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
|
||||
}
|
||||
@@ -673,7 +673,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
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()
|
||||
@@ -713,7 +715,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||
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
|
||||
}
|
||||
@@ -730,7 +735,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||
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
|
||||
}
|
||||
@@ -764,14 +772,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -781,14 +791,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
|
||||
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, serverConfig *Config, m handshakeMessa
|
||||
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 *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)
|
||||
}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := c.Read(buf)
|
||||
@@ -253,8 +264,10 @@ func TestTLS12OnlyCipherSuites(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
|
||||
@@ -311,8 +324,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
|
||||
@@ -1426,7 +1441,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)
|
||||
|
||||
@@ -306,7 +306,12 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
||||
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)
|
||||
@@ -397,8 +402,7 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
|
||||
@@ -406,7 +410,9 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
|
||||
// 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))})
|
||||
@@ -422,8 +428,7 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -431,7 +436,8 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// clientHelloMsg is not included in the transcript.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -522,9 +528,10 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -567,8 +574,7 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -597,8 +603,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -609,8 +614,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -641,8 +645,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -656,8 +659,7 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -718,7 +720,9 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
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
|
||||
@@ -743,8 +747,12 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
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
|
||||
}
|
||||
@@ -763,7 +771,7 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -788,7 +796,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
// 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
|
||||
}
|
||||
@@ -798,7 +806,6 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.transcript.Write(certMsg.marshal())
|
||||
|
||||
if err := c.processCertsFromClient(certMsg.certificate); err != nil {
|
||||
return err
|
||||
@@ -812,7 +819,10 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -843,7 +853,9 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
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
|
||||
@@ -858,7 +870,8 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/ecdh"
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
@@ -40,8 +41,24 @@ func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []by
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -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() []byte {
|
||||
b.AddBytes(m.resumptionSecret)
|
||||
})
|
||||
marshalCertificate(&b, m.certificate)
|
||||
return b.BytesOrPanic()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (m *sessionStateTLS13) unmarshal(data []byte) bool {
|
||||
|
||||
@@ -28,7 +28,7 @@ type pkcs8 struct {
|
||||
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
|
||||
//
|
||||
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, a ed25519.PrivateKey (not
|
||||
// a pointer), or a *ecdh.PublicKey (for X25519). More types might be supported
|
||||
// a pointer), or a *ecdh.PrivateKey (for X25519). More types might be supported
|
||||
// in the future.
|
||||
//
|
||||
// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
|
||||
|
||||
@@ -25,9 +25,10 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
return nil, err
|
||||
}
|
||||
sc, err := macOS.SecCertificateCreateWithData(c.Raw)
|
||||
if err == nil {
|
||||
macOS.CFArrayAppendValue(certs, sc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
macOS.CFArrayAppendValue(certs, sc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
rootPEMs := []string{
|
||||
geoTrustRoot,
|
||||
gtsRoot,
|
||||
googleLeaf,
|
||||
startComRoot,
|
||||
}
|
||||
|
||||
@@ -43,33 +43,33 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "Valid",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MixedCase",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "WwW.GooGLE.coM",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "HostnameMismatch",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.example.com",
|
||||
|
||||
errorCallback: expectHostnameError("certificate is valid for"),
|
||||
@@ -77,9 +77,9 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "IPMissing",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "1.2.3.4",
|
||||
|
||||
errorCallback: expectHostnameError("doesn't contain any IP SANs"),
|
||||
@@ -87,8 +87,8 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "Expired",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1,
|
||||
dnsName: "www.example.com",
|
||||
|
||||
@@ -97,8 +97,8 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "MissingIntermediate",
|
||||
leaf: googleLeaf,
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
// Skip when using systemVerify, since Windows
|
||||
@@ -109,13 +109,13 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "RootInIntermediates",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{geoTrustRoot, giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsRoot, gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
// CAPI doesn't build the chain with the duplicated GeoTrust
|
||||
// entry so the results don't match.
|
||||
@@ -163,9 +163,9 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "InvalidHash",
|
||||
leaf: googleLeafWithInvalidHash,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
// The specific error message may not occur when using system
|
||||
@@ -230,21 +230,20 @@ var verifyTests = []verifyTest{
|
||||
// Check that SHA-384 intermediates (which are popping up)
|
||||
// work.
|
||||
name: "SHA-384",
|
||||
leaf: moipLeafCert,
|
||||
intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
|
||||
roots: []string{addTrustRoot},
|
||||
currentTime: 1397502195,
|
||||
dnsName: "api.moip.com.br",
|
||||
leaf: trustAsiaLeaf,
|
||||
intermediates: []string{trustAsiaSHA384Intermediate},
|
||||
roots: []string{digicertRoot},
|
||||
currentTime: 1558051200,
|
||||
dnsName: "tm.cn",
|
||||
|
||||
// CryptoAPI can find alternative validation paths.
|
||||
systemLax: true,
|
||||
|
||||
expectedChains: [][]string{
|
||||
{
|
||||
"api.moip.com.br",
|
||||
"COMODO RSA Extended Validation Secure Server CA",
|
||||
"COMODO RSA Certification Authority",
|
||||
"AddTrust External CA Root",
|
||||
"tm.cn",
|
||||
"TrustAsia ECC OV TLS Pro CA",
|
||||
"DigiCert Global Root CA",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -582,106 +581,135 @@ func nameToKey(name *pkix.Name) string {
|
||||
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
|
||||
}
|
||||
|
||||
const geoTrustRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||
const gtsIntermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
|
||||
MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
|
||||
kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
|
||||
lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
|
||||
BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
|
||||
gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
|
||||
tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
|
||||
DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
|
||||
VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
|
||||
CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
|
||||
AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
|
||||
MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
|
||||
A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
|
||||
aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
|
||||
AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
|
||||
cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
|
||||
RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
|
||||
+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
|
||||
PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
|
||||
lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
|
||||
Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
|
||||
z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
|
||||
AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
|
||||
juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
|
||||
1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const giag2Intermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
|
||||
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
|
||||
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
|
||||
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
|
||||
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
|
||||
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
|
||||
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
|
||||
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
|
||||
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
|
||||
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
|
||||
K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
|
||||
KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
|
||||
ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
|
||||
BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
|
||||
/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
|
||||
zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
|
||||
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
|
||||
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
|
||||
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
|
||||
const gtsRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
|
||||
27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
|
||||
Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
|
||||
TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
|
||||
qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
|
||||
szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
|
||||
Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
|
||||
MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
|
||||
wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
|
||||
aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
|
||||
VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
|
||||
AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
||||
FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
|
||||
C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
|
||||
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
|
||||
h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
|
||||
7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
|
||||
ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
|
||||
MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
|
||||
Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
|
||||
6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
|
||||
0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
|
||||
2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
|
||||
bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const googleLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
|
||||
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
|
||||
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
|
||||
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
|
||||
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
|
||||
m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
|
||||
jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
|
||||
fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
|
||||
NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
|
||||
0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
|
||||
dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
|
||||
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
|
||||
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
|
||||
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
|
||||
A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
|
||||
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
|
||||
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
|
||||
RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
|
||||
5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
|
||||
tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
|
||||
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
|
||||
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
|
||||
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
|
||||
MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
|
||||
ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
|
||||
wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
|
||||
55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
|
||||
N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
|
||||
KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
|
||||
WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
|
||||
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
|
||||
f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
|
||||
aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
|
||||
cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
|
||||
b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
|
||||
VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
|
||||
TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
|
||||
4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
|
||||
3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
|
||||
1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
|
||||
hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
|
||||
IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
|
||||
MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
|
||||
VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
|
||||
zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
|
||||
c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
|
||||
i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
|
||||
// algorithm in the certificate contains a nonsense OID.
|
||||
const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
|
||||
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
|
||||
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
|
||||
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
|
||||
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
|
||||
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
|
||||
m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
|
||||
jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
|
||||
fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
|
||||
NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
|
||||
0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
|
||||
dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
|
||||
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
|
||||
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
|
||||
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
|
||||
A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
|
||||
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
|
||||
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
|
||||
RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
|
||||
5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
|
||||
tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
|
||||
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
|
||||
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
|
||||
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
|
||||
MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
|
||||
ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
|
||||
wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
|
||||
55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
|
||||
N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
|
||||
KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
|
||||
WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
|
||||
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
|
||||
f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
|
||||
aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
|
||||
cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
|
||||
b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
|
||||
VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
|
||||
TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
|
||||
4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
|
||||
3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
|
||||
1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
|
||||
hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
|
||||
IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F
|
||||
AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
|
||||
MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
|
||||
VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
|
||||
zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
|
||||
c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
|
||||
i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
|
||||
@@ -1095,136 +1123,81 @@ DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
|
||||
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var moipLeafCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw
|
||||
gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD
|
||||
VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl
|
||||
ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE
|
||||
BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE
|
||||
AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv
|
||||
bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g
|
||||
UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln
|
||||
YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50
|
||||
b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW
|
||||
MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||
DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe
|
||||
s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3
|
||||
UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi
|
||||
+NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw
|
||||
KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI
|
||||
pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME
|
||||
GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj
|
||||
LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
|
||||
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB
|
||||
MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG
|
||||
A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT
|
||||
QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH
|
||||
AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P
|
||||
RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB
|
||||
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku
|
||||
bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+
|
||||
pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC
|
||||
1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6
|
||||
z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW
|
||||
H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ
|
||||
jhuy8PqqZS9OuLilTeLu4a8z2JI=
|
||||
const digicertRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE-----
|
||||
MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
|
||||
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
||||
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
|
||||
MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
|
||||
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
|
||||
Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
|
||||
CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
|
||||
vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
|
||||
xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
|
||||
WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
|
||||
iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
|
||||
BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
|
||||
ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
|
||||
A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
|
||||
b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
|
||||
b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
|
||||
BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
|
||||
L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
|
||||
cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
|
||||
AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
|
||||
jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
|
||||
1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
|
||||
teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
|
||||
fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
|
||||
KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
|
||||
ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
|
||||
XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
|
||||
tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
|
||||
jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
|
||||
pLwltum95OmYdBbxN4SBB7SC
|
||||
const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO
|
||||
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD
|
||||
ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR
|
||||
xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v
|
||||
Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD
|
||||
VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||
MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl
|
||||
cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt
|
||||
Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG
|
||||
SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v
|
||||
Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd
|
||||
j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV
|
||||
OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk
|
||||
GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa
|
||||
SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq
|
||||
PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6
|
||||
rRzZxAYN36q1SX8=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const comodoRSAAuthority = `-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
|
||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
||||
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
||||
eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
|
||||
gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
|
||||
VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
|
||||
AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
|
||||
2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
|
||||
ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
|
||||
4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
|
||||
m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
|
||||
vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
|
||||
8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
|
||||
IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
|
||||
KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
|
||||
GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
|
||||
s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
|
||||
JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
|
||||
AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
|
||||
MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
|
||||
bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
|
||||
Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
|
||||
zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
|
||||
Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
|
||||
Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
|
||||
B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
|
||||
PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
|
||||
pu/xO28QOG8=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const addTrustRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
||||
const trustAsiaLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw
|
||||
CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j
|
||||
LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx
|
||||
NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI
|
||||
DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo
|
||||
5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm
|
||||
nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
|
||||
AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL
|
||||
TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/
|
||||
+LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud
|
||||
EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny
|
||||
bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD
|
||||
VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu
|
||||
ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG
|
||||
AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG
|
||||
OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM
|
||||
U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv
|
||||
AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA
|
||||
RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8
|
||||
leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K
|
||||
tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx
|
||||
x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw
|
||||
CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z
|
||||
0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364
|
||||
EEeHB9vhZAEjQSePAfjR9aAGhXRa
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const selfSigned = `-----BEGIN CERTIFICATE-----
|
||||
@@ -1508,33 +1481,36 @@ ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var unknownAuthorityErrorTests = []struct {
|
||||
name string
|
||||
cert string
|
||||
expected string
|
||||
}{
|
||||
{selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
|
||||
{selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
|
||||
{selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
|
||||
{"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
|
||||
{"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
|
||||
{"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
|
||||
}
|
||||
|
||||
func TestUnknownAuthorityError(t *testing.T) {
|
||||
for i, tt := range unknownAuthorityErrorTests {
|
||||
der, _ := pem.Decode([]byte(tt.cert))
|
||||
if der == nil {
|
||||
t.Errorf("#%d: Unable to decode PEM block", i)
|
||||
}
|
||||
c, err := ParseCertificate(der.Bytes)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: Unable to parse certificate -> %v", i, err)
|
||||
}
|
||||
uae := &UnknownAuthorityError{
|
||||
Cert: c,
|
||||
hintErr: fmt.Errorf("empty"),
|
||||
hintCert: c,
|
||||
}
|
||||
actual := uae.Error()
|
||||
if actual != tt.expected {
|
||||
t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
der, _ := pem.Decode([]byte(tt.cert))
|
||||
if der == nil {
|
||||
t.Fatalf("#%d: Unable to decode PEM block", i)
|
||||
}
|
||||
c, err := ParseCertificate(der.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: Unable to parse certificate -> %v", i, err)
|
||||
}
|
||||
uae := &UnknownAuthorityError{
|
||||
Cert: c,
|
||||
hintErr: fmt.Errorf("empty"),
|
||||
hintCert: c,
|
||||
}
|
||||
actual := uae.Error()
|
||||
if actual != tt.expected {
|
||||
t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1852,10 +1828,10 @@ func TestSystemRootsError(t *testing.T) {
|
||||
opts := VerifyOptions{
|
||||
Intermediates: NewCertPool(),
|
||||
DNSName: "www.google.com",
|
||||
CurrentTime: time.Unix(1395785200, 0),
|
||||
CurrentTime: time.Unix(1677615892, 0),
|
||||
}
|
||||
|
||||
if ok := opts.Intermediates.AppendCertsFromPEM([]byte(giag2Intermediate)); !ok {
|
||||
if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
|
||||
t.Fatalf("failed to parse intermediate")
|
||||
}
|
||||
|
||||
@@ -1881,6 +1857,16 @@ func TestSystemRootsErrorUnwrap(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue51759(t *testing.T) {
|
||||
if runtime.GOOS != "darwin" {
|
||||
t.Skip("only affects darwin")
|
||||
}
|
||||
builder := testenv.Builder()
|
||||
if builder == "" {
|
||||
t.Skip("only run this test on the builders, as we have no reasonable way to gate tests on macOS versions elsewhere")
|
||||
}
|
||||
if builder == "darwin-amd64-10_14" || builder == "darwin-amd64-10_15" {
|
||||
t.Skip("behavior only enforced in macOS 11 and after")
|
||||
}
|
||||
// badCertData contains a cert that we parse as valid
|
||||
// but that macOS SecCertificateCreateWithData rejects.
|
||||
const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r"
|
||||
@@ -1891,9 +1877,10 @@ func TestIssue51759(t *testing.T) {
|
||||
|
||||
t.Run("leaf", func(t *testing.T) {
|
||||
opts := VerifyOptions{}
|
||||
expectedErr := "invalid leaf certificate"
|
||||
_, err = badCert.Verify(opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1907,9 +1894,10 @@ func TestIssue51759(t *testing.T) {
|
||||
Intermediates: NewCertPool(),
|
||||
}
|
||||
opts.Intermediates.AddCert(badCert)
|
||||
expectedErr := "SecCertificateCreateWithData: invalid certificate"
|
||||
_, err = goodCert.Verify(opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d h1:KHU/KRz6+/yWyRHEC24m7T5gou5VSh62duch955ktBY=
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
|
||||
@@ -123,8 +123,6 @@ func (d *CoverageMetaDataDecoder) ReadFunc(fidx uint32, f *coverage.FuncDesc) er
|
||||
})
|
||||
}
|
||||
lit := d.r.ReadULEB128()
|
||||
if lit != 0 {
|
||||
f.Lit = true
|
||||
}
|
||||
f.Lit = lit != 0
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -274,3 +274,58 @@ func TestMetaDataWriterReader(t *testing.T) {
|
||||
inf.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaDataDecodeLitFlagIssue57942(t *testing.T) {
|
||||
|
||||
// Encode a package with a few functions. The funcs alternate
|
||||
// between regular functions and function literals.
|
||||
pp := "foo/bar/pkg"
|
||||
pn := "pkg"
|
||||
mp := "barmod"
|
||||
b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp)
|
||||
if err != nil {
|
||||
t.Fatalf("making builder: %v", err)
|
||||
}
|
||||
const NF = 6
|
||||
const NCU = 1
|
||||
ln := uint32(10)
|
||||
wantfds := []coverage.FuncDesc{}
|
||||
for fi := uint32(0); fi < NF; fi++ {
|
||||
fis := fmt.Sprintf("%d", fi)
|
||||
fd := coverage.FuncDesc{
|
||||
Funcname: "func" + fis,
|
||||
Srcfile: "foo" + fis + ".go",
|
||||
Units: []coverage.CoverableUnit{
|
||||
coverage.CoverableUnit{StLine: ln + 1, StCol: 2, EnLine: ln + 3, EnCol: 4, NxStmts: fi + 2},
|
||||
},
|
||||
Lit: (fi % 2) == 0,
|
||||
}
|
||||
wantfds = append(wantfds, fd)
|
||||
b.AddFunc(fd)
|
||||
}
|
||||
|
||||
// Emit into a writer.
|
||||
drws := &slicewriter.WriteSeeker{}
|
||||
b.Emit(drws)
|
||||
|
||||
// Decode the result.
|
||||
drws.Seek(0, io.SeekStart)
|
||||
dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false)
|
||||
if err != nil {
|
||||
t.Fatalf("making decoder: %v", err)
|
||||
}
|
||||
nf := dec.NumFuncs()
|
||||
if nf != NF {
|
||||
t.Fatalf("decoder number of functions: got %d want %d", nf, NF)
|
||||
}
|
||||
var fn coverage.FuncDesc
|
||||
for i := uint32(0); i < uint32(NF); i++ {
|
||||
if err := dec.ReadFunc(i, &fn); err != nil {
|
||||
t.Fatalf("err reading function %d: %v", i, err)
|
||||
}
|
||||
res := cmpFuncDesc(wantfds[i], fn)
|
||||
if res != "" {
|
||||
t.Errorf("ReadFunc(%d): %s", i, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,18 +41,22 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
|
||||
}
|
||||
n, err := copyFileRange(dst, src, int(max))
|
||||
switch err {
|
||||
case syscall.ENOSYS:
|
||||
// copy_file_range(2) was introduced in Linux 4.5.
|
||||
// Go supports Linux >= 2.6.33, so the system call
|
||||
// may not be present.
|
||||
//
|
||||
// If we see ENOSYS, we have certainly not transferred
|
||||
// any data, so we can tell the caller that we
|
||||
// couldn't handle the transfer and let them fall
|
||||
// back to more generic code.
|
||||
return 0, false, nil
|
||||
case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM:
|
||||
// Prior to Linux 5.3, it was not possible to
|
||||
// copy_file_range across file systems. An attempt
|
||||
// to do this will result in a EXDEV error.
|
||||
//
|
||||
// Even though we have checked the kernel version and blocked
|
||||
// the attempts to copy_file_range(2) when the kernel version
|
||||
// is older than 5.3, but until now the latest kernel (5.19.x)
|
||||
// may still return EXDEV error in certain cases.
|
||||
//
|
||||
// If we see EXDEV, we have not transferred any data,
|
||||
// and we can let the caller fall back to generic code.
|
||||
// copy_file_range across file systems. Similarly to
|
||||
// the ENOSYS case above, if we see EXDEV, we have
|
||||
// not transferred any data, and we can let the caller
|
||||
// fall back to generic code.
|
||||
//
|
||||
// As for EINVAL, that is what we see if, for example,
|
||||
// dst or src refer to a pipe rather than a regular
|
||||
|
||||
@@ -23,7 +23,7 @@ func runtime_pollServerInit()
|
||||
func runtime_pollOpen(fd uintptr) (uintptr, int)
|
||||
func runtime_pollClose(ctx uintptr)
|
||||
func runtime_pollWait(ctx uintptr, mode int) int
|
||||
func runtime_pollWaitCanceled(ctx uintptr, mode int) int
|
||||
func runtime_pollWaitCanceled(ctx uintptr, mode int)
|
||||
func runtime_pollReset(ctx uintptr, mode int) int
|
||||
func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
|
||||
func runtime_pollUnblock(ctx uintptr)
|
||||
|
||||
@@ -7,6 +7,7 @@ package multipart
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"internal/godebug"
|
||||
"io"
|
||||
"math"
|
||||
"net/textproto"
|
||||
@@ -31,25 +32,61 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
|
||||
return r.readForm(maxMemory)
|
||||
}
|
||||
|
||||
var multipartFiles = godebug.New("multipartfiles")
|
||||
|
||||
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
|
||||
combineFiles := multipartFiles.Value() != "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 +100,27 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
}
|
||||
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 +128,45 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
}
|
||||
|
||||
// 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 +174,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
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 +202,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 +217,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 +254,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
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
package multipart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -207,8 +210,8 @@ Content-Disposition: form-data; name="largetext"
|
||||
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 {
|
||||
@@ -223,7 +226,7 @@ Content-Disposition: form-data; name="largetext"
|
||||
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 {
|
||||
@@ -233,3 +236,135 @@ Content-Disposition: form-data; name="largetext"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +128,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
|
||||
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) (*Part, error) {
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
func (p *Part) populateHeaders() error {
|
||||
func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error {
|
||||
r := textproto.NewReader(p.mr.bufReader)
|
||||
header, err := r.ReadMIMEHeader()
|
||||
header, err := readMIMEHeader(r, maxMIMEHeaderSize)
|
||||
if err == nil {
|
||||
p.Header = header
|
||||
}
|
||||
// TODO: Add a distinguishable error to net/textproto.
|
||||
if err != nil && err.Error() == "message too large" {
|
||||
err = ErrMessageTooLarge
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -311,6 +315,7 @@ func (p *Part) Close() error {
|
||||
// isn't supported.
|
||||
type Reader struct {
|
||||
bufReader *bufio.Reader
|
||||
tempDir string // used in tests
|
||||
|
||||
currentPart *Part
|
||||
partsRead int
|
||||
@@ -321,6 +326,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.
|
||||
//
|
||||
@@ -328,7 +337,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.
|
||||
@@ -337,10 +346,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)
|
||||
return r.nextPart(true, maxMIMEHeaderSize)
|
||||
}
|
||||
|
||||
func (r *Reader) nextPart(rawPart bool) (*Part, error) {
|
||||
func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
|
||||
if r.currentPart != nil {
|
||||
r.currentPart.Close()
|
||||
}
|
||||
@@ -365,7 +374,7 @@ func (r *Reader) nextPart(rawPart bool) (*Part, error) {
|
||||
|
||||
if r.isBoundaryDelimiterLine(line) {
|
||||
r.partsRead++
|
||||
bp, err := newPart(r, rawPart)
|
||||
bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
14
src/mime/multipart/readmimeheader.go
Normal file
14
src/mime/multipart/readmimeheader.go
Normal file
@@ -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)
|
||||
@@ -1097,7 +1097,7 @@ func testMissingFile(t *testing.T, req *Request) {
|
||||
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)
|
||||
|
||||
@@ -617,50 +617,6 @@ func TestTCPStress(t *testing.T) {
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestTCPSelfConnect(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// TODO(brainman): do not know why it hangs.
|
||||
t.Skip("known-broken test on windows")
|
||||
}
|
||||
|
||||
ln := newLocalListener(t, "tcp")
|
||||
var d Dialer
|
||||
c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
|
||||
if err != nil {
|
||||
ln.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
network := c.LocalAddr().Network()
|
||||
laddr := *c.LocalAddr().(*TCPAddr)
|
||||
c.Close()
|
||||
ln.Close()
|
||||
|
||||
// Try to connect to that address repeatedly.
|
||||
n := 100000
|
||||
if testing.Short() {
|
||||
n = 1000
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "illumos", "solaris", "windows":
|
||||
// Non-Linux systems take a long time to figure
|
||||
// out that there is nothing listening on localhost.
|
||||
n = 100
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
d.Timeout = time.Millisecond
|
||||
c, err := d.Dial(network, laddr.String())
|
||||
if err == nil {
|
||||
addr := c.LocalAddr().(*TCPAddr)
|
||||
if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) {
|
||||
t.Errorf("Dial %v should fail", addr)
|
||||
} else {
|
||||
t.Logf("Dial %v succeeded - possibly racing with other listener", addr)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that >32-bit reads work on 64-bit systems.
|
||||
// On 32-bit systems this tests that maxint reads work.
|
||||
func TestTCPBig(t *testing.T) {
|
||||
|
||||
@@ -7,8 +7,10 @@ package textproto
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -477,6 +479,12 @@ var colon = []byte(":")
|
||||
// "Long-Key": {"Even Longer Value"},
|
||||
// }
|
||||
func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
|
||||
return readMIMEHeader(r, math.MaxInt64)
|
||||
}
|
||||
|
||||
// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size.
|
||||
// It is called by the mime/multipart package.
|
||||
func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
|
||||
// Avoid lots of small slice allocations later by allocating one
|
||||
// large one ahead of time which we'll cut up into smaller
|
||||
// slices. If this isn't big enough later, we allocate small ones.
|
||||
@@ -526,9 +534,19 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
|
||||
}
|
||||
|
||||
// Skip initial spaces in value.
|
||||
value := strings.TrimLeft(string(v), " \t")
|
||||
value := string(bytes.TrimLeft(v, " \t"))
|
||||
|
||||
vv := m[key]
|
||||
if vv == nil {
|
||||
lim -= int64(len(key))
|
||||
lim -= 100 // map entry overhead
|
||||
}
|
||||
lim -= int64(len(value))
|
||||
if lim < 0 {
|
||||
// TODO: This should be a distinguishable error (ErrMessageTooLarge)
|
||||
// to allow mime/multipart to detect it.
|
||||
return m, errors.New("message too large")
|
||||
}
|
||||
if vv == nil && len(strs) > 0 {
|
||||
// More than likely this will be a single-element key.
|
||||
// Most headers aren't multi-valued.
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -117,21 +118,9 @@ func Clean(path string) string {
|
||||
case os.IsPathSeparator(path[r]):
|
||||
// empty path element
|
||||
r++
|
||||
case path[r] == '.' && r+1 == n:
|
||||
case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
|
||||
// . element
|
||||
r++
|
||||
case path[r] == '.' && os.IsPathSeparator(path[r+1]):
|
||||
// ./ element
|
||||
r++
|
||||
|
||||
for r < len(path) && os.IsPathSeparator(path[r]) {
|
||||
r++
|
||||
}
|
||||
if out.w == 0 && volumeNameLen(path[r:]) > 0 {
|
||||
// When joining prefix "." and an absolute path on Windows,
|
||||
// the prefix should not be removed.
|
||||
out.append('.')
|
||||
}
|
||||
case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
|
||||
// .. element: remove to last separator
|
||||
r += 2
|
||||
@@ -157,6 +146,18 @@ func Clean(path string) string {
|
||||
if rooted && out.w != 1 || !rooted && out.w != 0 {
|
||||
out.append(Separator)
|
||||
}
|
||||
// If a ':' appears in the path element at the start of a Windows path,
|
||||
// insert a .\ at the beginning to avoid converting relative paths
|
||||
// like a/../c: into c:.
|
||||
if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 {
|
||||
for i := r; i < n && !os.IsPathSeparator(path[i]); i++ {
|
||||
if path[i] == ':' {
|
||||
out.append('.')
|
||||
out.append(Separator)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy element
|
||||
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
|
||||
out.append(path[r])
|
||||
|
||||
@@ -106,6 +106,13 @@ var wincleantests = []PathTest{
|
||||
{`//abc`, `\\abc`},
|
||||
{`///abc`, `\\\abc`},
|
||||
{`//abc//`, `\\abc\\`},
|
||||
|
||||
// Don't allow cleaning to move an element with a colon to the start of the path.
|
||||
{`a/../c:`, `.\c:`},
|
||||
{`a\..\c:`, `.\c:`},
|
||||
{`a/../c:/a`, `.\c:\a`},
|
||||
{`a/../../c:`, `..\c:`},
|
||||
{`foo:bar`, `foo:bar`},
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
@@ -174,6 +181,7 @@ var winislocaltests = []IsLocalTest{
|
||||
{`C:`, false},
|
||||
{`C:\a`, false},
|
||||
{`..\a`, false},
|
||||
{`a/../c:`, false},
|
||||
{`CONIN$`, false},
|
||||
{`conin$`, false},
|
||||
{`CONOUT$`, false},
|
||||
|
||||
@@ -542,7 +542,7 @@ func TestIssue52476(t *testing.T) {
|
||||
}{
|
||||
{`..\.`, `C:`, `..\C:`},
|
||||
{`..`, `C:`, `..\C:`},
|
||||
{`.`, `:`, `:`},
|
||||
{`.`, `:`, `.\:`},
|
||||
{`.`, `C:`, `.\C:`},
|
||||
{`.`, `C:/a/b/../c`, `.\C:\a\c`},
|
||||
{`.`, `\C:`, `.\C:`},
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"internal/coverage/pods"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// processCoverTestDir is called (via a linknamed reference) from
|
||||
@@ -80,7 +81,15 @@ func processCoverTestDirInternal(dir string, cfile string, cm string, cpkg strin
|
||||
cf: cformat.NewFormatter(cmode),
|
||||
cmode: cmode,
|
||||
}
|
||||
// Generate the expected hash string based on the final meta-data
|
||||
// hash for this test, then look only for pods that refer to that
|
||||
// hash (just in case there are multiple instrumented executables
|
||||
// in play). See issue #57924 for more on this.
|
||||
hashstring := fmt.Sprintf("%x", finalHash)
|
||||
for _, p := range podlist {
|
||||
if !strings.Contains(p.MetaFile, hashstring) {
|
||||
continue
|
||||
}
|
||||
if err := ts.processPod(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -873,11 +873,30 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
|
||||
traceGCSweepStart()
|
||||
}
|
||||
|
||||
// Fix debt if necessary.
|
||||
retry:
|
||||
sweptBasis := mheap_.pagesSweptBasis.Load()
|
||||
|
||||
// Fix debt if necessary.
|
||||
newHeapLive := uintptr(gcController.heapLive.Load()-mheap_.sweepHeapLiveBasis) + spanBytes
|
||||
live := gcController.heapLive.Load()
|
||||
liveBasis := mheap_.sweepHeapLiveBasis
|
||||
newHeapLive := spanBytes
|
||||
if liveBasis < live {
|
||||
// Only do this subtraction when we don't overflow. Otherwise, pagesTarget
|
||||
// might be computed as something really huge, causing us to get stuck
|
||||
// sweeping here until the next mark phase.
|
||||
//
|
||||
// Overflow can happen here if gcPaceSweeper is called concurrently with
|
||||
// sweeping (i.e. not during a STW, like it usually is) because this code
|
||||
// is intentionally racy. A concurrent call to gcPaceSweeper can happen
|
||||
// if a GC tuning parameter is modified and we read an older value of
|
||||
// heapLive than what was used to set the basis.
|
||||
//
|
||||
// This state should be transient, so it's fine to just let newHeapLive
|
||||
// be a relatively small number. We'll probably just skip this attempt to
|
||||
// sweep.
|
||||
//
|
||||
// See issue #57523.
|
||||
newHeapLive += uintptr(live - liveBasis)
|
||||
}
|
||||
pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages)
|
||||
for pagesTarget > int64(mheap_.pagesSwept.Load()-sweptBasis) {
|
||||
if sweepone() == ^uintptr(0) {
|
||||
|
||||
@@ -213,7 +213,9 @@ func pthread_kill_trampoline()
|
||||
//
|
||||
//go:nosplit
|
||||
func osinit_hack() {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(osinit_hack_trampoline)), nil)
|
||||
if GOOS == "darwin" { // not ios
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(osinit_hack_trampoline)), nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
func osinit_hack_trampoline()
|
||||
|
||||
@@ -190,5 +190,5 @@ func (v *Value) CompareAndSwap(old, new any) (swapped bool) {
|
||||
}
|
||||
|
||||
// Disable/enable preemption, implemented in runtime.
|
||||
func runtime_procPin()
|
||||
func runtime_procPin() int
|
||||
func runtime_procUnpin()
|
||||
|
||||
@@ -27,9 +27,11 @@ import (
|
||||
// In the terminology of the Go memory model, Map arranges that a write operation
|
||||
// “synchronizes before” any read operation that observes the effect of the write, where
|
||||
// read and write operations are defined as follows.
|
||||
// Load, LoadAndDelete, LoadOrStore are read operations;
|
||||
// Delete, LoadAndDelete, and Store are write operations;
|
||||
// and LoadOrStore is a write operation when it returns loaded set to false.
|
||||
// Load, LoadAndDelete, LoadOrStore, Swap, CompareAndSwap, and CompareAndDelete
|
||||
// are read operations; Delete, LoadAndDelete, Store, and Swap are write operations;
|
||||
// LoadOrStore is a write operation when it returns loaded set to false;
|
||||
// CompareAndSwap is a write operation when it returns swapped set to true;
|
||||
// and CompareAndDelete is a write operation when it returns deleted set to true.
|
||||
type Map struct {
|
||||
mu Mutex
|
||||
|
||||
|
||||
@@ -74,21 +74,24 @@ func Clearenv() {
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
s, e := GetEnvironmentStrings()
|
||||
envp, e := GetEnvironmentStrings()
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
defer FreeEnvironmentStrings(s)
|
||||
defer FreeEnvironmentStrings(envp)
|
||||
|
||||
r := make([]string, 0, 50) // Empty with room to grow.
|
||||
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
|
||||
if p[i] == 0 {
|
||||
// empty string marks the end
|
||||
if i <= from {
|
||||
break
|
||||
}
|
||||
r = append(r, string(utf16.Decode(p[from:i])))
|
||||
from = i + 1
|
||||
const size = unsafe.Sizeof(*envp)
|
||||
for *envp != 0 { // environment block ends with empty string
|
||||
// find NUL terminator
|
||||
end := unsafe.Pointer(envp)
|
||||
for *(*uint16)(end) != 0 {
|
||||
end = unsafe.Add(end, size)
|
||||
}
|
||||
|
||||
entry := unsafe.Slice(envp, (uintptr(end)-uintptr(unsafe.Pointer(envp)))/size)
|
||||
r = append(r, string(utf16.Decode(entry)))
|
||||
envp = (*uint16)(unsafe.Add(end, size))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -138,6 +138,16 @@ func isGroupMember(gid int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isCapDacOverrideSet() bool {
|
||||
const _CAP_DAC_OVERRIDE = 1
|
||||
var c caps
|
||||
c.hdr.version = _LINUX_CAPABILITY_VERSION_3
|
||||
|
||||
_, _, err := RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0)
|
||||
|
||||
return err == 0 && c.data[0].effective&capToMask(_CAP_DAC_OVERRIDE) != 0
|
||||
}
|
||||
|
||||
//sys faccessat(dirfd int, path string, mode uint32) (err error)
|
||||
//sys faccessat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_faccessat2
|
||||
|
||||
@@ -179,9 +189,16 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fallback to checking permission bits.
|
||||
var uid int
|
||||
if flags&_AT_EACCESS != 0 {
|
||||
uid = Geteuid()
|
||||
if uid != 0 && isCapDacOverrideSet() {
|
||||
// If CAP_DAC_OVERRIDE is set, file access check is
|
||||
// done by the kernel in the same way as for root
|
||||
// (see generic_permission() in the Linux sources).
|
||||
uid = 0
|
||||
}
|
||||
} else {
|
||||
uid = Getuid()
|
||||
}
|
||||
|
||||
@@ -155,7 +155,8 @@ func parseRFC3339[bytes []byte | string](s bytes, local *Location) (Time, bool)
|
||||
func parseStrictRFC3339(b []byte) (Time, error) {
|
||||
t, ok := parseRFC3339(b, Local)
|
||||
if !ok {
|
||||
if _, err := Parse(RFC3339, string(b)); err != nil {
|
||||
t, err := Parse(RFC3339, string(b))
|
||||
if err != nil {
|
||||
return Time{}, err
|
||||
}
|
||||
|
||||
@@ -164,6 +165,10 @@ func parseStrictRFC3339(b []byte) (Time, error) {
|
||||
// See https://go.dev/issue/54580.
|
||||
num2 := func(b []byte) byte { return 10*(b[0]-'0') + (b[1] - '0') }
|
||||
switch {
|
||||
// TODO(https://go.dev/issue/54580): Strict parsing is disabled for now.
|
||||
// Enable this again with a GODEBUG opt-out.
|
||||
case true:
|
||||
return t, nil
|
||||
case b[len("2006-01-02T")+1] == ':': // hour must be two digits
|
||||
return Time{}, &ParseError{RFC3339, string(b), "15", string(b[len("2006-01-02T"):][:1]), ""}
|
||||
case b[len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a period
|
||||
|
||||
@@ -830,10 +830,10 @@ func TestUnmarshalInvalidTimes(t *testing.T) {
|
||||
}{
|
||||
{`{}`, "Time.UnmarshalJSON: input is not a JSON string"},
|
||||
{`[]`, "Time.UnmarshalJSON: input is not a JSON string"},
|
||||
{`"2000-01-01T1:12:34Z"`, `parsing time "2000-01-01T1:12:34Z" as "2006-01-02T15:04:05Z07:00": cannot parse "1" as "15"`},
|
||||
{`"2000-01-01T00:00:00,000Z"`, `parsing time "2000-01-01T00:00:00,000Z" as "2006-01-02T15:04:05Z07:00": cannot parse "," as "."`},
|
||||
{`"2000-01-01T00:00:00+24:00"`, `parsing time "2000-01-01T00:00:00+24:00": timezone hour out of range`},
|
||||
{`"2000-01-01T00:00:00+00:60"`, `parsing time "2000-01-01T00:00:00+00:60": timezone minute out of range`},
|
||||
{`"2000-01-01T1:12:34Z"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00,000Z"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+24:00"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+00:60"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+123:45"`, `parsing time "2000-01-01T00:00:00+123:45" as "2006-01-02T15:04:05Z07:00": cannot parse "+123:45" as "Z07:00"`},
|
||||
}
|
||||
|
||||
@@ -842,13 +842,13 @@ func TestUnmarshalInvalidTimes(t *testing.T) {
|
||||
|
||||
want := tt.want
|
||||
err := json.Unmarshal([]byte(tt.in), &ts)
|
||||
if err == nil || err.Error() != want {
|
||||
if fmt.Sprint(err) != want {
|
||||
t.Errorf("Time.UnmarshalJSON(%s) = %v, want %v", tt.in, err, want)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(tt.in, `"`) && strings.HasSuffix(tt.in, `"`) {
|
||||
err = ts.UnmarshalText([]byte(strings.Trim(tt.in, `"`)))
|
||||
if err == nil || err.Error() != want {
|
||||
if fmt.Sprint(err) != want {
|
||||
t.Errorf("Time.UnmarshalText(%s) = %v, want %v", tt.in, err, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ var abbrs = map[string]abbr{
|
||||
"Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
|
||||
"Morocco Standard Time": {"+00", "+01"}, // Africa/Casablanca
|
||||
"South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
|
||||
"South Sudan Standard Time": {"CAT", "CAT"}, // Africa/Juba
|
||||
"Sudan Standard Time": {"CAT", "CAT"}, // Africa/Khartoum
|
||||
"W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
|
||||
"E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
|
||||
"Sao Tome Standard Time": {"GMT", "WAT"}, // Africa/Sao_Tome
|
||||
"Sao Tome Standard Time": {"GMT", "GMT"}, // Africa/Sao_Tome
|
||||
"Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
|
||||
"Namibia Standard Time": {"CAT", "CAT"}, // Africa/Windhoek
|
||||
"Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
|
||||
@@ -33,8 +34,8 @@ var abbrs = map[string]abbr{
|
||||
"Venezuela Standard Time": {"-04", "-04"}, // America/Caracas
|
||||
"SA Eastern Standard Time": {"-03", "-03"}, // America/Cayenne
|
||||
"Central Standard Time": {"CST", "CDT"}, // America/Chicago
|
||||
"Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
|
||||
"Central Brazilian Standard Time": {"-04", "-03"}, // America/Cuiaba
|
||||
"Mountain Standard Time (Mexico)": {"CST", "CST"}, // America/Chihuahua
|
||||
"Central Brazilian Standard Time": {"-04", "-04"}, // America/Cuiaba
|
||||
"Mountain Standard Time": {"MST", "MDT"}, // America/Denver
|
||||
"Greenland Standard Time": {"-03", "-02"}, // America/Godthab
|
||||
"Turks And Caicos Standard Time": {"EST", "EDT"}, // America/Grand_Turk
|
||||
@@ -44,7 +45,7 @@ var abbrs = map[string]abbr{
|
||||
"US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
|
||||
"SA Western Standard Time": {"-04", "-04"}, // America/La_Paz
|
||||
"Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
|
||||
"Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
|
||||
"Central Standard Time (Mexico)": {"CST", "CST"}, // America/Mexico_City
|
||||
"Saint Pierre Standard Time": {"-03", "-02"}, // America/Miquelon
|
||||
"Montevideo Standard Time": {"-03", "-03"}, // America/Montevideo
|
||||
"Eastern Standard Time": {"EST", "EDT"}, // America/New_York
|
||||
@@ -53,11 +54,12 @@ var abbrs = map[string]abbr{
|
||||
"Magallanes Standard Time": {"-03", "-03"}, // America/Punta_Arenas
|
||||
"Canada Central Standard Time": {"CST", "CST"}, // America/Regina
|
||||
"Pacific SA Standard Time": {"-04", "-03"}, // America/Santiago
|
||||
"E. South America Standard Time": {"-03", "-02"}, // America/Sao_Paulo
|
||||
"E. South America Standard Time": {"-03", "-03"}, // America/Sao_Paulo
|
||||
"Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
|
||||
"Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Tijuana
|
||||
"Yukon Standard Time": {"MST", "MST"}, // America/Whitehorse
|
||||
"Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty
|
||||
"Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
|
||||
"Jordan Standard Time": {"+03", "+03"}, // Asia/Amman
|
||||
"Arabic Standard Time": {"+03", "+03"}, // Asia/Baghdad
|
||||
"Azerbaijan Standard Time": {"+04", "+04"}, // Asia/Baku
|
||||
"SE Asia Standard Time": {"+07", "+07"}, // Asia/Bangkok
|
||||
@@ -66,7 +68,7 @@ var abbrs = map[string]abbr{
|
||||
"India Standard Time": {"IST", "IST"}, // Asia/Calcutta
|
||||
"Transbaikal Standard Time": {"+09", "+09"}, // Asia/Chita
|
||||
"Sri Lanka Standard Time": {"+0530", "+0530"}, // Asia/Colombo
|
||||
"Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
|
||||
"Syria Standard Time": {"+03", "+03"}, // Asia/Damascus
|
||||
"Bangladesh Standard Time": {"+06", "+06"}, // Asia/Dhaka
|
||||
"Arabian Standard Time": {"+04", "+04"}, // Asia/Dubai
|
||||
"West Bank Standard Time": {"EET", "EEST"}, // Asia/Hebron
|
||||
@@ -82,7 +84,7 @@ var abbrs = map[string]abbr{
|
||||
"N. Central Asia Standard Time": {"+07", "+07"}, // Asia/Novosibirsk
|
||||
"Omsk Standard Time": {"+06", "+06"}, // Asia/Omsk
|
||||
"North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
|
||||
"Qyzylorda Standard Time": {"+05", "+06"}, // Asia/Qyzylorda
|
||||
"Qyzylorda Standard Time": {"+05", "+05"}, // Asia/Qyzylorda
|
||||
"Myanmar Standard Time": {"+0630", "+0630"}, // Asia/Rangoon
|
||||
"Arab Standard Time": {"+03", "+03"}, // Asia/Riyadh
|
||||
"Sakhalin Standard Time": {"+11", "+11"}, // Asia/Sakhalin
|
||||
@@ -93,7 +95,7 @@ var abbrs = map[string]abbr{
|
||||
"Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
|
||||
"West Asia Standard Time": {"+05", "+05"}, // Asia/Tashkent
|
||||
"Georgian Standard Time": {"+04", "+04"}, // Asia/Tbilisi
|
||||
"Iran Standard Time": {"+0330", "+0430"}, // Asia/Tehran
|
||||
"Iran Standard Time": {"+0330", "+0330"}, // Asia/Tehran
|
||||
"Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
|
||||
"Tomsk Standard Time": {"+07", "+07"}, // Asia/Tomsk
|
||||
"Ulaanbaatar Standard Time": {"+08", "+08"}, // Asia/Ulaanbaatar
|
||||
@@ -112,7 +114,6 @@ var abbrs = map[string]abbr{
|
||||
"Lord Howe Standard Time": {"+1030", "+11"}, // Australia/Lord_Howe
|
||||
"W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
|
||||
"AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
|
||||
"UTC": {"GMT", "GMT"}, // Etc/GMT
|
||||
"UTC-11": {"-11", "-11"}, // Etc/GMT+11
|
||||
"Dateline Standard Time": {"-12", "-12"}, // Etc/GMT+12
|
||||
"UTC-02": {"-02", "-02"}, // Etc/GMT+2
|
||||
@@ -120,6 +121,7 @@ var abbrs = map[string]abbr{
|
||||
"UTC-09": {"-09", "-09"}, // Etc/GMT+9
|
||||
"UTC+12": {"+12", "+12"}, // Etc/GMT-12
|
||||
"UTC+13": {"+13", "+13"}, // Etc/GMT-13
|
||||
"UTC": {"UTC", "UTC"}, // Etc/UTC
|
||||
"Astrakhan Standard Time": {"+04", "+04"}, // Europe/Astrakhan
|
||||
"W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
|
||||
"GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
|
||||
@@ -134,20 +136,20 @@ var abbrs = map[string]abbr{
|
||||
"Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
|
||||
"Russia Time Zone 3": {"+04", "+04"}, // Europe/Samara
|
||||
"Saratov Standard Time": {"+04", "+04"}, // Europe/Saratov
|
||||
"Volgograd Standard Time": {"+04", "+04"}, // Europe/Volgograd
|
||||
"Volgograd Standard Time": {"+03", "+03"}, // Europe/Volgograd
|
||||
"Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
|
||||
"Mauritius Standard Time": {"+04", "+04"}, // Indian/Mauritius
|
||||
"Samoa Standard Time": {"+13", "+14"}, // Pacific/Apia
|
||||
"Samoa Standard Time": {"+13", "+13"}, // Pacific/Apia
|
||||
"New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
|
||||
"Bougainville Standard Time": {"+11", "+11"}, // Pacific/Bougainville
|
||||
"Chatham Islands Standard Time": {"+1245", "+1345"}, // Pacific/Chatham
|
||||
"Easter Island Standard Time": {"-06", "-05"}, // Pacific/Easter
|
||||
"Fiji Standard Time": {"+12", "+13"}, // Pacific/Fiji
|
||||
"Fiji Standard Time": {"+12", "+12"}, // Pacific/Fiji
|
||||
"Central Pacific Standard Time": {"+11", "+11"}, // Pacific/Guadalcanal
|
||||
"Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
|
||||
"Line Islands Standard Time": {"+14", "+14"}, // Pacific/Kiritimati
|
||||
"Marquesas Standard Time": {"-0930", "-0930"}, // Pacific/Marquesas
|
||||
"Norfolk Standard Time": {"+11", "+11"}, // Pacific/Norfolk
|
||||
"Norfolk Standard Time": {"+11", "+12"}, // Pacific/Norfolk
|
||||
"West Pacific Standard Time": {"+10", "+10"}, // Pacific/Port_Moresby
|
||||
"Tonga Standard Time": {"+13", "+13"}, // Pacific/Tongatapu
|
||||
}
|
||||
|
||||
85
src/vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
85
src/vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
@@ -359,6 +359,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||
|
||||
var hf HeaderField
|
||||
wantStr := d.emitEnabled || it.indexed()
|
||||
var undecodedName undecodedString
|
||||
if nameIdx > 0 {
|
||||
ihf, ok := d.at(nameIdx)
|
||||
if !ok {
|
||||
@@ -366,15 +367,27 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||
}
|
||||
hf.Name = ihf.Name
|
||||
} else {
|
||||
hf.Name, buf, err = d.readString(buf, wantStr)
|
||||
undecodedName, buf, err = d.readString(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hf.Value, buf, err = d.readString(buf, wantStr)
|
||||
undecodedValue, buf, err := d.readString(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wantStr {
|
||||
if nameIdx <= 0 {
|
||||
hf.Name, err = d.decodeString(undecodedName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hf.Value, err = d.decodeString(undecodedValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.buf = buf
|
||||
if it.indexed() {
|
||||
d.dynTab.add(hf)
|
||||
@@ -459,46 +472,52 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
|
||||
return 0, origP, errNeedMore
|
||||
}
|
||||
|
||||
// readString decodes an hpack string from p.
|
||||
// readString reads an hpack string from p.
|
||||
//
|
||||
// wantStr is whether s will be used. If false, decompression and
|
||||
// []byte->string garbage are skipped if s will be ignored
|
||||
// anyway. This does mean that huffman decoding errors for non-indexed
|
||||
// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
|
||||
// is returning an error anyway, and because they're not indexed, the error
|
||||
// won't affect the decoding state.
|
||||
func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
|
||||
// It returns a reference to the encoded string data to permit deferring decode costs
|
||||
// until after the caller verifies all data is present.
|
||||
func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
|
||||
if len(p) == 0 {
|
||||
return "", p, errNeedMore
|
||||
return u, p, errNeedMore
|
||||
}
|
||||
isHuff := p[0]&128 != 0
|
||||
strLen, p, err := readVarInt(7, p)
|
||||
if err != nil {
|
||||
return "", p, err
|
||||
return u, p, err
|
||||
}
|
||||
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
|
||||
return "", nil, ErrStringLength
|
||||
// Returning an error here means Huffman decoding errors
|
||||
// for non-indexed strings past the maximum string length
|
||||
// are ignored, but the server is returning an error anyway
|
||||
// and because the string is not indexed the error will not
|
||||
// affect the decoding state.
|
||||
return u, nil, ErrStringLength
|
||||
}
|
||||
if uint64(len(p)) < strLen {
|
||||
return "", p, errNeedMore
|
||||
return u, p, errNeedMore
|
||||
}
|
||||
if !isHuff {
|
||||
if wantStr {
|
||||
s = string(p[:strLen])
|
||||
}
|
||||
return s, p[strLen:], nil
|
||||
}
|
||||
|
||||
if wantStr {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
defer bufPool.Put(buf)
|
||||
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||
buf.Reset()
|
||||
return "", nil, err
|
||||
}
|
||||
s = buf.String()
|
||||
buf.Reset() // be nice to GC
|
||||
}
|
||||
return s, p[strLen:], nil
|
||||
u.isHuff = isHuff
|
||||
u.b = p[:strLen]
|
||||
return u, p[strLen:], nil
|
||||
}
|
||||
|
||||
type undecodedString struct {
|
||||
isHuff bool
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeString(u undecodedString) (string, error) {
|
||||
if !u.isHuff {
|
||||
return string(u.b), nil
|
||||
}
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
var s string
|
||||
err := huffmanDecode(buf, d.maxStrLen, u.b)
|
||||
if err == nil {
|
||||
s = buf.String()
|
||||
}
|
||||
buf.Reset() // be nice to GC
|
||||
bufPool.Put(buf)
|
||||
return s, err
|
||||
}
|
||||
|
||||
2
src/vendor/modules.txt
vendored
2
src/vendor/modules.txt
vendored
@@ -7,7 +7,7 @@ golang.org/x/crypto/cryptobyte/asn1
|
||||
golang.org/x/crypto/hkdf
|
||||
golang.org/x/crypto/internal/alias
|
||||
golang.org/x/crypto/internal/poly1305
|
||||
# golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10
|
||||
# golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d
|
||||
## explicit; go 1.17
|
||||
golang.org/x/net/dns/dnsmessage
|
||||
golang.org/x/net/http/httpguts
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// compiledir
|
||||
// compiledir -d=inlstaticinit=1
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
19
test/fixedbugs/issue57778.go
Normal file
19
test/fixedbugs/issue57778.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
type FreeListG[T any] struct {
|
||||
freelist []*node[T]
|
||||
}
|
||||
|
||||
type node[T any] struct{}
|
||||
|
||||
func NewFreeListG[T any](size int) *FreeListG[T] {
|
||||
return &FreeListG[T]{freelist: make([]*node[T], 0, size)}
|
||||
}
|
||||
|
||||
var bf = NewFreeListG[*int](1024)
|
||||
76
test/fixedbugs/issue57823.go
Normal file
76
test/fixedbugs/issue57823.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:noinline
|
||||
func g(x *byte) *byte { return x }
|
||||
|
||||
func main() {
|
||||
slice()
|
||||
str("AAAAAAAA", "BBBBBBBBB")
|
||||
}
|
||||
|
||||
func wait(done <-chan struct{}) bool {
|
||||
for i := 0; i < 10; i++ {
|
||||
runtime.GC()
|
||||
select {
|
||||
case <-done:
|
||||
return true
|
||||
default:
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func slice() {
|
||||
s := make([]byte, 100)
|
||||
s[0] = 1
|
||||
one := unsafe.SliceData(s)
|
||||
|
||||
done := make(chan struct{})
|
||||
runtime.SetFinalizer(one, func(*byte) { close(done) })
|
||||
|
||||
h := g(one)
|
||||
|
||||
if wait(done) {
|
||||
panic("GC'd early")
|
||||
}
|
||||
|
||||
if *h != 1 {
|
||||
panic("lost one")
|
||||
}
|
||||
|
||||
if !wait(done) {
|
||||
panic("never GC'd")
|
||||
}
|
||||
}
|
||||
|
||||
var strDone = make(chan struct{})
|
||||
|
||||
//go:noinline
|
||||
func str(x, y string) {
|
||||
s := x + y // put in temporary on stack
|
||||
p := unsafe.StringData(s)
|
||||
runtime.SetFinalizer(p, func(*byte) { close(strDone) })
|
||||
|
||||
if wait(strDone) {
|
||||
panic("GC'd early")
|
||||
}
|
||||
|
||||
if *p != 'A' {
|
||||
panic("lost p")
|
||||
}
|
||||
|
||||
if !wait(strDone) {
|
||||
panic("never GC'd")
|
||||
}
|
||||
}
|
||||
13
test/fixedbugs/issue58293.go
Normal file
13
test/fixedbugs/issue58293.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
var bar = f(13579)
|
||||
|
||||
func f(x uint16) uint16 {
|
||||
return x>>8 | x<<8
|
||||
}
|
||||
23
test/fixedbugs/issue58325.go
Normal file
23
test/fixedbugs/issue58325.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
type S1 struct {
|
||||
s2 S2
|
||||
}
|
||||
|
||||
type S2 struct{}
|
||||
|
||||
func (S2) Make() S2 {
|
||||
return S2{}
|
||||
}
|
||||
|
||||
func (S1) Make() S1 {
|
||||
return S1{s2: S2{}.Make()}
|
||||
}
|
||||
|
||||
var _ = S1{}.Make()
|
||||
30
test/fixedbugs/issue58341.go
Normal file
30
test/fixedbugs/issue58341.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
type S[T comparable] struct {
|
||||
m map[T]T
|
||||
}
|
||||
|
||||
func (s S[T]) M1(node T) {
|
||||
defer delete(s.m, node)
|
||||
}
|
||||
|
||||
func (s S[T]) M2(node T) {
|
||||
defer func() {
|
||||
delete(s.m, node)
|
||||
}()
|
||||
}
|
||||
|
||||
func (s S[T]) M3(node T) {
|
||||
defer f(s.m, node)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f[T comparable](map[T]T, T) {}
|
||||
|
||||
var _ = S[int]{}
|
||||
13
test/fixedbugs/issue58563.dir/a.go
Normal file
13
test/fixedbugs/issue58563.dir/a.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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 a
|
||||
|
||||
func Start() interface{ Stop() } {
|
||||
return new(Stopper)
|
||||
}
|
||||
|
||||
type Stopper struct{}
|
||||
|
||||
func (s *Stopper) Stop() {}
|
||||
16
test/fixedbugs/issue58563.dir/main.go
Normal file
16
test/fixedbugs/issue58563.dir/main.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 main
|
||||
|
||||
import "test/a"
|
||||
|
||||
func main() {
|
||||
stop := start()
|
||||
defer stop()
|
||||
}
|
||||
|
||||
func start() func() {
|
||||
return a.Start().Stop
|
||||
}
|
||||
7
test/fixedbugs/issue58563.go
Normal file
7
test/fixedbugs/issue58563.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// compiledir
|
||||
|
||||
// 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 ignored
|
||||
@@ -1,4 +1,4 @@
|
||||
// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
|
||||
// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1 -d=inlstaticinit=1
|
||||
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user