]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.boringcrypto] all: merge master into dev.boringcrypto
authorDmitri Shuralyov <dmitshur@golang.org>
Thu, 9 Jul 2020 03:29:54 +0000 (23:29 -0400)
committerDmitri Shuralyov <dmitshur@golang.org>
Thu, 9 Jul 2020 21:52:30 +0000 (17:52 -0400)
Change-Id: I948e086e11e1da571e2be23bb08a7bbd6618dc2f

13 files changed:
1  2 
src/cmd/go/go_test.go
src/cmd/go/internal/load/pkg.go
src/cmd/link/internal/ld/lib.go
src/crypto/hmac/hmac.go
src/crypto/hmac/hmac_test.go
src/crypto/tls/common.go
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_tls13.go
src/crypto/tls/handshake_messages_test.go
src/crypto/tls/handshake_server.go
src/crypto/tls/handshake_server_tls13.go
src/crypto/x509/verify.go
src/go/build/deps_test.go

diff --combined src/cmd/go/go_test.go
index 6b832076b269d164389bb0e8845248c13ac0a5f3,021930a8a8170106002e7d6cde64b749c43d49be..31eb1418e52e97610264cfecd497bc9cc23d8736
@@@ -6,7 -6,6 +6,6 @@@ package main_tes
  
  import (
        "bytes"
-       "context"
        "debug/elf"
        "debug/macho"
        "debug/pe"
@@@ -114,12 -113,6 +113,6 @@@ var testGo strin
  var testTmpDir string
  var testBin string
  
- // testCtx is canceled when the test binary is about to time out.
- //
- // If https://golang.org/issue/28135 is accepted, uses of this variable in test
- // functions should be replaced by t.Context().
- var testCtx = context.Background()
  // The TestMain function creates a go command for testing purposes and
  // deletes it after the tests have been run.
  func TestMain(m *testing.M) {
                fmt.Printf("SKIP\n")
                return
        }
-       os.Unsetenv("GOROOT_FINAL")
  
        flag.Parse()
  
-       timeoutFlag := flag.Lookup("test.timeout")
-       if timeoutFlag != nil {
-               // TODO(golang.org/issue/28147): The go command does not pass the
-               // test.timeout flag unless either -timeout or -test.timeout is explicitly
-               // set on the command line.
-               if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
-                       aBitShorter := d * 95 / 100
-                       var cancel context.CancelFunc
-                       testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
-                       defer cancel()
-               }
-       }
        if *proxyAddr != "" {
                StartProxy()
                select {}
                }
                testGOROOT = goEnv("GOROOT")
                os.Setenv("TESTGO_GOROOT", testGOROOT)
+               // Ensure that GOROOT is set explicitly.
+               // Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
+               // yet been moved to its final location, programs that invoke runtime.GOROOT
+               // may accidentally use the wrong path.
+               os.Setenv("GOROOT", testGOROOT)
  
                // The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
                // toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
                }
                testCC = strings.TrimSpace(string(out))
  
-               if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
-                       fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
+               cmd := exec.Command(testGo, "env", "CGO_ENABLED")
+               cmd.Stderr = new(strings.Builder)
+               if out, err := cmd.Output(); err != nil {
+                       fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
                        canRun = false
                } else {
                        canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
@@@ -829,10 -815,9 +815,9 @@@ func removeAll(dir string) error 
        // module cache has 0444 directories;
        // make them writable in order to remove content.
        filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
-               if err != nil {
-                       return nil // ignore errors walking in file system
-               }
-               if info.IsDir() {
+               // chmod not only directories, but also things that we couldn't even stat
+               // due to permission errors: they may also be unreadable directories.
+               if err != nil || info.IsDir() {
                        os.Chmod(path, 0777)
                }
                return nil
@@@ -1859,12 -1844,8 +1844,12 @@@ func TestBinaryOnlyPackages(t *testing.
        tg.grepStdout("p2: false", "p2 listed as BinaryOnly")
  }
  
 -// Issue 16050.
 -func TestAlwaysLinkSysoFiles(t *testing.T) {
 +// Issue 16050 and 21884.
 +func TestLinkSysoFiles(t *testing.T) {
 +      if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
 +              t.Skip("not linux/amd64")
 +      }
 +
        tg := testgo(t)
        defer tg.cleanup()
        tg.parallel()
        tg.setenv("CGO_ENABLED", "0")
        tg.run("list", "-f", "{{.SysoFiles}}", "syso")
        tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
 +
 +      tg.setenv("CGO_ENABLED", "1")
 +      tg.run("list", "-msan", "-f", "{{.SysoFiles}}", "syso")
 +      tg.grepStdoutNot("a.syso", "unexpected syso file with -msan")
  }
  
  // Issue 16120.
index 61818380c77f0bd0675f5de4995e04a33244a2a1,fcc47bd9c519836f5a6cedb7d6ed43b2c69781fe..e0bd71b40d3f1e7eaed1a308b191959990fee8b0
@@@ -217,13 -217,9 +217,9 @@@ func (e *NoGoError) Error() string 
  // setLoadPackageDataError returns true if it's safe to load information about
  // imported packages, for example, if there was a parse error loading imports
  // in one file, but other files are okay.
- func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack) {
-       // Include the path on the import stack unless the error includes it already.
-       errHasPath := false
-       if impErr, ok := err.(ImportPathError); ok && impErr.ImportPath() == path {
-               errHasPath = true
-       } else if matchErr, ok := err.(*search.MatchError); ok && matchErr.Match.Pattern() == path {
-               errHasPath = true
+ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack, importPos []token.Position) {
+       matchErr, isMatchErr := err.(*search.MatchError)
+       if isMatchErr && matchErr.Match.Pattern() == path {
                if matchErr.Match.IsLiteral() {
                        // The error has a pattern has a pattern similar to the import path.
                        // It may be slightly different (./foo matching example.com/foo),
                        err = matchErr.Err
                }
        }
-       var errStk []string
-       if errHasPath {
-               errStk = stk.Copy()
-       } else {
-               stk.Push(path)
-               errStk = stk.Copy()
-               stk.Pop()
-       }
  
        // Replace (possibly wrapped) *build.NoGoError with *load.NoGoError.
        // The latter is more specific about the cause.
                err = &NoGoError{Package: p}
        }
  
+       // Report the error on the importing package if the problem is with the import declaration
+       // for example, if the package doesn't exist or if the import path is malformed.
+       // On the other hand, don't include a position if the problem is with the imported package,
+       // for example there are no Go files (NoGoError), or there's a problem in the imported
+       // package's source files themselves.
+       //
+       // TODO(matloob): Perhaps make each of those the errors in the first group
+       // (including modload.ImportMissingError, and the corresponding
+       // "cannot find package %q in any of" GOPATH-mode error
+       // produced in build.(*Context).Import; modload.AmbiguousImportError,
+       // and modload.PackageNotInModuleError; and the malformed module path errors
+       // produced in golang.org/x/mod/module.CheckMod) implement an interface
+       // to make it easier to check for them? That would save us from having to
+       // move the modload errors into this package to avoid a package import cycle,
+       // and from having to export an error type for the errors produced in build.
+       if !isMatchErr && nogoErr != nil {
+               stk.Push(path)
+               defer stk.Pop()
+       }
        // Take only the first error from a scanner.ErrorList. PackageError only
        // has room for one position, so we report the first error with a position
        // instead of all of the errors without a position.
        }
  
        p.Error = &PackageError{
-               ImportStack: errStk,
+               ImportStack: stk.Copy(),
                Pos:         pos,
                Err:         err,
        }
+       if path != stk.Top() {
+               p = setErrorPos(p, importPos)
+       }
  }
  
  // Resolve returns the resolved version of imports,
@@@ -336,12 -348,6 +348,12 @@@ func (p *Package) copyBuild(pp *build.P
        p.SwigFiles = pp.SwigFiles
        p.SwigCXXFiles = pp.SwigCXXFiles
        p.SysoFiles = pp.SysoFiles
 +      if cfg.BuildMSan {
 +              // There's no way for .syso files to be built both with and without
 +              // support for memory sanitizer. Assume they are built without,
 +              // and drop them.
 +              p.SysoFiles = nil
 +      }
        p.CgoCFLAGS = pp.CgoCFLAGS
        p.CgoCPPFLAGS = pp.CgoCPPFLAGS
        p.CgoCXXFLAGS = pp.CgoCXXFLAGS
@@@ -469,6 -475,13 +481,13 @@@ func (s *ImportStack) Copy() []string 
        return append([]string{}, *s...)
  }
  
+ func (s *ImportStack) Top() string {
+       if len(*s) == 0 {
+               return ""
+       }
+       return (*s)[len(*s)-1]
+ }
  // shorterThan reports whether sp is shorter than t.
  // We use this to record the shortest import sequence
  // that leads to a particular package.
@@@ -639,13 -652,7 +658,7 @@@ func loadImport(pre *preload, path, src
                // Load package.
                // loadPackageData may return bp != nil even if an error occurs,
                // in order to return partial information.
-               p.load(path, stk, bp, err)
-               // Add position information unless this is a NoGoError or an ImportCycle error.
-               // Import cycles deserve special treatment.
-               var g *build.NoGoError
-               if p.Error != nil && p.Error.Pos == "" && !errors.As(err, &g) && !p.Error.IsImportCycle {
-                       p = setErrorPos(p, importPos)
-               }
+               p.load(path, stk, importPos, bp, err)
  
                if !cfg.ModulesEnabled && path != cleanImport(path) {
                        p.Error = &PackageError{
@@@ -1579,7 -1586,7 +1592,7 @@@ func (p *Package) DefaultExecName() str
  // load populates p using information from bp, err, which should
  // be the result of calling build.Context.Import.
  // stk contains the import stack, not including path itself.
- func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err error) {
+ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
        p.copyBuild(bp)
  
        // The localPrefix is the path we interpret ./ imports relative to.
                                ImportStack: stk.Copy(),
                                Err:         err,
                        }
+                       // Add the importer's position information if the import position exists, and
+                       // the current package being examined is the importer.
+                       // If we have not yet accepted package p onto the import stack,
+                       // then the cause of the error is not within p itself: the error
+                       // must be either in an explicit command-line argument,
+                       // or on the importer side (indicated by a non-empty importPos).
+                       if path != stk.Top() && len(importPos) > 0 {
+                               p = setErrorPos(p, importPos)
+                       }
                }
        }
  
        if err != nil {
                p.Incomplete = true
-               p.setLoadPackageDataError(err, path, stk)
+               p.setLoadPackageDataError(err, path, stk, importPos)
        }
  
        useBindir := p.Name == "main"
        if useBindir {
                // Report an error when the old code.google.com/p/go.tools paths are used.
                if InstallTargetDir(p) == StalePath {
+                       // TODO(matloob): remove this branch, and StalePath itself. code.google.com/p/go is so
+                       // old, even this code checking for it is stale now!
                        newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
                        e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
                        setError(e)
@@@ -2169,8 -2188,10 +2194,10 @@@ func PackagesAndErrors(patterns []strin
                        // Report it as a synthetic package.
                        p := new(Package)
                        p.ImportPath = m.Pattern()
-                       var stk ImportStack // empty stack, since the error arose from a pattern, not an import
-                       p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk)
+                       // Pass an empty ImportStack and nil importPos: the error arose from a pattern, not an import.
+                       var stk ImportStack
+                       var importPos []token.Position
+                       p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk, importPos)
                        p.Incomplete = true
                        p.Match = append(p.Match, m.Pattern())
                        p.Internal.CmdlinePkg = true
@@@ -2316,7 -2337,7 +2343,7 @@@ func GoFilesPackage(gofiles []string) *
        pkg := new(Package)
        pkg.Internal.Local = true
        pkg.Internal.CmdlineFiles = true
-       pkg.load("command-line-arguments", &stk, bp, err)
+       pkg.load("command-line-arguments", &stk, nil, bp, err)
        pkg.Internal.LocalPrefix = dirToImportPath(dir)
        pkg.ImportPath = "command-line-arguments"
        pkg.Target = ""
index b2d74ed4e6e3661861586f14cc95c2d94e3419d7,b0a9613e4f478fda55a44b3c5dad81432a30ae33..b1bfd6e96bbc6d3a9b7091e373e4b9211b44e931
@@@ -1,5 -1,5 +1,5 @@@
  // Inferno utils/8l/asm.c
- // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+ // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
  //
  //    Copyright Â© 1994-1999 Lucent Technologies Inc.  All rights reserved.
  //    Portions Copyright Â© 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@@ -65,7 -65,7 +65,7 @@@ import 
  // Data layout and relocation.
  
  // Derived from Inferno utils/6l/l.h
- // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+ // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
  //
  //    Copyright Â© 1994-1999 Lucent Technologies Inc.  All rights reserved.
  //    Portions Copyright Â© 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@@ -157,6 -157,7 +157,7 @@@ const AfterLoadlibFull = 
  func (ctxt *Link) mkArchSym(which int, name string, ver int, ls *loader.Sym, ss **sym.Symbol) {
        if which == BeforeLoadlibFull {
                *ls = ctxt.loader.LookupOrCreateSym(name, ver)
+               ctxt.loader.SetAttrReachable(*ls, true)
        } else {
                *ss = ctxt.loader.Syms[*ls]
        }
  func (ctxt *Link) mkArchSymVec(which int, name string, ver int, ls []loader.Sym, ss []*sym.Symbol) {
        if which == BeforeLoadlibFull {
                ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
+               ctxt.loader.SetAttrReachable(ls[ver], true)
        } else if ls[ver] != 0 {
                ss[ver] = ctxt.loader.Syms[ls[ver]]
        }
@@@ -1128,7 -1130,6 +1130,7 @@@ var hostobj []Hostob
  // These packages can use internal linking mode.
  // Others trigger external mode.
  var internalpkg = []string{
 +      "crypto/internal/boring",
        "crypto/x509",
        "net",
        "os/user",
@@@ -1467,6 -1468,7 +1469,7 @@@ func (ctxt *Link) hostlink() 
                }
        }
  
+       var altLinker string
        if ctxt.IsELF && ctxt.DynlinkingGo() {
                // We force all symbol resolution to be done at program startup
                // because lazy PLT resolution can use large amounts of stack at
                // from the beginning of the section (like sym.STYPE).
                argv = append(argv, "-Wl,-znocopyreloc")
  
+               if objabi.GOOS == "android" {
+                       // Use lld to avoid errors from default linker (issue #38838)
+                       altLinker = "lld"
+               }
                if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && objabi.GOOS == "linux" {
                        // On ARM, the GNU linker will generate COPY relocations
                        // even with -znocopyreloc set.
                        // generating COPY relocations.
                        //
                        // In both cases, switch to gold.
-                       argv = append(argv, "-fuse-ld=gold")
+                       altLinker = "gold"
  
                        // If gold is not installed, gcc will silently switch
                        // back to ld.bfd. So we parse the version information
                        }
                }
        }
        if ctxt.Arch.Family == sys.ARM64 && objabi.GOOS == "freebsd" {
                // Switch to ld.bfd on freebsd/arm64.
-               argv = append(argv, "-fuse-ld=bfd")
+               altLinker = "bfd"
  
                // Provide a useful error if ld.bfd is missing.
                cmd := exec.Command(*flagExtld, "-fuse-ld=bfd", "-Wl,--version")
                        }
                }
        }
+       if altLinker != "" {
+               argv = append(argv, "-fuse-ld="+altLinker)
+       }
  
        if ctxt.IsELF && len(buildinfo) > 0 {
                argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
        }
  
        const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
-       if ctxt.compressDWARF && linkerFlagSupported(argv[0], compressDWARF) {
+       if ctxt.compressDWARF && linkerFlagSupported(argv[0], altLinker, compressDWARF) {
                argv = append(argv, compressDWARF)
        }
  
        if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
                // GCC uses -no-pie, clang uses -nopie.
                for _, nopie := range []string{"-no-pie", "-nopie"} {
-                       if linkerFlagSupported(argv[0], nopie) {
+                       if linkerFlagSupported(argv[0], altLinker, nopie) {
                                argv = append(argv, nopie)
                                break
                        }
  
  var createTrivialCOnce sync.Once
  
- func linkerFlagSupported(linker, flag string) bool {
+ func linkerFlagSupported(linker, altLinker, flag string) bool {
        createTrivialCOnce.Do(func() {
                src := filepath.Join(*flagTmpdir, "trivial.c")
                if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
                }
        }
  
+       if altLinker != "" {
+               flags = append(flags, "-fuse-ld="+altLinker)
+       }
        flags = append(flags, flag, "trivial.c")
  
        cmd := exec.Command(linker, flags...)
@@@ -2114,7 -2126,9 +2127,9 @@@ func ldshlibsyms(ctxt *Link, shlib stri
                Errorf(nil, "cannot open shared library: %s", libpath)
                return
        }
-       defer f.Close()
+       // Keep the file open as decodetypeGcprog needs to read from it.
+       // TODO: fix. Maybe mmap the file.
+       //defer f.Close()
  
        hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
        if err != nil {
diff --combined src/crypto/hmac/hmac.go
index 52885b07608f9b9a6d4cf89b653c88cdc19a45e9,a6ba71c27560d7b2569de8b500c931d096ea25ec..2c4fc2db91786893296ce559418d8adf39fc5b92
@@@ -26,8 -26,6 +26,8 @@@ import 
        "hash"
  )
  
 +import "crypto/internal/boring"
 +
  // FIPS 198-1:
  // https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
  
  // opad = 0x5c byte repeated for key length
  // hmac = H([key ^ opad] H([key ^ ipad] text))
  
+ // Marshalable is the combination of encoding.BinaryMarshaler and
+ // encoding.BinaryUnmarshaler. Their method definitions are repeated here to
+ // avoid a dependency on the encoding package.
+ type marshalable interface {
+       MarshalBinary() ([]byte, error)
+       UnmarshalBinary([]byte) error
+ }
  type hmac struct {
-       size         int
-       blocksize    int
        opad, ipad   []byte
        outer, inner hash.Hash
+       // If marshaled is true, then opad and ipad do not contain a padded
+       // copy of the key, but rather the marshaled state of outer/inner after
+       // opad/ipad has been fed into it.
+       marshaled bool
  }
  
  func (h *hmac) Sum(in []byte) []byte {
        origLen := len(in)
        in = h.inner.Sum(in)
-       h.outer.Reset()
-       h.outer.Write(h.opad)
+       if h.marshaled {
+               if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
+                       panic(err)
+               }
+       } else {
+               h.outer.Reset()
+               h.outer.Write(h.opad)
+       }
        h.outer.Write(in[origLen:])
        return h.outer.Sum(in[:origLen])
  }
@@@ -56,13 -72,51 +74,51 @@@ func (h *hmac) Write(p []byte) (n int, 
        return h.inner.Write(p)
  }
  
- func (h *hmac) Size() int { return h.size }
- func (h *hmac) BlockSize() int { return h.blocksize }
+ func (h *hmac) Size() int      { return h.outer.Size() }
+ func (h *hmac) BlockSize() int { return h.inner.BlockSize() }
  
  func (h *hmac) Reset() {
+       if h.marshaled {
+               if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
+                       panic(err)
+               }
+               return
+       }
        h.inner.Reset()
        h.inner.Write(h.ipad)
+       // If the underlying hash is marshalable, we can save some time by
+       // saving a copy of the hash state now, and restoring it on future
+       // calls to Reset and Sum instead of writing ipad/opad every time.
+       //
+       // If either hash is unmarshalable for whatever reason,
+       // it's safe to bail out here.
+       marshalableInner, innerOK := h.inner.(marshalable)
+       if !innerOK {
+               return
+       }
+       marshalableOuter, outerOK := h.outer.(marshalable)
+       if !outerOK {
+               return
+       }
+       imarshal, err := marshalableInner.MarshalBinary()
+       if err != nil {
+               return
+       }
+       h.outer.Reset()
+       h.outer.Write(h.opad)
+       omarshal, err := marshalableOuter.MarshalBinary()
+       if err != nil {
+               return
+       }
+       // Marshaling succeeded; save the marshaled state for later
+       h.ipad = imarshal
+       h.opad = omarshal
+       h.marshaled = true
  }
  
  // New returns a new HMAC hash using the given hash.Hash type and key.
  // the returned Hash does not implement encoding.BinaryMarshaler
  // or encoding.BinaryUnmarshaler.
  func New(h func() hash.Hash, key []byte) hash.Hash {
 +      if boring.Enabled {
 +              hm := boring.NewHMAC(h, key)
 +              if hm != nil {
 +                      return hm
 +              }
 +              // BoringCrypto did not recognize h, so fall through to standard Go code.
 +      }
        hm := new(hmac)
        hm.outer = h()
        hm.inner = h()
-       hm.size = hm.inner.Size()
-       hm.blocksize = hm.inner.BlockSize()
-       hm.ipad = make([]byte, hm.blocksize)
-       hm.opad = make([]byte, hm.blocksize)
-       if len(key) > hm.blocksize {
+       blocksize := hm.inner.BlockSize()
+       hm.ipad = make([]byte, blocksize)
+       hm.opad = make([]byte, blocksize)
+       if len(key) > blocksize {
                // If key is too big, hash it.
                hm.outer.Write(key)
                key = hm.outer.Sum(nil)
                hm.opad[i] ^= 0x5c
        }
        hm.inner.Write(hm.ipad)
        return hm
  }
  
index 96e84f74a1ec603b5cfe099d1e51013fdc4b3123,453bfb3b7fd4425bcf4f69e95415fa5f418e6307..7be8b1bbcfc0879471a4953123c0c81c850a5b70
@@@ -5,7 -5,6 +5,7 @@@
  package hmac
  
  import (
 +      "bytes"
        "crypto/md5"
        "crypto/sha1"
        "crypto/sha256"
@@@ -519,31 -518,6 +519,31 @@@ var hmacTests = []hmacTest
                sha512.Size,
                sha512.BlockSize,
        },
 +      // HMAC without key is dumb but should probably not fail.
 +      {
 +              sha1.New,
 +              []byte{},
 +              []byte("message"),
 +              "d5d1ed05121417247616cfc8378f360a39da7cfa",
 +              sha1.Size,
 +              sha1.BlockSize,
 +      },
 +      {
 +              sha256.New,
 +              []byte{},
 +              []byte("message"),
 +              "eb08c1f56d5ddee07f7bdf80468083da06b64cf4fac64fe3a90883df5feacae4",
 +              sha256.Size,
 +              sha256.BlockSize,
 +      },
 +      {
 +              sha512.New,
 +              []byte{},
 +              []byte("message"),
 +              "08fce52f6395d59c2a3fb8abb281d74ad6f112b9a9c787bcea290d94dadbc82b2ca3e5e12bf2277c7fedbb0154d5493e41bb7459f63c8e39554ea3651b812492",
 +              sha512.Size,
 +              sha512.BlockSize,
 +      },
  }
  
  func TestHMAC(t *testing.T) {
                if b := h.BlockSize(); b != tt.blocksize {
                        t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
                }
-               for j := 0; j < 2; j++ {
+               for j := 0; j < 4; j++ {
                        n, err := h.Write(tt.in)
                        if n != len(tt.in) || err != nil {
                                t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
  
                        // Second iteration: make sure reset works.
                        h.Reset()
+                       // Third and fourth iteration: make sure hmac works on
+                       // hashes without MarshalBinary/UnmarshalBinary
+                       if j == 1 {
+                               h = New(func() hash.Hash { return justHash{tt.hash()} }, tt.key)
+                       }
                }
        }
  }
+ // justHash implements just the hash.Hash methods and nothing else
+ type justHash struct {
+       hash.Hash
+ }
  
  func TestEqual(t *testing.T) {
        a := []byte("test")
        }
  }
  
 +func TestWriteAfterSum(t *testing.T) {
 +      h := New(sha1.New, nil)
 +      h.Write([]byte("hello"))
 +      sumHello := h.Sum(nil)
 +
 +      h = New(sha1.New, nil)
 +      h.Write([]byte("hello world"))
 +      sumHelloWorld := h.Sum(nil)
 +
 +      // Test that Sum has no effect on future Sum or Write operations.
 +      // This is a bit unusual as far as usage, but it's allowed
 +      // by the definition of Go hash.Hash, and some clients expect it to work.
 +      h = New(sha1.New, nil)
 +      h.Write([]byte("hello"))
 +      if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
 +              t.Fatalf("1st Sum after hello = %x, want %x", sum, sumHello)
 +      }
 +      if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
 +              t.Fatalf("2nd Sum after hello = %x, want %x", sum, sumHello)
 +      }
 +
 +      h.Write([]byte(" world"))
 +      if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
 +              t.Fatalf("1st Sum after hello world = %x, want %x", sum, sumHelloWorld)
 +      }
 +      if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
 +              t.Fatalf("2nd Sum after hello world = %x, want %x", sum, sumHelloWorld)
 +      }
 +
 +      h.Reset()
 +      h.Write([]byte("hello"))
 +      if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
 +              t.Fatalf("Sum after Reset + hello = %x, want %x", sum, sumHello)
 +      }
 +}
 +
  func BenchmarkHMACSHA256_1K(b *testing.B) {
        key := make([]byte, 32)
        buf := make([]byte, 1024)
diff --combined src/crypto/tls/common.go
index f6fe2d2a9088780986fdc230ecab9a4dce66a51d,eb002ada2f5ea79f16d98c5e1b09a5beec6c90c1..30755bdd6ff7bc976b1333b51fdb70ce993b0bf3
@@@ -171,11 -171,11 +171,11 @@@ const 
  // hash function associated with the Ed25519 signature scheme.
  var directSigning crypto.Hash = 0
  
 -// supportedSignatureAlgorithms contains the signature and hash algorithms that
 +// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
  // the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
  // CertificateRequest. The two fields are merged to match with TLS 1.3.
  // Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
 -var supportedSignatureAlgorithms = []SignatureScheme{
 +var defaultSupportedSignatureAlgorithms = []SignatureScheme{
        PSSWithSHA256,
        ECDSAWithP256AndSHA256,
        Ed25519,
@@@ -213,28 -213,72 +213,72 @@@ var testingOnlyForceDowngradeCanary boo
  
  // ConnectionState records basic TLS details about the connection.
  type ConnectionState struct {
-       Version                     uint16                // TLS version used by the connection (e.g. VersionTLS12)
-       HandshakeComplete           bool                  // TLS handshake is complete
-       DidResume                   bool                  // connection resumes a previous TLS connection
-       CipherSuite                 uint16                // cipher suite in use (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ...)
-       NegotiatedProtocol          string                // negotiated next protocol (not guaranteed to be from Config.NextProtos)
-       NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server (client side only)
-       ServerName                  string                // server name requested by client, if any (server side only)
-       PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
-       VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
-       SignedCertificateTimestamps [][]byte              // SCTs from the peer, if any
-       OCSPResponse                []byte                // stapled OCSP response from peer, if any
+       // Version is the TLS version used by the connection (e.g. VersionTLS12).
+       Version uint16
  
-       // ekm is a closure exposed via ExportKeyingMaterial.
-       ekm func(label string, context []byte, length int) ([]byte, error)
+       // HandshakeComplete is true if the handshake has concluded.
+       HandshakeComplete bool
+       // DidResume is true if this connection was successfully resumed from a
+       // previous session with a session ticket or similar mechanism.
+       DidResume bool
+       // CipherSuite is the cipher suite negotiated for the connection (e.g.
+       // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+       CipherSuite uint16
+       // NegotiatedProtocol is the application protocol negotiated with ALPN.
+       //
+       // Note that on the client side, this is currently not guaranteed to be from
+       // Config.NextProtos.
+       NegotiatedProtocol string
+       // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+       //
+       // Deprecated: this value is always true.
+       NegotiatedProtocolIsMutual bool
  
-       // TLSUnique contains the "tls-unique" channel binding value (see RFC
-       // 5929, section 3). For resumed sessions this value will be nil
-       // because resumption does not include enough context (see
-       // https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will
-       // change in future versions of Go once the TLS master-secret fix has
-       // been standardized and implemented. It is not defined in TLS 1.3.
+       // ServerName is the value of the Server Name Indication extension sent by
+       // the client. It's available both on the server and on the client side.
+       ServerName string
+       // PeerCertificates are the parsed certificates sent by the peer, in the
+       // order in which they were sent. The first element is the leaf certificate
+       // that the connection is verified against.
+       //
+       // On the client side, it can't be empty. On the server side, it can be
+       // empty if Config.ClientAuth is not RequireAnyClientCert or
+       // RequireAndVerifyClientCert.
+       PeerCertificates []*x509.Certificate
+       // VerifiedChains is a list of one or more chains where the first element is
+       // PeerCertificates[0] and the last element is from Config.RootCAs (on the
+       // client side) or Config.ClientCAs (on the server side).
+       //
+       // On the client side, it's set if Config.InsecureSkipVerify is false. On
+       // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+       // (and the peer provided a certificate) or RequireAndVerifyClientCert.
+       VerifiedChains [][]*x509.Certificate
+       // SignedCertificateTimestamps is a list of SCTs provided by the peer
+       // through the TLS handshake for the leaf certificate, if any.
+       SignedCertificateTimestamps [][]byte
+       // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP)
+       // response provided by the peer for the leaf certificate, if any.
+       OCSPResponse []byte
+       // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+       // Section 3). This value will be nil for TLS 1.3 connections and for all
+       // resumed connections.
+       //
+       // Deprecated: there are conditions in which this value might not be unique
+       // to a connection. See the Security Considerations sections of RFC 5705 and
+       // RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
        TLSUnique []byte
+       // ekm is a closure exposed via ExportKeyingMaterial.
+       ekm func(label string, context []byte, length int) ([]byte, error)
  }
  
  // ExportKeyingMaterial returns length bytes of exported key material in a new
@@@ -278,6 -322,8 +322,8 @@@ type ClientSessionState struct 
        serverCertificates []*x509.Certificate   // Certificate chain presented by the server
        verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
        receivedAt         time.Time             // When the session ticket was received from the server
+       ocspResponse       []byte                // Stapled OCSP response presented by the server
+       scts               [][]byte              // SCTs presented by the server
  
        // TLS 1.3 fields.
        nonce  []byte    // Ticket nonce sent by the server, to derive PSK
@@@ -501,15 -547,10 +547,10 @@@ type Config struct 
        // If GetConfigForClient is nil, the Config passed to Server() will be
        // used for all connections.
        //
-       // Uniquely for the fields in the returned Config, session ticket keys
-       // will be duplicated from the original Config if not set.
-       // Specifically, if SetSessionTicketKeys was called on the original
-       // config but not on the returned config then the ticket keys from the
-       // original config will be copied into the new config before use.
-       // Otherwise, if SessionTicketKey was set in the original config but
-       // not in the returned config then it will be copied into the returned
-       // config before use. If neither of those cases applies then the key
-       // material from the returned config will be used for session tickets.
+       // If SessionTicketKey was explicitly set on the returned Config, or if
+       // SetSessionTicketKeys was called on the returned Config, those keys will
+       // be used. Otherwise, the original Config keys will be used (and possibly
+       // rotated if they are automatically managed).
        GetConfigForClient func(*ClientHelloInfo) (*Config, error)
  
        // VerifyPeerCertificate, if not nil, is called after normal
        // be considered but the verifiedChains argument will always be nil.
        VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
  
+       // VerifyConnection, if not nil, is called after normal certificate
+       // verification and after VerifyPeerCertificate by either a TLS client
+       // or server. If it returns a non-nil error, the handshake is aborted
+       // and that error results.
+       //
+       // If normal verification fails then the handshake will abort before
+       // considering this callback. This callback will run for all connections
+       // regardless of InsecureSkipVerify or ClientAuth settings.
+       VerifyConnection func(ConnectionState) error
        // RootCAs defines the set of root certificate authorities
        // that clients use when verifying server certificates.
        // If RootCAs is nil, TLS uses the host's root CA set.
        // See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
        // with random data before the first server handshake.
        //
-       // If multiple servers are terminating connections for the same host
-       // they should all have the same SessionTicketKey. If the
-       // SessionTicketKey leaks, previously recorded and future TLS
-       // connections using that key might be compromised.
+       // Deprecated: if this field is left at zero, session ticket keys will be
+       // automatically rotated every day and dropped after seven days. For
+       // customizing the rotation schedule or synchronizing servers that are
+       // terminating connections for the same host, use SetSessionTicketKeys.
        SessionTicketKey [32]byte
  
        // ClientSessionCache is a cache of ClientSessionState entries for TLS
        // used for debugging.
        KeyLogWriter io.Writer
  
-       serverInitOnce sync.Once // guards calling (*Config).serverInit
-       // mutex protects sessionTicketKeys.
+       // mutex protects sessionTicketKeys and autoSessionTicketKeys.
        mutex sync.RWMutex
-       // sessionTicketKeys contains zero or more ticket keys. If the length
-       // is zero, SessionTicketsDisabled must be true. The first key is used
-       // for new tickets and any subsequent keys can be used to decrypt old
-       // tickets.
+       // sessionTicketKeys contains zero or more ticket keys. If set, it means the
+       // the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+       // first key is used for new tickets and any subsequent keys can be used to
+       // decrypt old tickets. The slice contents are not protected by the mutex
+       // and are immutable.
        sessionTicketKeys []ticketKey
+       // autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+       // auto-rotation logic. See Config.ticketKeys.
+       autoSessionTicketKeys []ticketKey
  }
  
- // ticketKeyNameLen is the number of bytes of identifier that is prepended to
- // an encrypted session ticket in order to identify the key used to encrypt it.
- const ticketKeyNameLen = 16
+ const (
+       // ticketKeyNameLen is the number of bytes of identifier that is prepended to
+       // an encrypted session ticket in order to identify the key used to encrypt it.
+       ticketKeyNameLen = 16
+       // ticketKeyLifetime is how long a ticket key remains valid and can be used to
+       // resume a client connection.
+       ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+       // ticketKeyRotation is how often the server should rotate the session ticket key
+       // that is used for new tickets.
+       ticketKeyRotation = 24 * time.Hour
+ )
  
  // ticketKey is the internal representation of a session ticket key.
  type ticketKey struct {
        keyName [ticketKeyNameLen]byte
        aesKey  [16]byte
        hmacKey [16]byte
+       // created is the time at which this ticket key was created. See Config.ticketKeys.
+       created time.Time
  }
  
  // ticketKeyFromBytes converts from the external representation of a session
  // ticket key to a ticketKey. Externally, session ticket keys are 32 random
  // bytes and this function expands that into sufficient name and key material.
- func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+ func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
        hashed := sha512.Sum512(b[:])
        copy(key.keyName[:], hashed[:ticketKeyNameLen])
        copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
        copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+       key.created = c.time()
        return key
  }
  
@@@ -664,15 -730,8 +730,8 @@@ const maxSessionTicketLifetime = 7 * 2
  // Clone returns a shallow clone of c. It is safe to clone a Config that is
  // being used concurrently by a TLS client or server.
  func (c *Config) Clone() *Config {
-       // Running serverInit ensures that it's safe to read
-       // SessionTicketsDisabled.
-       c.serverInitOnce.Do(func() { c.serverInit(nil) })
-       var sessionTicketKeys []ticketKey
        c.mutex.RLock()
-       sessionTicketKeys = c.sessionTicketKeys
-       c.mutex.RUnlock()
+       defer c.mutex.RUnlock()
        return &Config{
                Rand:                        c.Rand,
                Time:                        c.Time,
                GetClientCertificate:        c.GetClientCertificate,
                GetConfigForClient:          c.GetConfigForClient,
                VerifyPeerCertificate:       c.VerifyPeerCertificate,
+               VerifyConnection:            c.VerifyConnection,
                RootCAs:                     c.RootCAs,
                NextProtos:                  c.NextProtos,
                ServerName:                  c.ServerName,
                DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
                Renegotiation:               c.Renegotiation,
                KeyLogWriter:                c.KeyLogWriter,
-               sessionTicketKeys:           sessionTicketKeys,
+               sessionTicketKeys:           c.sessionTicketKeys,
+               autoSessionTicketKeys:       c.autoSessionTicketKeys,
        }
  }
  
- // serverInit is run under c.serverInitOnce to do initialization of c. If c was
- // returned by a GetConfigForClient callback then the argument should be the
- // Config that was passed to Server, otherwise it should be nil.
- func (c *Config) serverInit(originalConfig *Config) {
-       if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
+ // deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was
+ // randomized for backwards compatibility but is not in use.
+ var deprecatedSessionTicketKey = []byte("DEPRECATED")
+ // initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is
+ // randomized if empty, and that sessionTicketKeys is populated from it otherwise.
+ func (c *Config) initLegacySessionTicketKeyRLocked() {
+       // Don't write if SessionTicketKey is already defined as our deprecated string,
+       // or if it is defined by the user but sessionTicketKeys is already set.
+       if c.SessionTicketKey != [32]byte{} &&
+               (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
                return
        }
  
-       alreadySet := false
-       for _, b := range c.SessionTicketKey {
-               if b != 0 {
-                       alreadySet = true
-                       break
+       // We need to write some data, so get an exclusive lock and re-check any conditions.
+       c.mutex.RUnlock()
+       defer c.mutex.RLock()
+       c.mutex.Lock()
+       defer c.mutex.Unlock()
+       if c.SessionTicketKey == [32]byte{} {
+               if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+                       panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
                }
+               // Write the deprecated prefix at the beginning so we know we created
+               // it. This key with the DEPRECATED prefix isn't used as an actual
+               // session ticket key, and is only randomized in case the application
+               // reuses it for some reason.
+               copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
+       } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
+               c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
        }
  
-       if !alreadySet {
-               if originalConfig != nil {
-                       copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
-               } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
-                       c.SessionTicketsDisabled = true
-                       return
+ }
+ // ticketKeys returns the ticketKeys for this connection.
+ // If configForClient has explicitly set keys, those will
+ // be returned. Otherwise, the keys on c will be used and
+ // may be rotated if auto-managed.
+ // During rotation, any expired session ticket keys are deleted from
+ // c.sessionTicketKeys. If the session ticket key that is currently
+ // encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys)
+ // is not fresh, then a new session ticket key will be
+ // created and prepended to c.sessionTicketKeys.
+ func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
+       // If the ConfigForClient callback returned a Config with explicitly set
+       // keys, use those, otherwise just use the original Config.
+       if configForClient != nil {
+               configForClient.mutex.RLock()
+               if configForClient.SessionTicketsDisabled {
+                       return nil
                }
+               configForClient.initLegacySessionTicketKeyRLocked()
+               if len(configForClient.sessionTicketKeys) != 0 {
+                       ret := configForClient.sessionTicketKeys
+                       configForClient.mutex.RUnlock()
+                       return ret
+               }
+               configForClient.mutex.RUnlock()
        }
  
-       if originalConfig != nil {
-               originalConfig.mutex.RLock()
-               c.sessionTicketKeys = originalConfig.sessionTicketKeys
-               originalConfig.mutex.RUnlock()
-       } else {
-               c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+       c.mutex.RLock()
+       defer c.mutex.RUnlock()
+       if c.SessionTicketsDisabled {
+               return nil
+       }
+       c.initLegacySessionTicketKeyRLocked()
+       if len(c.sessionTicketKeys) != 0 {
+               return c.sessionTicketKeys
+       }
+       // Fast path for the common case where the key is fresh enough.
+       if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
+               return c.autoSessionTicketKeys
        }
- }
  
- func (c *Config) ticketKeys() []ticketKey {
-       c.mutex.RLock()
-       // c.sessionTicketKeys is constant once created. SetSessionTicketKeys
-       // will only update it by replacing it with a new value.
-       ret := c.sessionTicketKeys
+       // autoSessionTicketKeys are managed by auto-rotation.
        c.mutex.RUnlock()
-       return ret
+       defer c.mutex.RLock()
+       c.mutex.Lock()
+       defer c.mutex.Unlock()
+       // Re-check the condition in case it changed since obtaining the new lock.
+       if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
+               var newKey [32]byte
+               if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
+                       panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
+               }
+               valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
+               valid = append(valid, c.ticketKeyFromBytes(newKey))
+               for _, k := range c.autoSessionTicketKeys {
+                       // While rotating the current key, also remove any expired ones.
+                       if c.time().Sub(k.created) < ticketKeyLifetime {
+                               valid = append(valid, k)
+                       }
+               }
+               c.autoSessionTicketKeys = valid
+       }
+       return c.autoSessionTicketKeys
  }
  
- // SetSessionTicketKeys updates the session ticket keys for a server. The first
- // key will be used when creating new tickets, while all keys can be used for
- // decrypting tickets. It is safe to call this function while the server is
- // running in order to rotate the session ticket keys. The function will panic
- // if keys is empty.
+ // SetSessionTicketKeys updates the session ticket keys for a server.
+ //
+ // The first key will be used when creating new tickets, while all keys can be
+ // used for decrypting tickets. It is safe to call this function while the
+ // server is running in order to rotate the session ticket keys. The function
+ // will panic if keys is empty.
+ //
+ // Calling this function will turn off automatic session ticket key rotation.
+ //
+ // If multiple servers are terminating connections for the same host they should
+ // all have the same session ticket keys. If the session ticket keys leaks,
+ // previously recorded and future TLS connections using those keys might be
+ // compromised.
  func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
        if len(keys) == 0 {
                panic("tls: keys must have at least one key")
  
        newKeys := make([]ticketKey, len(keys))
        for i, bytes := range keys {
-               newKeys[i] = ticketKeyFromBytes(bytes)
+               newKeys[i] = c.ticketKeyFromBytes(bytes)
        }
  
        c.mutex.Lock()
@@@ -783,9 -907,6 +907,9 @@@ func (c *Config) time() time.Time 
  }
  
  func (c *Config) cipherSuites() []uint16 {
 +      if needFIPS() {
 +              return fipsCipherSuites(c)
 +      }
        s := c.CipherSuites
        if s == nil {
                s = defaultCipherSuites()
@@@ -803,9 -924,6 +927,9 @@@ var supportedVersions = []uint16
  func (c *Config) supportedVersions() []uint16 {
        versions := make([]uint16, 0, len(supportedVersions))
        for _, v := range supportedVersions {
 +              if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
 +                      continue
 +              }
                if c != nil && c.MinVersion != 0 && v < c.MinVersion {
                        continue
                }
@@@ -842,9 -960,6 +966,9 @@@ func supportedVersionsFromMax(maxVersio
  var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
  
  func (c *Config) curvePreferences() []CurveID {
 +      if needFIPS() {
 +              return fipsCurvePreferences(c)
 +      }
        if c == nil || len(c.CurvePreferences) == 0 {
                return defaultCurvePreferences
        }
@@@ -1314,8 -1429,7 +1438,8 @@@ func initDefaultCipherSuites() 
                hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
        )
  
 -      if hasGCMAsm {
 +      if hasGCMAsm || boringEnabled {
 +              // If BoringCrypto is enabled, always prioritize AES-GCM.
                // If AES-GCM hardware is provided then prioritise AES-GCM
                // cipher suites.
                topCipherSuites = []uint16{
index a72555f66e62d83b46e73cf243da8e35a7907b20,46b0a770d5309436660038f77b3f6d08e32eaa60..e089762b9f9a635ef396fde94afa808075d64bcc
@@@ -112,10 -112,7 +112,10 @@@ func (c *Conn) makeClientHello() (*clie
        }
  
        if hello.vers >= VersionTLS12 {
 -              hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
 +              hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
 +      }
 +      if testingOnlyForceClientHelloSignatureAlgorithms != nil {
 +              hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
        }
  
        var params ecdheParameters
@@@ -149,6 -146,7 +149,7 @@@ func (c *Conn) clientHandshake() (err e
        if err != nil {
                return err
        }
+       c.serverName = hello.serverName
  
        cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
        if cacheKey != "" && session != nil {
@@@ -391,6 -389,7 +392,7 @@@ func (hs *clientHandshakeState) handsha
        hs.finishedHash.Write(hs.serverHello.marshal())
  
        c.buffering = true
+       c.didResume = isResume
        if isResume {
                if err := hs.establishKeys(); err != nil {
                        return err
                        return err
                }
                c.clientFinishedIsFirst = false
+               // Make sure the connection is still being verified whether or not this
+               // is a resumption. Resumptions currently don't reverify certificates so
+               // they don't call verifyServerCertificate. See Issue 31641.
+               if c.config.VerifyConnection != nil {
+                       if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                               c.sendAlert(alertBadCertificate)
+                               return err
+                       }
+               }
                if err := hs.sendFinished(c.clientFinished[:]); err != nil {
                        return err
                }
        }
  
        c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
-       c.didResume = isResume
        atomic.StoreUint32(&c.handshakeStatus, 1)
  
        return nil
@@@ -461,25 -468,6 +471,6 @@@ func (hs *clientHandshakeState) doFullH
        }
        hs.finishedHash.Write(certMsg.marshal())
  
-       if c.handshakes == 0 {
-               // If this is the first handshake on a connection, process and
-               // (optionally) verify the server's certificates.
-               if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
-                       return err
-               }
-       } else {
-               // This is a renegotiation handshake. We require that the
-               // server's identity (i.e. leaf certificate) is unchanged and
-               // thus any previous trust decision is still valid.
-               //
-               // See https://mitls.org/pages/attacks/3SHAKE for the
-               // motivation behind this requirement.
-               if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
-                       c.sendAlert(alertBadCertificate)
-                       return errors.New("tls: server's identity changed during renegotiation")
-               }
-       }
        msg, err = c.readHandshake()
        if err != nil {
                return err
                }
        }
  
+       if c.handshakes == 0 {
+               // If this is the first handshake on a connection, process and
+               // (optionally) verify the server's certificates.
+               if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
+                       return err
+               }
+       } else {
+               // This is a renegotiation handshake. We require that the
+               // server's identity (i.e. leaf certificate) is unchanged and
+               // thus any previous trust decision is still valid.
+               //
+               // See https://mitls.org/pages/attacks/3SHAKE for the
+               // motivation behind this requirement.
+               if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+                       c.sendAlert(alertBadCertificate)
+                       return errors.New("tls: server's identity changed during renegotiation")
+               }
+       }
        keyAgreement := hs.suite.ka(c.vers)
  
        skx, ok := msg.(*serverKeyExchangeMsg)
@@@ -721,10 -728,17 +731,17 @@@ func (hs *clientHandshakeState) process
                return false, errors.New("tls: server resumed a session with a different cipher suite")
        }
  
-       // Restore masterSecret and peerCerts from previous state
+       // Restore masterSecret, peerCerts, and ocspResponse from previous state
        hs.masterSecret = hs.session.masterSecret
        c.peerCertificates = hs.session.serverCertificates
        c.verifiedChains = hs.session.verifiedChains
+       c.ocspResponse = hs.session.ocspResponse
+       // Let the ServerHello SCTs override the session SCTs from the original
+       // connection, if any are provided
+       if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+               c.scts = hs.session.scts
+       }
        return true, nil
  }
  
@@@ -781,6 -795,8 +798,8 @@@ func (hs *clientHandshakeState) readSes
                serverCertificates: c.peerCertificates,
                verifiedChains:     c.verifiedChains,
                receivedAt:         c.config.time(),
+               ocspResponse:       c.ocspResponse,
+               scts:               c.scts,
        }
  
        return nil
@@@ -818,8 -834,6 +837,8 @@@ func (c *Conn) verifyServerCertificate(
  
        if !c.config.InsecureSkipVerify {
                opts := x509.VerifyOptions{
 +                      IsBoring: isBoringCertificate,
 +
                        Roots:         c.config.RootCAs,
                        CurrentTime:   c.config.time(),
                        DNSName:       c.config.ServerName,
                }
        }
  
-       if c.config.VerifyPeerCertificate != nil {
-               if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
-                       c.sendAlert(alertBadCertificate)
-                       return err
-               }
-       }
        switch certs[0].PublicKey.(type) {
        case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
                break
  
        c.peerCertificates = certs
  
+       if c.config.VerifyPeerCertificate != nil {
+               if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return err
+               }
+       }
+       if c.config.VerifyConnection != nil {
+               if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return err
+               }
+       }
        return nil
  }
  
index c454d7f9ac5669dee7546ca9c45f67f5fa8a4647,9c61105cf73d02b18b3c110c15777146d515677b..fab26b246a04bdd02bba88b6fdcc7967dbe7348d
@@@ -39,10 -39,6 +39,10 @@@ type clientHandshakeStateTLS13 struct 
  func (hs *clientHandshakeStateTLS13) handshake() error {
        c := hs.c
  
 +      if needFIPS() {
 +              return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
 +      }
 +
        // The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
        // sections 4.1.2 and 4.1.3.
        if c.handshakes > 0 {
@@@ -338,6 -334,8 +338,8 @@@ func (hs *clientHandshakeStateTLS13) pr
        c.didResume = true
        c.peerCertificates = hs.session.serverCertificates
        c.verifiedChains = hs.session.verifiedChains
+       c.ocspResponse = hs.session.ocspResponse
+       c.scts = hs.session.scts
        return nil
  }
  
@@@ -411,6 -409,15 +413,15 @@@ func (hs *clientHandshakeStateTLS13) re
        // Either a PSK or a certificate is always used, but not both.
        // See RFC 8446, Section 4.1.1.
        if hs.usingPSK {
+               // Make sure the connection is still being verified whether or not this
+               // is a resumption. Resumptions currently don't reverify certificates so
+               // they don't call verifyServerCertificate. See Issue 31641.
+               if c.config.VerifyConnection != nil {
+                       if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                               c.sendAlert(alertBadCertificate)
+                               return err
+                       }
+               }
                return nil
        }
  
        }
  
        // See RFC 8446, Section 4.4.3.
 -      if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
 +      if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
                c.sendAlert(alertIllegalParameter)
                return errors.New("tls: certificate used with invalid signature algorithm")
        }
@@@ -661,6 -668,8 +672,8 @@@ func (c *Conn) handleNewSessionTicket(m
                nonce:              msg.nonce,
                useBy:              c.config.time().Add(lifetime),
                ageAdd:             msg.ageAdd,
+               ocspResponse:       c.ocspResponse,
+               scts:               c.scts,
        }
  
        cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
index 49fd42d8dea772bec4172ee04bf7f7f03e543a1b,bb8aea86700509d82222e73ae6f30eedb59ef1f7..8821670e9ae432803fce44b136f502c2aa020d60
@@@ -147,10 -147,10 +147,10 @@@ func (*clientHelloMsg) Generate(rand *r
                }
        }
        if rand.Intn(10) > 5 {
 -              m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
 +              m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
 -              m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
 +              m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
        }
        for i := 0; i < rand.Intn(5); i++ {
                m.alpnProtocols = append(m.alpnProtocols, randomString(rand.Intn(20)+1, rand))
@@@ -309,6 -309,7 +309,7 @@@ func (*sessionState) Generate(rand *ran
        s.vers = uint16(rand.Intn(10000))
        s.cipherSuite = uint16(rand.Intn(10000))
        s.masterSecret = randomBytes(rand.Intn(100)+1, rand)
+       s.createdAt = uint64(rand.Int63())
        for i := 0; i < rand.Intn(20); i++ {
                s.certificates = append(s.certificates, randomBytes(rand.Intn(500)+1, rand))
        }
@@@ -368,10 -369,10 +369,10 @@@ func (*certificateRequestMsgTLS13) Gene
                m.scts = true
        }
        if rand.Intn(10) > 5 {
 -              m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
 +              m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
 -              m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
 +              m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
                m.certificateAuthorities = make([][]byte, 3)
index 0e0856c2242a006401c5bf597bf9fd6cba4b932e,16d3e643f0b28ed45936142e6dacdb56385ee480..99e30b884566d4ad3ef1930cce5ae4cad2ae8a55
@@@ -15,6 -15,7 +15,7 @@@ import 
        "fmt"
        "io"
        "sync/atomic"
+       "time"
  )
  
  // serverHandshakeState contains details of a server handshake in progress.
@@@ -36,10 -37,6 +37,6 @@@ type serverHandshakeState struct 
  
  // serverHandshake performs a TLS handshake as a server.
  func (c *Conn) serverHandshake() error {
-       // If this is the first server handshake, we generate a random key to
-       // encrypt the tickets with.
-       c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
        clientHello, err := c.readClientHello()
        if err != nil {
                return err
@@@ -71,19 -68,15 +68,15 @@@ func (hs *serverHandshakeState) handsha
        c.buffering = true
        if hs.checkForResumption() {
                // The client has included a session ticket and so we do an abbreviated handshake.
+               c.didResume = true
                if err := hs.doResumeHandshake(); err != nil {
                        return err
                }
                if err := hs.establishKeys(); err != nil {
                        return err
                }
-               // ticketSupported is set in a resumption handshake if the
-               // ticket from the client was encrypted with an old session
-               // ticket key and thus a refreshed ticket should be sent.
-               if hs.hello.ticketSupported {
-                       if err := hs.sendSessionTicket(); err != nil {
-                               return err
-                       }
+               if err := hs.sendSessionTicket(); err != nil {
+                       return err
                }
                if err := hs.sendFinished(c.serverFinished[:]); err != nil {
                        return err
@@@ -95,7 -88,6 +88,6 @@@
                if err := hs.readFinished(nil); err != nil {
                        return err
                }
-               c.didResume = true
        } else {
                // The client didn't include a session ticket, or it wasn't
                // valid so we do a full handshake.
@@@ -142,16 -134,18 +134,18 @@@ func (c *Conn) readClientHello() (*clie
                return nil, unexpectedMessageError(clientHello, msg)
        }
  
+       var configForClient *Config
+       originalConfig := c.config
        if c.config.GetConfigForClient != nil {
                chi := clientHelloInfo(c, clientHello)
-               if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
+               if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
                        c.sendAlert(alertInternalError)
                        return nil, err
-               } else if newConfig != nil {
-                       newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
-                       c.config = newConfig
+               } else if configForClient != nil {
+                       c.config = configForClient
                }
        }
+       c.ticketKeys = originalConfig.ticketKeys(configForClient)
  
        clientVersions := clientHello.supportedVersions
        if len(clientHello.supportedVersions) == 0 {
@@@ -314,6 -308,7 +308,7 @@@ func (hs *serverHandshakeState) pickCip
                c.sendAlert(alertHandshakeFailure)
                return errors.New("tls: no cipher suite supported by both client and server")
        }
+       c.cipherSuite = hs.suite.id
  
        for _, id := range hs.clientHello.cipherSuites {
                if id == TLS_FALLBACK_SCSV {
@@@ -368,6 -363,11 +363,11 @@@ func (hs *serverHandshakeState) checkFo
                return false
        }
  
+       createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
+       if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+               return false
+       }
        // Never resume a session for a different TLS version.
        if c.vers != hs.sessionState.vers {
                return false
@@@ -408,6 -408,7 +408,7 @@@ func (hs *serverHandshakeState) doResum
        c := hs.c
  
        hs.hello.cipherSuite = hs.suite.id
+       c.cipherSuite = hs.suite.id
        // We echo the client's session ID in the ServerHello to let it know
        // that we're doing a resumption.
        hs.hello.sessionId = hs.clientHello.sessionId
                return err
        }
  
+       if c.config.VerifyConnection != nil {
+               if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return err
+               }
+       }
        hs.masterSecret = hs.sessionState.masterSecret
  
        return nil
@@@ -492,7 -500,7 +500,7 @@@ func (hs *serverHandshakeState) doFullH
                }
                if c.vers >= VersionTLS12 {
                        certReq.hasSignatureAlgorithm = true
 -                      certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
 +                      certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
                }
  
                // An empty list of certificateAuthorities signals to
                        return err
                }
        }
+       if c.config.VerifyConnection != nil {
+               if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return err
+               }
+       }
  
        // Get client key exchange
        ckx, ok := msg.(*clientKeyExchangeMsg)
@@@ -675,6 -689,9 +689,9 @@@ func (hs *serverHandshakeState) readFin
  }
  
  func (hs *serverHandshakeState) sendSessionTicket() error {
+       // ticketSupported is set in a resumption handshake if the
+       // ticket from the client was encrypted with an old session
+       // ticket key and thus a refreshed ticket should be sent.
        if !hs.hello.ticketSupported {
                return nil
        }
        c := hs.c
        m := new(newSessionTicketMsg)
  
+       createdAt := uint64(c.config.time().Unix())
+       if hs.sessionState != nil {
+               // If this is re-wrapping an old key, then keep
+               // the original time it was created.
+               createdAt = hs.sessionState.createdAt
+       }
        var certsFromClient [][]byte
        for _, cert := range c.peerCertificates {
                certsFromClient = append(certsFromClient, cert.Raw)
        state := sessionState{
                vers:         c.vers,
                cipherSuite:  hs.suite.id,
+               createdAt:    createdAt,
                masterSecret: hs.masterSecret,
                certificates: certsFromClient,
        }
@@@ -720,7 -745,6 +745,6 @@@ func (hs *serverHandshakeState) sendFin
                return err
        }
  
-       c.cipherSuite = hs.suite.id
        copy(out, finished.verifyData)
  
        return nil
@@@ -747,8 -771,6 +771,8 @@@ func (c *Conn) processCertsFromClient(c
  
        if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
                opts := x509.VerifyOptions{
 +                      IsBoring: isBoringCertificate,
 +
                        Roots:         c.config.ClientCAs,
                        CurrentTime:   c.config.time(),
                        Intermediates: x509.NewCertPool(),
                c.verifiedChains = chains
        }
  
+       c.peerCertificates = certs
+       c.ocspResponse = certificate.OCSPStaple
+       c.scts = certificate.SignedCertificateTimestamps
+       if len(certs) > 0 {
+               switch certs[0].PublicKey.(type) {
+               case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+               default:
+                       c.sendAlert(alertUnsupportedCertificate)
+                       return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+               }
+       }
        if c.config.VerifyPeerCertificate != nil {
                if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
                        c.sendAlert(alertBadCertificate)
                }
        }
  
-       if len(certs) == 0 {
-               return nil
-       }
-       switch certs[0].PublicKey.(type) {
-       case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
-       default:
-               c.sendAlert(alertUnsupportedCertificate)
-               return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
-       }
-       c.peerCertificates = certs
-       c.ocspResponse = certificate.OCSPStaple
-       c.scts = certificate.SignedCertificateTimestamps
        return nil
  }
  
index 95dd8a60ea8daf739b297ce1f9f5479a546c7042,92d55e0293a46e9d362fc7ec34db9fd990fe3932..7a84efd2a9c52ff884643697fa56d4ba278ea187
@@@ -42,10 -42,6 +42,10 @@@ type serverHandshakeStateTLS13 struct 
  func (hs *serverHandshakeStateTLS13) handshake() error {
        c := hs.c
  
 +      if needFIPS() {
 +              return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
 +      }
 +
        // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
        if err := hs.processClientHello(); err != nil {
                return err
@@@ -310,6 -306,7 +310,7 @@@ func (hs *serverHandshakeStateTLS13) ch
                        return errors.New("tls: invalid PSK binder")
                }
  
+               c.didResume = true
                if err := c.processCertsFromClient(sessionState.certificate); err != nil {
                        return err
                }
                hs.hello.selectedIdentityPresent = true
                hs.hello.selectedIdentity = uint16(i)
                hs.usingPSK = true
-               c.didResume = true
                return nil
        }
  
@@@ -588,7 -584,7 +588,7 @@@ func (hs *serverHandshakeStateTLS13) se
                certReq := new(certificateRequestMsgTLS13)
                certReq.ocspStapling = true
                certReq.scts = true
 -              certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
 +              certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
                if c.config.ClientCAs != nil {
                        certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
                }
@@@ -757,6 -753,14 +757,14 @@@ func (hs *serverHandshakeStateTLS13) re
        c := hs.c
  
        if !hs.requestClientCert() {
+               // Make sure the connection is still being verified whether or not
+               // the server requested a client certificate.
+               if c.config.VerifyConnection != nil {
+                       if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                               c.sendAlert(alertBadCertificate)
+                               return err
+                       }
+               }
                return nil
        }
  
                return err
        }
  
+       if c.config.VerifyConnection != nil {
+               if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return err
+               }
+       }
        if len(certMsg.certificate.Certificate) != 0 {
                msg, err = c.readHandshake()
                if err != nil {
                }
  
                // See RFC 8446, Section 4.4.3.
 -              if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
 +              if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
                        c.sendAlert(alertIllegalParameter)
                        return errors.New("tls: client certificate used with invalid signature algorithm")
                }
index e01f55733ce91aac18303a1ab1256986ff45ca52,be11e730e52c2c68dcdba4d6253585226fcf942f..d47f8382ae2156bfa11c3dae3b2171ec54bba673
@@@ -19,7 -19,7 +19,7 @@@ import 
  )
  
  // ignoreCN disables interpreting Common Name as a hostname. See issue 24151.
- var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1")
+ var ignoreCN = !strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=0")
  
  type InvalidReason int
  
@@@ -48,9 -48,9 +48,9 @@@ const 
        // contains name constraints, and the Common Name can be interpreted as
        // a hostname.
        //
-       // You can avoid this error by setting the experimental GODEBUG environment
-       // variable to "x509ignoreCN=1", disabling Common Name matching entirely.
-       // This behavior might become the default in the future.
+       // This error is only returned when legacy Common Name matching is enabled
+       // by setting the GODEBUG environment variable to "x509ignoreCN=1". This
+       // setting might be removed in the future.
        NameConstraintsWithoutSANs
        // UnconstrainedName results when a CA certificate contains permitted
        // name constraints, but leaf certificate contains a name of an
@@@ -109,10 -109,16 +109,16 @@@ type HostnameError struct 
  func (h HostnameError) Error() string {
        c := h.Certificate
  
-       if !c.hasSANExtension() && !validHostname(c.Subject.CommonName) &&
-               matchHostnames(toLowerCaseASCII(c.Subject.CommonName), toLowerCaseASCII(h.Host)) {
-               // This would have validated, if it weren't for the validHostname check on Common Name.
-               return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+       if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
+               if !ignoreCN && !validHostnamePattern(c.Subject.CommonName) {
+                       // This would have validated, if it weren't for the validHostname check on Common Name.
+                       return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+               }
+               if ignoreCN && validHostnamePattern(c.Subject.CommonName) {
+                       // This would have validated if x509ignoreCN=0 were set.
+                       return "x509: certificate relies on legacy Common Name field, " +
+                               "use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0"
+               }
        }
  
        var valid string
@@@ -187,11 -193,6 +193,11 @@@ var errNotParsed = errors.New("x509: mi
  
  // VerifyOptions contains parameters for Certificate.Verify.
  type VerifyOptions struct {
 +      // IsBoring is a validity check for BoringCrypto.
 +      // If not nil, it will be called to check whether a given certificate
 +      // can be used for constructing verification chains.
 +      IsBoring func(*Certificate) bool
 +
        // DNSName, if set, is checked against the leaf certificate with
        // Certificate.VerifyHostname.
        DNSName string
@@@ -726,13 -727,6 +732,13 @@@ func (c *Certificate) isValid(certType 
                }
        }
  
 +      if opts.IsBoring != nil && !opts.IsBoring(c) {
 +              // IncompatibleUsage is not quite right here,
 +              // but it's also the "no chains found" error
 +              // and is close enough.
 +              return CertificateInvalidError{c, IncompatibleUsage, ""}
 +      }
 +
        return nil
  }
  
  // the name being validated. Note that DirectoryName constraints are not
  // supported.
  //
+ // Name constraint validation follows the rules from RFC 5280, with the
+ // addition that DNS name constraints may use the leading period format
+ // defined for emails and URIs. When a constraint has a leading period
+ // it indicates that at least one additional label must be prepended to
+ // the constrained name to be considered valid.
+ //
  // Extended Key Usage values are enforced down a chain, so an intermediate or
  // root that enumerates EKUs prevents a leaf from asserting an EKU not in that
  // list.
@@@ -908,12 -908,16 +920,16 @@@ func (c *Certificate) buildChains(cach
        return
  }
  
+ func validHostnamePattern(host string) bool { return validHostname(host, true) }
+ func validHostnameInput(host string) bool   { return validHostname(host, false) }
  // validHostname reports whether host is a valid hostname that can be matched or
  // matched against according to RFC 6125 2.2, with some leniency to accommodate
  // legacy values.
- func validHostname(host string) bool {
-       host = strings.TrimSuffix(host, ".")
+ func validHostname(host string, isPattern bool) bool {
+       if !isPattern {
+               host = strings.TrimSuffix(host, ".")
+       }
        if len(host) == 0 {
                return false
        }
                        // Empty label.
                        return false
                }
-               if i == 0 && part == "*" {
+               if isPattern && i == 0 && part == "*" {
                        // Only allow full left-most wildcards, as those are the only ones
                        // we match, and matching literal '*' characters is probably never
                        // the expected behavior.
                        if c == '-' && j != 0 {
                                continue
                        }
-                       if c == '_' || c == ':' {
-                               // Not valid characters in hostnames, but commonly
+                       if c == '_' {
+                               // Not a valid character in hostnames, but commonly
                                // found in deployments outside the WebPKI.
                                continue
                        }
  
  // commonNameAsHostname reports whether the Common Name field should be
  // considered the hostname that the certificate is valid for. This is a legacy
- // behavior, disabled if the Subject Alt Name extension is present.
+ // behavior, disabled by default or if the Subject Alt Name extension is present.
  //
  // It applies the strict validHostname check to the Common Name field, so that
  // certificates without SANs can still be validated against CAs with name
  // constraints if there is no risk the CN would be matched as a hostname.
  // See NameConstraintsWithoutSANs and issue 24151.
  func (c *Certificate) commonNameAsHostname() bool {
-       return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName)
+       return !ignoreCN && !c.hasSANExtension() && validHostnamePattern(c.Subject.CommonName)
+ }
+ func matchExactly(hostA, hostB string) bool {
+       if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
+               return false
+       }
+       return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
  }
  
  func matchHostnames(pattern, host string) bool {
-       host = strings.TrimSuffix(host, ".")
-       pattern = strings.TrimSuffix(pattern, ".")
+       pattern = toLowerCaseASCII(pattern)
+       host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
  
        if len(pattern) == 0 || len(host) == 0 {
                return false
@@@ -1030,13 -1041,13 +1053,13 @@@ func toLowerCaseASCII(in string) strin
  //
  // IP addresses can be optionally enclosed in square brackets and are checked
  // against the IPAddresses field. Other names are checked case insensitively
- // against the DNSNames field, with support for only one wildcard as the whole
- // left-most label.
+ // against the DNSNames field. If the names are valid hostnames, the certificate
+ // fields can have a wildcard as the left-most label.
  //
- // If the Common Name field is a valid hostname, and the certificate doesn't
- // have any Subject Alternative Names, the name will also be checked against the
- // Common Name. This legacy behavior can be disabled by setting the GODEBUG
- // environment variable to "x509ignoreCN=1" and might be removed in the future.
+ // The legacy Common Name field is ignored unless it's a valid hostname, the
+ // certificate doesn't have any Subject Alternative Names, and the GODEBUG
+ // environment variable is set to "x509ignoreCN=0". Support for Common Name is
+ // deprecated will be entirely removed in the future.
  func (c *Certificate) VerifyHostname(h string) error {
        // IP addresses may be written in [ ].
        candidateIP := h
                return HostnameError{c, candidateIP}
        }
  
-       lowered := toLowerCaseASCII(h)
+       names := c.DNSNames
        if c.commonNameAsHostname() {
-               if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
-                       return nil
-               }
-       } else {
-               for _, match := range c.DNSNames {
-                       if matchHostnames(toLowerCaseASCII(match), lowered) {
+               names = []string{c.Subject.CommonName}
+       }
+       candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
+       validCandidateName := validHostnameInput(candidateName)
+       for _, match := range names {
+               // Ideally, we'd only match valid hostnames according to RFC 6125 like
+               // browsers (more or less) do, but in practice Go is used in a wider
+               // array of contexts and can't even assume DNS resolution. Instead,
+               // always allow perfect matches, and only apply wildcard and trailing
+               // dot processing to valid hostnames.
+               if validCandidateName && validHostnamePattern(match) {
+                       if matchHostnames(match, candidateName) {
+                               return nil
+                       }
+               } else {
+                       if matchExactly(match, candidateName) {
                                return nil
                        }
                }
index b8be271707a3b74dda7663b74a0291865af8c2ed,bd0ebce1c7dfbb9a994dd3fb0dec1f68ab9f78dd..62d6e6296bcb46f49313e20f359975e9a02d0681
@@@ -20,481 -20,470 +20,471 @@@ import 
        "testing"
  )
  
- // pkgDeps defines the expected dependencies between packages in
+ // depsRules defines the expected dependencies between packages in
  // the Go source tree. It is a statement of policy.
- // Changes should not be made to this map without prior discussion.
- //
- // The map contains two kinds of entries:
- // 1) Lower-case keys are standard import paths and list the
- // allowed imports in that package.
- // 2) Upper-case keys define aliases for package sets, which can then
- // be used as dependencies by other rules.
  //
  // DO NOT CHANGE THIS DATA TO FIX BUILDS.
+ // Existing packages should not have their constraints relaxed
+ // without prior discussion.
+ // Negative assertions should almost never be removed.
  //
- var pkgDeps = map[string][]string{
-       // L0 is the lowest level, core, nearly unavoidable packages.
-       "errors":                  {"runtime", "internal/reflectlite"},
-       "io":                      {"errors", "sync", "sync/atomic"},
-       "runtime":                 {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"},
-       "runtime/internal/sys":    {},
-       "runtime/internal/atomic": {"unsafe", "internal/cpu"},
-       "runtime/internal/math":   {"runtime/internal/sys"},
-       "internal/race":           {"runtime", "unsafe"},
-       "sync":                    {"internal/race", "runtime", "sync/atomic", "unsafe"},
-       "sync/atomic":             {"unsafe"},
-       "unsafe":                  {},
-       "internal/cpu":            {},
-       "internal/bytealg":        {"unsafe", "internal/cpu"},
-       "internal/reflectlite":    {"runtime", "unsafe", "internal/unsafeheader"},
-       "internal/unsafeheader":   {"unsafe"},
-       "L0": {
-               "errors",
-               "io",
-               "runtime",
-               "runtime/internal/atomic",
-               "sync",
-               "sync/atomic",
-               "unsafe",
-               "internal/cpu",
-               "internal/bytealg",
-               "internal/reflectlite",
-       },
-       // L1 adds simple functions and strings processing,
-       // but not Unicode tables.
-       "math":          {"internal/cpu", "unsafe", "math/bits"},
-       "math/bits":     {"unsafe"},
-       "math/cmplx":    {"math", "math/bits"},
-       "math/rand":     {"L0", "math"},
-       "strconv":       {"L0", "unicode/utf8", "math", "math/bits"},
-       "unicode/utf16": {},
-       "unicode/utf8":  {},
-       "L1": {
-               "L0",
-               "math",
-               "math/bits",
-               "math/cmplx",
-               "math/rand",
-               "sort",
-               "strconv",
-               "unicode/utf16",
-               "unicode/utf8",
-       },
-       // L2 adds Unicode and strings processing.
-       "bufio":   {"L0", "unicode/utf8", "bytes", "strings"},
-       "bytes":   {"L0", "unicode", "unicode/utf8"},
-       "path":    {"L0", "unicode/utf8", "strings"},
-       "strings": {"L0", "unicode", "unicode/utf8"},
-       "unicode": {},
-       "L2": {
-               "L1",
-               "bufio",
-               "bytes",
-               "path",
-               "strings",
-               "unicode",
-       },
-       // L3 adds reflection and some basic utility packages
-       // and interface definitions, but nothing that makes
-       // system calls.
-       "crypto":                 {"L2", "hash"}, // interfaces
-       "crypto/cipher":          {"L2", "crypto/subtle", "crypto/internal/subtle", "encoding/binary"},
-       "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag
-       "crypto/subtle":          {},
-       "encoding/base32":        {"L2"},
-       "encoding/base64":        {"L2", "encoding/binary"},
-       "encoding/binary":        {"L2", "reflect"},
-       "hash":                   {"L2"}, // interfaces
-       "hash/adler32":           {"L2", "hash"},
-       "hash/crc32":             {"L2", "hash"},
-       "hash/crc64":             {"L2", "hash"},
-       "hash/fnv":               {"L2", "hash"},
-       "hash/maphash":           {"L2", "hash"},
-       "image":                  {"L2", "image/color"}, // interfaces
-       "image/color":            {"L2"},                // interfaces
-       "image/color/palette":    {"L2", "image/color"},
-       "internal/fmtsort":       {"reflect", "sort"},
-       "reflect":                {"L2", "internal/unsafeheader"},
-       "sort":                   {"internal/reflectlite"},
-       "crypto/internal/boring":         {"L2", "C", "crypto", "crypto/cipher", "crypto/internal/boring/sig", "crypto/subtle", "encoding/asn1", "hash", "math/big"},
-       "crypto/internal/boring/fipstls": {"sync/atomic"},
-       "crypto/internal/cipherhw":       {"crypto/internal/boring"},
-       "crypto/tls/fipsonly":            {"crypto/internal/boring/fipstls", "crypto/internal/boring/sig"},
-       "L3": {
-               "L2",
-               "crypto",
-               "crypto/cipher",
-               "crypto/internal/boring",
-               "crypto/internal/boring/fipstls",
-               "crypto/internal/subtle",
-               "crypto/subtle",
-               "encoding/base32",
-               "encoding/base64",
-               "encoding/binary",
-               "hash",
-               "hash/adler32",
-               "hash/crc32",
-               "hash/crc64",
-               "hash/fnv",
-               "image",
-               "image/color",
-               "image/color/palette",
-               "internal/fmtsort",
-               "internal/oserror",
-               "reflect",
-       },
-       // End of linear dependency definitions.
-       // Operating system access.
-       "syscall":                           {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "internal/unsafeheader", "syscall/js", "unicode/utf16"},
-       "syscall/js":                        {"L0"},
-       "internal/oserror":                  {"L0"},
-       "internal/syscall/unix":             {"L0", "syscall"},
-       "internal/syscall/windows":          {"L0", "syscall", "internal/syscall/windows/sysdll", "internal/unsafeheader", "unicode/utf16"},
-       "internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
-       "internal/syscall/execenv":          {"L0", "syscall", "internal/syscall/windows", "unicode/utf16"},
-       "time": {
-               // "L0" without the "io" package:
-               "errors",
-               "runtime",
-               "runtime/internal/atomic",
-               "sync",
-               "sync/atomic",
-               "unsafe",
-               // Other time dependencies:
-               "internal/syscall/windows/registry",
-               "syscall",
-               "syscall/js",
-               "time/tzdata",
-       },
-       "time/tzdata": {"L0", "syscall"},
-       "internal/cfg":     {"L0"},
-       "internal/poll":    {"L0", "internal/oserror", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows", "internal/syscall/unix"},
-       "internal/testlog": {"L0"},
-       "os":               {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/syscall/execenv", "internal/testlog"},
-       "path/filepath":    {"L2", "os", "syscall", "internal/syscall/windows"},
-       "io/ioutil":        {"L2", "os", "path/filepath", "time"},
-       "os/exec":          {"L2", "os", "context", "path/filepath", "syscall", "internal/syscall/execenv"},
-       "os/signal":        {"L2", "os", "syscall"},
-       // OS enables basic operating system functionality,
-       // but not direct use of package syscall, nor os/signal.
-       "OS": {
-               "io/ioutil",
-               "os",
-               "os/exec",
-               "path/filepath",
-               "time",
-       },
-       // Formatted I/O: few dependencies (L1) but we must add reflect and internal/fmtsort.
-       "fmt": {"L1", "os", "reflect", "internal/fmtsort"},
-       "log": {"L1", "os", "fmt", "time"},
-       // Packages used by testing must be low-level (L2+fmt).
-       "regexp":         {"L2", "regexp/syntax"},
-       "regexp/syntax":  {"L2"},
-       "runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"},
-       "runtime/pprof":  {"L2", "compress/gzip", "context", "encoding/binary", "fmt", "io/ioutil", "os", "syscall", "text/tabwriter", "time"},
-       "runtime/trace":  {"L0", "context", "fmt"},
-       "text/tabwriter": {"L2"},
-       "testing":                  {"L2", "flag", "fmt", "internal/race", "io/ioutil", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
-       "testing/iotest":           {"L2", "log"},
-       "testing/quick":            {"L2", "flag", "fmt", "reflect", "time"},
-       "internal/obscuretestdata": {"L2", "OS", "encoding/base64"},
-       "internal/testenv":         {"L2", "OS", "flag", "testing", "syscall", "internal/cfg"},
-       "internal/lazyregexp":      {"L2", "OS", "regexp"},
-       "internal/lazytemplate":    {"L2", "OS", "text/template"},
-       // L4 is defined as L3+fmt+log+time, because in general once
-       // you're using L3 packages, use of fmt, log, or time is not a big deal.
-       "L4": {
-               "L3",
-               "fmt",
-               "log",
-               "time",
-       },
-       // Go parser.
-       "go/ast":     {"L4", "OS", "go/scanner", "go/token"},
-       "go/doc":     {"L4", "OS", "go/ast", "go/token", "regexp", "internal/lazyregexp", "text/template"},
-       "go/parser":  {"L4", "OS", "go/ast", "go/scanner", "go/token"},
-       "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
-       "go/scanner": {"L4", "OS", "go/token"},
-       "go/token":   {"L4"},
-       "GOPARSER": {
-               "go/ast",
-               "go/doc",
-               "go/parser",
-               "go/printer",
-               "go/scanner",
-               "go/token",
-       },
-       "go/format":       {"L4", "GOPARSER", "internal/format"},
-       "internal/format": {"L4", "GOPARSER"},
-       // Go type checking.
-       "go/constant":               {"L4", "go/token", "math/big"},
-       "go/importer":               {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
-       "go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
-       "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner"},
-       "go/internal/srcimporter":   {"L4", "OS", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
-       "go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
-       // One of a kind.
-       "archive/tar":               {"L4", "OS", "syscall", "os/user"},
-       "archive/zip":               {"L4", "OS", "compress/flate"},
-       "container/heap":            {"sort"},
-       "compress/bzip2":            {"L4"},
-       "compress/flate":            {"L4"},
-       "compress/gzip":             {"L4", "compress/flate"},
-       "compress/lzw":              {"L4"},
-       "compress/zlib":             {"L4", "compress/flate"},
-       "context":                   {"errors", "internal/reflectlite", "sync", "sync/atomic", "time"},
-       "database/sql":              {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
-       "database/sql/driver":       {"L4", "context", "time", "database/sql/internal"},
-       "debug/dwarf":               {"L4"},
-       "debug/elf":                 {"L4", "OS", "debug/dwarf", "compress/zlib"},
-       "debug/gosym":               {"L4"},
-       "debug/macho":               {"L4", "OS", "debug/dwarf", "compress/zlib"},
-       "debug/pe":                  {"L4", "OS", "debug/dwarf", "compress/zlib"},
-       "debug/plan9obj":            {"L4", "OS"},
-       "encoding":                  {"L4"},
-       "encoding/ascii85":          {"L4"},
-       "encoding/asn1":             {"L4", "math/big"},
-       "encoding/csv":              {"L4"},
-       "encoding/gob":              {"L4", "OS", "encoding"},
-       "encoding/hex":              {"L4"},
-       "encoding/json":             {"L4", "encoding"},
-       "encoding/pem":              {"L4"},
-       "encoding/xml":              {"L4", "encoding"},
-       "flag":                      {"L4", "OS"},
-       "go/build":                  {"L4", "OS", "GOPARSER", "internal/goroot", "internal/goversion"},
-       "html":                      {"L4"},
-       "image/draw":                {"L4", "image/internal/imageutil"},
-       "image/gif":                 {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-       "image/internal/imageutil":  {"L4"},
-       "image/jpeg":                {"L4", "image/internal/imageutil"},
-       "image/png":                 {"L4", "compress/zlib"},
-       "index/suffixarray":         {"L4", "regexp"},
-       "internal/goroot":           {"L4", "OS"},
-       "internal/singleflight":     {"sync"},
-       "internal/trace":            {"L4", "OS", "container/heap"},
-       "internal/xcoff":            {"L4", "OS", "debug/dwarf"},
-       "math/big":                  {"L4"},
-       "mime":                      {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
-       "mime/quotedprintable":      {"L4"},
-       "net/internal/socktest":     {"L4", "OS", "syscall", "internal/syscall/windows"},
-       "net/url":                   {"L4"},
-       "plugin":                    {"L0", "OS", "CGO"},
-       "internal/profile":          {"L4", "OS", "compress/gzip", "regexp"},
-       "testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"},
-       "text/scanner":              {"L4", "OS"},
-       "text/template/parse":       {"L4"},
-       "html/template": {
-               "L4", "OS", "encoding/json", "html", "text/template",
-               "text/template/parse",
-       },
-       "text/template": {
-               "L4", "OS", "net/url", "text/template/parse",
-       },
-       // Cgo.
-       // If you add a dependency on CGO, you must add the package to
-       // cgoPackages in cmd/dist/test.go.
-       "runtime/cgo": {"L0", "C"},
-       "CGO":         {"C", "runtime/cgo"},
-       // Fake entry to satisfy the pseudo-import "C"
-       // that shows up in programs that use cgo.
-       "C": {},
-       // Race detector/MSan uses cgo.
-       "runtime/race": {"C"},
-       "runtime/msan": {"C"},
-       // Plan 9 alone needs io/ioutil and os.
-       "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall", "internal/syscall/windows", "internal/syscall/windows/registry"},
-       // Internal package used only for testing.
-       "os/signal/internal/pty": {"CGO", "fmt", "os", "syscall"},
-       // Basic networking.
-       // Because net must be used by any package that wants to
-       // do networking portably, it must have a small dependency set: just L0+basic os.
-       "net": {
-               "L0", "CGO",
-               "context", "math/rand", "os", "sort", "syscall", "time",
-               "internal/nettrace", "internal/poll", "internal/syscall/unix",
-               "internal/syscall/windows", "internal/singleflight", "internal/race",
-               "golang.org/x/net/dns/dnsmessage", "golang.org/x/net/lif", "golang.org/x/net/route",
-       },
-       // NET enables use of basic network-related packages.
-       "NET": {
-               "net",
-               "mime",
-               "net/textproto",
-               "net/url",
-       },
-       // Uses of networking.
-       "log/syslog":    {"L4", "OS", "net"},
-       "net/mail":      {"L4", "NET", "OS", "mime"},
-       "net/textproto": {"L4", "OS", "net"},
-       // Core crypto.
-       "crypto/aes":               {"L3"},
-       "crypto/des":               {"L3"},
-       "crypto/hmac":              {"L3"},
-       "crypto/internal/randutil": {"io", "sync"},
-       "crypto/md5":               {"L3"},
-       "crypto/rc4":               {"L3"},
-       "crypto/sha1":              {"L3"},
-       "crypto/sha256":            {"L3"},
-       "crypto/sha512":            {"L3"},
-       "CRYPTO": {
-               "crypto/aes",
-               "crypto/des",
-               "crypto/hmac",
-               "crypto/internal/randutil",
-               "crypto/md5",
-               "crypto/rc4",
-               "crypto/sha1",
-               "crypto/sha256",
-               "crypto/sha512",
-               "golang.org/x/crypto/chacha20poly1305",
-               "golang.org/x/crypto/curve25519",
-               "golang.org/x/crypto/poly1305",
-       },
-       // Random byte, number generation.
-       // This would be part of core crypto except that it imports
-       // math/big, which imports fmt.
-       "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "syscall/js", "internal/syscall/unix"},
-       // Not part of CRYPTO because it imports crypto/rand and crypto/sha512.
-       "crypto/ed25519":                       {"L3", "CRYPTO", "crypto/rand", "crypto/ed25519/internal/edwards25519"},
-       "crypto/ed25519/internal/edwards25519": {"encoding/binary"},
-       // Mathematical crypto: dependencies on fmt (L4) and math/big.
-       // We could avoid some of the fmt, but math/big imports fmt anyway.
-       "crypto/dsa": {"L4", "CRYPTO", "math/big"},
-       "crypto/ecdsa": {
-               "L4", "CRYPTO", "crypto/elliptic", "math/big",
-               "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1",
-       },
-       "crypto/elliptic": {"L4", "CRYPTO", "math/big"},
-       "crypto/rsa":      {"L4", "CRYPTO", "crypto/rand", "math/big"},
-       "CRYPTO-MATH": {
-               "CRYPTO",
-               "crypto/dsa",
-               "crypto/ecdsa",
-               "crypto/elliptic",
-               "crypto/rand",
-               "crypto/rsa",
-               "encoding/asn1",
-               "math/big",
-       },
-       // SSL/TLS.
-       "crypto/tls": {
-               "L4", "CRYPTO-MATH", "OS", "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/hkdf",
-               "container/list", "context", "crypto/x509", "encoding/pem", "net", "syscall", "crypto/ed25519",
-       },
-       "crypto/x509": {
-               "L4", "CRYPTO-MATH", "OS", "CGO", "crypto/ed25519",
-               "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall", "net/url",
-               "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1",
-       },
-       "crypto/x509/pkix": {"L4", "CRYPTO-MATH", "encoding/hex"},
-       // Simple net+crypto-aware packages.
-       "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
-       "net/smtp":       {"L4", "CRYPTO", "NET", "crypto/tls"},
-       // HTTP, kingpin of dependencies.
-       "net/http": {
-               "L4", "NET", "OS",
-               "compress/gzip",
-               "container/list",
-               "context",
-               "crypto/rand",
-               "crypto/tls",
-               "golang.org/x/net/http/httpguts",
-               "golang.org/x/net/http/httpproxy",
-               "golang.org/x/net/http2/hpack",
-               "golang.org/x/net/idna",
-               "golang.org/x/text/unicode/norm",
-               "golang.org/x/text/width",
-               "internal/nettrace",
-               "mime/multipart",
-               "net/http/httptrace",
-               "net/http/internal",
-               "runtime/debug",
-               "syscall/js",
-       },
-       "net/http/internal":  {"L4"},
-       "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "net/textproto", "reflect", "time"},
-       // HTTP-using packages.
-       "expvar":             {"L4", "OS", "encoding/json", "net/http"},
-       "net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
-       "net/http/cookiejar": {"L4", "NET", "net/http"},
-       "net/http/fcgi":      {"L4", "NET", "OS", "context", "net/http", "net/http/cgi"},
-       "net/http/httptest": {
-               "L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal", "crypto/x509",
-               "golang.org/x/net/http/httpguts",
-       },
-       "net/http/httputil": {"L4", "NET", "OS", "context", "net/http", "net/http/internal", "golang.org/x/net/http/httpguts"},
-       "net/http/pprof":    {"L4", "OS", "context", "html/template", "net/http", "runtime/pprof", "runtime/trace", "internal/profile"},
-       "net/rpc":           {"L4", "NET", "encoding/gob", "html/template", "net/http", "go/token"},
-       "net/rpc/jsonrpc":   {"L4", "NET", "encoding/json", "net/rpc"},
- }
+ // The general syntax of a rule is:
+ //
+ //            a, b < c, d;
+ //
+ // which means c and d come after a and b in the partial order
+ // (that is, c and d can import a and b),
+ // but doesn't provide a relative order between a vs b or c vs d.
+ //
+ // The rules can chain together, as in:
+ //
+ //            e < f, g < h;
+ //
+ // which is equivalent to
+ //
+ //            e < f, g;
+ //            f, g < h;
+ //
+ // Except for the special bottom element "NONE", each name
+ // must appear exactly once on the right-hand side of a rule.
+ // That rule serves as the definition of the allowed dependencies
+ // for that name. The definition must appear before any uses
+ // of the name on the left-hand side of a rule. (That is, the
+ // rules themselves must be ordered according to the partial
+ // order, for easier reading by people.)
+ //
+ // Negative assertions double-check the partial order:
+ //
+ //            i !< j
+ //
+ // means that it must NOT be the case that i < j.
+ // Negative assertions may appear anywhere in the rules,
+ // even before i and j have been defined.
+ //
+ // Comments begin with #.
+ //
+ // All-caps names are pseudo-names for specific points
+ // in the dependency lattice.
+ //
+ var depsRules = `
+       # No dependencies allowed for any of these packages.
+       NONE
+       < container/list, container/ring,
+         internal/cfg, internal/cpu,
+         internal/goversion, internal/nettrace,
+         unicode/utf8, unicode/utf16, unicode,
+         unsafe;
+       # RUNTIME is the core runtime group of packages, all of them very light-weight.
+       internal/cpu, unsafe
+       < internal/bytealg
+       < internal/unsafeheader
+       < runtime/internal/sys
+       < runtime/internal/atomic
+       < runtime/internal/math
+       < runtime
+       < sync/atomic
+       < internal/race
+       < sync
+       < internal/reflectlite
+       < errors
+       < internal/oserror, math/bits
+       < RUNTIME;
+       RUNTIME
+       < sort
+       < container/heap;
+       RUNTIME
+       < io;
+       reflect !< sort;
+       # SYSCALL is RUNTIME plus the packages necessary for basic system calls.
+       RUNTIME, unicode/utf8, unicode/utf16, io
+       < internal/syscall/windows/sysdll, syscall/js
+       < syscall
+       < internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
+       < internal/syscall/execenv
+       < SYSCALL;
+       # TIME is SYSCALL plus the core packages about time, including context.
+       SYSCALL
+       < time/tzdata
+       < time
+       < context
+       < TIME;
+       # MATH is RUNTIME plus the basic math packages.
+       RUNTIME
+       < math
+       < MATH;
+       unicode !< math;
+       MATH
+       < math/cmplx;
+       MATH
+       < math/rand;
+       MATH, unicode/utf8
+       < strconv;
+       unicode !< strconv;
+       # STR is basic string and buffer manipulation.
+       RUNTIME, io, unicode/utf8, unicode/utf16, unicode
+       < bytes, strings
+       < bufio, path;
+       bufio, path, strconv
+       < STR;
+       # OS is basic OS access, including helpers (path/filepath, os/exec, etc).
+       # OS includes string routines, but those must be layered above package os.
+       # OS does not include reflection.
+       TIME, io, sort
+       < internal/testlog
+       < internal/poll
+       < os
+       < os/signal;
+       unicode, fmt !< os, os/signal;
+       os/signal, STR
+       < path/filepath
+       < io/ioutil, os/exec
+       < OS;
+       reflect !< OS;
+       OS
+       < golang.org/x/sys/cpu, internal/goroot;
+       # FMT is OS (which includes string routines) plus reflect and fmt.
+       # It does not include package log, which should be avoided in core packages.
+       strconv, unicode
+       < reflect;
+       os, reflect
+       < internal/fmtsort
+       < fmt;
+       OS, fmt
+       < FMT;
+       log !< FMT;
+       # Misc packages needing only FMT.
+       FMT
+       < flag,
+         html,
+         mime/quotedprintable,
+         net/internal/socktest,
+         net/url,
+         runtime/debug,
+         runtime/trace,
+         text/scanner,
+         text/tabwriter;
+       # encodings
+       # core ones do not use fmt.
+       io, strconv
+       < encoding;
+       encoding, reflect
+       < encoding/binary
+       < encoding/base32, encoding/base64;
+       fmt !< encoding/base32, encoding/base64;
+       FMT, encoding/base32, encoding/base64
+       < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
+         encoding/json, encoding/pem, encoding/xml, mime;
+       # hashes
+       io
+       < hash
+       < hash/adler32, hash/crc32, hash/crc64, hash/fnv, hash/maphash;
+       # math/big
+       FMT, encoding/binary, math/rand
+       < math/big;
+       # compression
+       FMT, encoding/binary, hash/adler32, hash/crc32
+       < compress/bzip2, compress/flate, compress/lzw
+       < archive/zip, compress/gzip, compress/zlib;
+       # templates
+       FMT
+       < text/template/parse;
+       net/url, text/template/parse
+       < text/template
+       < internal/lazytemplate;
+       encoding/json, html, text/template
+       < html/template;
+       # regexp
+       FMT
+       < regexp/syntax
+       < regexp
+       < internal/lazyregexp;
+       # suffix array
+       encoding/binary, regexp
+       < index/suffixarray;
+       # executable parsing
+       FMT, encoding/binary, compress/zlib
+       < debug/dwarf
+       < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
+       < DEBUG;
+       # go parser and friends.
+       FMT
+       < go/token
+       < go/scanner
+       < go/ast
+       < go/parser;
+       go/parser, text/tabwriter
+       < go/printer
+       < go/format;
+       go/parser, internal/lazyregexp, text/template
+       < go/doc;
+       math/big, go/token
+       < go/constant;
+       container/heap, go/constant, go/parser
+       < go/types;
+       go/doc, go/parser, internal/goroot, internal/goversion
+       < go/build;
+       DEBUG, go/build, go/types, text/scanner
+       < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
+       < go/importer;
+       # databases
+       FMT
+       < database/sql/internal
+       < database/sql/driver
+       < database/sql;
+       # images
+       FMT, compress/lzw, compress/zlib
+       < image/color
+       < image, image/color/palette
+       < image/internal/imageutil
+       < image/draw
+       < image/gif, image/jpeg, image/png;
+       # cgo, delayed as long as possible.
+       # If you add a dependency on CGO, you must add the package
+       # to cgoPackages in cmd/dist/test.go as well.
+       RUNTIME
+       < C
+       < runtime/cgo
+       < CGO
+       < runtime/race, runtime/msan;
+       # Bulk of the standard library must not use cgo.
+       # The prohibition stops at net and os/user.
 -      C !< fmt, go/types, CRYPTO-MATH;
++      C !< fmt, go/types;
+       CGO, OS
+       < plugin;
+       CGO, FMT
+       < os/user
+       < archive/tar;
+       sync
+       < internal/singleflight;
+       os
+       < golang.org/x/net/dns/dnsmessage,
+         golang.org/x/net/lif,
+         golang.org/x/net/route;
+       # net is unavoidable when doing any networking,
+       # so large dependencies must be kept out.
+       # This is a long-looking list but most of these
+       # are small with few dependencies.
+       # math/rand should probably be removed at some point.
+       CGO,
+       golang.org/x/net/dns/dnsmessage,
+       golang.org/x/net/lif,
+       golang.org/x/net/route,
+       internal/nettrace,
+       internal/poll,
+       internal/singleflight,
+       internal/race,
+       math/rand,
+       os
+       < net;
+       fmt, unicode !< net;
+       # NET is net plus net-helper packages.
+       FMT, net
+       < net/textproto;
+       mime, net/textproto, net/url
+       < NET;
+       # logging - most packages should not import; http and up is allowed
+       FMT
+       < log;
+       log !< crypto/tls, database/sql, go/importer, testing;
+       FMT, log, net
+       < log/syslog;
+       NET, log
+       < net/mail;
 -      # CRYPTO is core crypto algorithms - no cgo, fmt, net.
 -      # Unfortunately, stuck with reflect via encoding/binary.
 -      encoding/binary, golang.org/x/sys/cpu, hash
++      NONE < crypto/internal/boring/sig;
++      sync/atomic < crypto/internal/boring/fipstls;
++
++      encoding/binary, golang.org/x/sys/cpu, hash,
++      FMT, math/big,
++      CGO, crypto/internal/boring/sig, crypto/internal/boring/fipstls
+       < crypto
+       < crypto/subtle
+       < crypto/internal/subtle
+       < crypto/cipher
++      < encoding/asn1
++      < crypto/internal/boring
+       < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
+         crypto/sha1, crypto/sha256, crypto/sha512
 -      < CRYPTO;
 -
 -      CGO, fmt, net !< CRYPTO;
 -
 -      # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
 -      CRYPTO, FMT, math/big
+       < crypto/rand
+       < crypto/internal/randutil
+       < crypto/ed25519/internal/edwards25519
+       < crypto/ed25519
 -      < encoding/asn1
+       < golang.org/x/crypto/cryptobyte/asn1
+       < golang.org/x/crypto/cryptobyte
+       < golang.org/x/crypto/curve25519
+       < crypto/dsa, crypto/elliptic, crypto/rsa
+       < crypto/ecdsa
 -      < CRYPTO-MATH;
++      < CRYPTO-BORING;
 -      CGO, net !< CRYPTO-MATH;
++      net !< CRYPTO-BORING;
+       # TLS, Prince of Dependencies.
 -      CGO, CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
++      CGO, CRYPTO-BORING, NET, container/list, encoding/hex, encoding/pem
+       < golang.org/x/crypto/internal/subtle
+       < golang.org/x/crypto/chacha20
+       < golang.org/x/crypto/poly1305
+       < golang.org/x/crypto/chacha20poly1305
+       < golang.org/x/crypto/hkdf
+       < crypto/x509/internal/macOS
+       < crypto/x509/pkix
+       < crypto/x509
+       < crypto/tls;
++      crypto/internal/boring/sig, crypto/internal/boring/fipstls
++      < crypto/tls/fipsonly;
++
+       # crypto-aware packages
+       NET, crypto/rand, mime/quotedprintable
+       < mime/multipart;
+       crypto/tls
+       < net/smtp;
+       # HTTP, King of Dependencies.
+       FMT
+       < golang.org/x/net/http2/hpack, net/http/internal;
+       FMT, NET, container/list, encoding/binary, log
+       < golang.org/x/text/transform
+       < golang.org/x/text/unicode/norm
+       < golang.org/x/text/unicode/bidi
+       < golang.org/x/text/secure/bidirule
+       < golang.org/x/net/idna
+       < golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
+       NET, crypto/tls
+       < net/http/httptrace;
+       compress/gzip,
+       golang.org/x/net/http/httpguts,
+       golang.org/x/net/http/httpproxy,
+       golang.org/x/net/http2/hpack,
+       net/http/internal,
+       net/http/httptrace,
+       mime/multipart,
+       log
+       < net/http;
+       # HTTP-aware packages
  
- // isMacro reports whether p is a package dependency macro
- // (uppercase name).
- func isMacro(p string) bool {
-       return 'A' <= p[0] && p[0] <= 'Z'
- }
+       encoding/json, net/http
+       < expvar;
  
- func allowed(pkg string) map[string]bool {
-       m := map[string]bool{}
-       var allow func(string)
-       allow = func(p string) {
-               if m[p] {
-                       return
-               }
-               m[p] = true // set even for macros, to avoid loop on cycle
+       net/http
+       < net/http/cookiejar, net/http/httputil;
+       net/http, flag
+       < net/http/httptest;
+       net/http, regexp
+       < net/http/cgi
+       < net/http/fcgi;
+       # Profiling
+       FMT, compress/gzip, encoding/binary, text/tabwriter
+       < runtime/pprof;
+       OS, compress/gzip, regexp
+       < internal/profile;
+       html/template, internal/profile, net/http, runtime/pprof, runtime/trace
+       < net/http/pprof;
+       # RPC
+       encoding/gob, encoding/json, go/token, html/template, net/http
+       < net/rpc
+       < net/rpc/jsonrpc;
+       # Test-only
+       log
+       < testing/iotest;
+       FMT, flag, math/rand
+       < testing/quick;
  
-               // Upper-case names are macro-expanded.
-               if isMacro(p) {
-                       for _, pp := range pkgDeps[p] {
-                               allow(pp)
-                       }
-               }
-       }
-       for _, pp := range pkgDeps[pkg] {
-               allow(pp)
-       }
-       return m
- }
+       FMT, flag, runtime/debug, runtime/trace
+       < testing;
+       internal/testlog, runtime/pprof, regexp
+       < testing/internal/testdeps;
+       OS, flag, testing, internal/cfg
+       < internal/testenv;
+       OS, encoding/base64
+       < internal/obscuretestdata;
+       CGO, OS, fmt
+       < os/signal/internal/pty;
+       NET, testing
+       < golang.org/x/net/nettest;
+       FMT, container/heap, math/rand
+       < internal/trace;
+ `
  
  // listStdPkgs returns the same list of packages as "go list std".
  func listStdPkgs(goroot string) ([]string, error) {
                }
  
                name := filepath.ToSlash(path[len(src):])
-               if name == "builtin" || name == "cmd" || strings.Contains(name, "golang.org/x/") {
+               if name == "builtin" || name == "cmd" {
                        return filepath.SkipDir
                }
  
-               pkgs = append(pkgs, name)
+               pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
                return nil
        }
        if err := filepath.Walk(src, walkFn); err != nil {
@@@ -542,6 -531,7 +532,7 @@@ func TestDependencies(t *testing.T) 
        sort.Strings(all)
  
        sawImport := map[string]map[string]bool{} // from package => to package => true
+       policy := depsPolicy(t)
  
        for _, pkg := range all {
                imports, err := findImports(pkg)
                if sawImport[pkg] == nil {
                        sawImport[pkg] = map[string]bool{}
                }
-               ok := allowed(pkg)
+               ok := policy[pkg]
                var bad []string
                for _, imp := range imports {
                        sawImport[pkg][imp] = true
                }
                return ""
        }
-       // Also test some high-level policy goals are being met by not finding
-       // these dependency paths:
-       badPaths := []struct{ from, to string }{
-               {"net", "unicode"},
-               {"os", "unicode"},
-       }
-       for _, path := range badPaths {
-               if how := depPath(path.from, path.to); how != "" {
-                       t.Errorf("policy violation: %s", how)
-               }
-       }
  }
  
  var buildIgnore = []byte("\n// +build ignore")
  
  func findImports(pkg string) ([]string, error) {
-       dir := filepath.Join(Default.GOROOT, "src", pkg)
+       vpkg := pkg
+       if strings.HasPrefix(pkg, "golang.org") {
+               vpkg = "vendor/" + pkg
+       }
+       dir := filepath.Join(Default.GOROOT, "src", vpkg)
        files, err := ioutil.ReadDir(dir)
        if err != nil {
                return nil, err
        sort.Strings(imports)
        return imports, nil
  }
+ // depsPolicy returns a map m such that m[p][d] == true when p can import d.
+ func depsPolicy(t *testing.T) map[string]map[string]bool {
+       allowed := map[string]map[string]bool{"NONE": {}}
+       disallowed := [][2][]string{}
+       parseDepsRules(t, func(deps []string, op string, users []string) {
+               if op == "!<" {
+                       disallowed = append(disallowed, [2][]string{deps, users})
+                       return
+               }
+               for _, u := range users {
+                       if allowed[u] != nil {
+                               t.Errorf("multiple deps lists for %s", u)
+                       }
+                       allowed[u] = make(map[string]bool)
+                       for _, d := range deps {
+                               if allowed[d] == nil {
+                                       t.Errorf("use of %s before its deps list", d)
+                               }
+                               allowed[u][d] = true
+                       }
+               }
+       })
+       // Check for missing deps info.
+       for _, deps := range allowed {
+               for d := range deps {
+                       if allowed[d] == nil {
+                               t.Errorf("missing deps list for %s", d)
+                       }
+               }
+       }
+       // Complete transitive allowed deps.
+       for k := range allowed {
+               for i := range allowed {
+                       for j := range allowed {
+                               if i != k && k != j && allowed[i][k] && allowed[k][j] {
+                                       if i == j {
+                                               // Can only happen along with a "use of X before deps" error above,
+                                               // but this error is more specific - it makes clear that reordering the
+                                               // rules will not be enough to fix the problem.
+                                               t.Errorf("deps policy cycle: %s < %s < %s", j, k, i)
+                                       }
+                                       allowed[i][j] = true
+                               }
+                       }
+               }
+       }
+       // Check negative assertions against completed allowed deps.
+       for _, bad := range disallowed {
+               deps, users := bad[0], bad[1]
+               for _, d := range deps {
+                       for _, u := range users {
+                               if allowed[u][d] {
+                                       t.Errorf("deps policy incorrect: assertion failed: %s !< %s", d, u)
+                               }
+                       }
+               }
+       }
+       if t.Failed() {
+               t.FailNow()
+       }
+       return allowed
+ }
+ // parseDepsRules parses depsRules, calling save(deps, op, users)
+ // for each deps < users or deps !< users rule
+ // (op is "<" or "!<").
+ func parseDepsRules(t *testing.T, save func(deps []string, op string, users []string)) {
+       p := &depsParser{t: t, lineno: 1, text: depsRules}
+       var prev []string
+       var op string
+       for {
+               list, tok := p.nextList()
+               if tok == "" {
+                       if prev == nil {
+                               break
+                       }
+                       p.syntaxError("unexpected EOF")
+               }
+               if prev != nil {
+                       save(prev, op, list)
+               }
+               prev = list
+               if tok == ";" {
+                       prev = nil
+                       op = ""
+                       continue
+               }
+               if tok != "<" && tok != "!<" {
+                       p.syntaxError("missing <")
+               }
+               op = tok
+       }
+ }
+ // A depsParser parses the depsRules syntax described above.
+ type depsParser struct {
+       t        *testing.T
+       lineno   int
+       lastWord string
+       text     string
+ }
+ // syntaxError reports a parsing error.
+ func (p *depsParser) syntaxError(msg string) {
+       p.t.Fatalf("deps:%d: syntax error: %s near %s", p.lineno, msg, p.lastWord)
+ }
+ // nextList parses and returns a comma-separated list of names.
+ func (p *depsParser) nextList() (list []string, token string) {
+       for {
+               tok := p.nextToken()
+               switch tok {
+               case "":
+                       if len(list) == 0 {
+                               return nil, ""
+                       }
+                       fallthrough
+               case ",", "<", "!<", ";":
+                       p.syntaxError("bad list syntax")
+               }
+               list = append(list, tok)
+               tok = p.nextToken()
+               if tok != "," {
+                       return list, tok
+               }
+       }
+ }
+ // nextToken returns the next token in the deps rules,
+ // one of ";" "," "<" "!<" or a name.
+ func (p *depsParser) nextToken() string {
+       for {
+               if p.text == "" {
+                       return ""
+               }
+               switch p.text[0] {
+               case ';', ',', '<':
+                       t := p.text[:1]
+                       p.text = p.text[1:]
+                       return t
+               case '!':
+                       if len(p.text) < 2 || p.text[1] != '<' {
+                               p.syntaxError("unexpected token !")
+                       }
+                       p.text = p.text[2:]
+                       return "!<"
+               case '#':
+                       i := strings.Index(p.text, "\n")
+                       if i < 0 {
+                               i = len(p.text)
+                       }
+                       p.text = p.text[i:]
+                       continue
+               case '\n':
+                       p.lineno++
+                       fallthrough
+               case ' ', '\t':
+                       p.text = p.text[1:]
+                       continue
+               default:
+                       i := strings.IndexAny(p.text, "!;,<#\n \t")
+                       if i < 0 {
+                               i = len(p.text)
+                       }
+                       t := p.text[:i]
+                       p.text = p.text[i:]
+                       p.lastWord = t
+                       return t
+               }
+       }
+ }