From afca8cab3b3c8517256c880feed027a2935b04be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 07:44:43 +0000 Subject: [PATCH] Bump github.com/onsi/gomega from 1.40.0 to 1.42.1 in /tests Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.40.0 to 1.42.1. - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.40.0...v1.42.1) --- updated-dependencies: - dependency-name: github.com/onsi/gomega dependency-version: 1.42.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/go.mod | 18 +- tests/go.sum | 36 +- .../github.com/onsi/gomega/CHANGELOG.md | 18 + tests/vendor/github.com/onsi/gomega/README.md | 13 + .../github.com/onsi/gomega/format/format.go | 37 +- .../github.com/onsi/gomega/gomega_dsl.go | 2 +- .../vendor/github.com/onsi/gomega/matchers.go | 12 + .../gomega/matchers/be_a_slice_matcher.go | 28 + .../gomega/matchers/be_an_array_matcher.go | 28 + .../github.com/onsi/gomega/types/types.go | 12 + .../golang.org/x/crypto/cryptobyte/asn1.go | 825 +++ .../x/crypto/cryptobyte/asn1/asn1.go | 46 + .../golang.org/x/crypto/cryptobyte/builder.go | 350 ++ .../golang.org/x/crypto/cryptobyte/string.go | 183 + .../golang.org/x/crypto/pbkdf2/pbkdf2.go | 73 +- .../golang.org/x/crypto/ssh/agent/client.go | 236 +- .../golang.org/x/crypto/ssh/agent/keyring.go | 23 +- .../golang.org/x/crypto/ssh/agent/server.go | 36 +- tests/vendor/golang.org/x/crypto/ssh/certs.go | 18 +- .../vendor/golang.org/x/crypto/ssh/channel.go | 68 +- .../vendor/golang.org/x/crypto/ssh/cipher.go | 2 +- .../vendor/golang.org/x/crypto/ssh/client.go | 85 + .../golang.org/x/crypto/ssh/client_auth.go | 64 +- .../golang.org/x/crypto/ssh/connection.go | 10 +- .../vendor/golang.org/x/crypto/ssh/control.go | 155 + tests/vendor/golang.org/x/crypto/ssh/kex.go | 75 +- tests/vendor/golang.org/x/crypto/ssh/keys.go | 99 +- tests/vendor/golang.org/x/crypto/ssh/mux.go | 39 +- .../vendor/golang.org/x/crypto/ssh/server.go | 165 +- .../vendor/golang.org/x/crypto/ssh/session.go | 3 + tests/vendor/golang.org/x/net/html/entity.go | 5 +- tests/vendor/golang.org/x/net/html/escape.go | 140 +- tests/vendor/golang.org/x/net/html/foreign.go | 2 +- tests/vendor/golang.org/x/net/html/parse.go | 287 +- tests/vendor/golang.org/x/net/html/render.go | 35 +- tests/vendor/golang.org/x/net/html/token.go | 52 +- tests/vendor/golang.org/x/net/http2/README.md | 19 + .../x/net/http2/client_conn_pool.go | 14 +- .../golang.org/x/net/http2/clientconn.go | 57 + tests/vendor/golang.org/x/net/http2/config.go | 2 + .../golang.org/x/net/http2/hpack/tables.go | 13 +- tests/vendor/golang.org/x/net/http2/http2.go | 2 +- tests/vendor/golang.org/x/net/http2/server.go | 214 +- .../golang.org/x/net/http2/server_common.go | 221 + .../golang.org/x/net/http2/server_wrap.go | 217 + .../golang.org/x/net/http2/transport.go | 453 +- .../x/net/http2/transport_common.go | 447 ++ .../golang.org/x/net/http2/transport_wrap.go | 392 ++ .../golang.org/x/net/http2/writesched.go | 46 +- .../x/net/http2/writesched_common.go | 90 + .../net/http2/writesched_priority_rfc7540.go | 43 +- .../net/http2/writesched_priority_rfc9218.go | 2 + .../x/net/http2/writesched_random.go | 2 + .../x/net/http2/writesched_roundrobin.go | 2 + tests/vendor/golang.org/x/net/idna/go118.go | 13 - .../x/net/idna/{idna10.0.0.go => idna.go} | 181 +- .../vendor/golang.org/x/net/idna/idna9.0.0.go | 717 --- .../vendor/golang.org/x/net/idna/pre_go118.go | 11 - .../vendor/golang.org/x/net/idna/punycode.go | 5 +- .../golang.org/x/net/idna/tables10.0.0.go | 4559 -------------- .../golang.org/x/net/idna/tables11.0.0.go | 4653 --------------- .../golang.org/x/net/idna/tables12.0.0.go | 4733 --------------- .../golang.org/x/net/idna/tables13.0.0.go | 4959 --------------- .../golang.org/x/net/idna/tables15.0.0.go | 2 +- .../golang.org/x/net/idna/tables17.0.0.go | 5302 +++++++++++++++++ .../golang.org/x/net/idna/tables9.0.0.go | 4486 -------------- .../golang.org/x/net/idna/trie12.0.0.go | 30 - .../golang.org/x/net/idna/trie13.0.0.go | 30 - .../x/net/internal/httpcommon/request.go | 8 + .../golang.org/x/sync/errgroup/errgroup.go | 2 +- .../golang.org/x/sync/semaphore/semaphore.go | 10 +- tests/vendor/golang.org/x/sys/cpu/cpu.go | 19 +- .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 2 + .../golang.org/x/sys/cpu/cpu_loong64.go | 16 +- .../golang.org/x/sys/cpu/cpu_other_arm64.go | 2 +- .../golang.org/x/sys/cpu/cpu_riscv64.go | 1 + .../golang.org/x/sys/cpu/cpu_windows.go | 26 + .../golang.org/x/sys/cpu/cpu_windows_arm64.go | 38 + .../golang.org/x/sys/cpu/zcpu_windows.go | 48 + .../golang.org/x/sys/unix/affinity_linux.go | 128 +- tests/vendor/golang.org/x/sys/unix/mkall.sh | 2 +- .../vendor/golang.org/x/sys/unix/mkerrors.sh | 3 + .../golang.org/x/sys/unix/readv_unix.go | 103 + .../golang.org/x/sys/unix/syscall_darwin.go | 89 - .../golang.org/x/sys/unix/syscall_linux.go | 114 +- .../x/sys/unix/syscall_linux_arm.go | 3 + .../x/sys/unix/syscall_linux_arm64.go | 3 + .../x/sys/unix/syscall_linux_loong64.go | 3 + .../x/sys/unix/syscall_linux_riscv64.go | 3 + .../golang.org/x/sys/unix/syscall_openbsd.go | 4 + .../golang.org/x/sys/unix/zerrors_linux.go | 61 +- .../x/sys/unix/zerrors_linux_386.go | 7 +- .../x/sys/unix/zerrors_linux_amd64.go | 7 +- .../x/sys/unix/zerrors_linux_arm.go | 7 +- .../x/sys/unix/zerrors_linux_arm64.go | 7 +- .../x/sys/unix/zerrors_linux_loong64.go | 7 +- .../x/sys/unix/zerrors_linux_mips.go | 7 +- .../x/sys/unix/zerrors_linux_mips64.go | 7 +- .../x/sys/unix/zerrors_linux_mips64le.go | 7 +- .../x/sys/unix/zerrors_linux_mipsle.go | 7 +- .../x/sys/unix/zerrors_linux_ppc.go | 7 +- .../x/sys/unix/zerrors_linux_ppc64.go | 7 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 7 +- .../x/sys/unix/zerrors_linux_riscv64.go | 1114 ++-- .../x/sys/unix/zerrors_linux_s390x.go | 7 +- .../x/sys/unix/zerrors_linux_sparc64.go | 7 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 12 +- .../x/sys/unix/zsyscall_openbsd_386.go | 84 + .../x/sys/unix/zsyscall_openbsd_386.s | 20 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 84 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 20 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 84 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 20 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 84 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 24 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 84 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 20 + .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 5 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_loong64.go | 5 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 5 + .../golang.org/x/sys/unix/ztypes_linux.go | 123 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 12 + .../x/sys/unix/ztypes_linux_amd64.go | 12 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 12 + .../x/sys/unix/ztypes_linux_arm64.go | 12 + .../x/sys/unix/ztypes_linux_loong64.go | 12 + .../x/sys/unix/ztypes_linux_mips.go | 12 + .../x/sys/unix/ztypes_linux_mips64.go | 12 + .../x/sys/unix/ztypes_linux_mips64le.go | 12 + .../x/sys/unix/ztypes_linux_mipsle.go | 12 + .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 12 + .../x/sys/unix/ztypes_linux_ppc64.go | 12 + .../x/sys/unix/ztypes_linux_ppc64le.go | 12 + .../x/sys/unix/ztypes_linux_riscv64.go | 12 + .../x/sys/unix/ztypes_linux_s390x.go | 12 + .../x/sys/unix/ztypes_linux_sparc64.go | 12 + .../x/sys/windows/syscall_windows.go | 16 +- .../golang.org/x/sys/windows/types_windows.go | 33 +- .../x/sys/windows/zsyscall_windows.go | 71 + .../golang.org/x/tools/go/ast/edge/edge.go | 24 +- .../golang.org/x/tools/go/packages/golist.go | 17 +- .../x/tools/go/packages/packages.go | 16 +- .../x/tools/go/types/objectpath/objectpath.go | 563 +- .../x/tools/internal/gcimporter/ureader.go | 42 +- .../x/tools/internal/gocommand/version.go | 5 +- tests/vendor/modules.txt | 22 +- 162 files changed, 12548 insertions(+), 26468 deletions(-) create mode 100644 tests/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go create mode 100644 tests/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go create mode 100644 tests/vendor/golang.org/x/crypto/cryptobyte/asn1.go create mode 100644 tests/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go create mode 100644 tests/vendor/golang.org/x/crypto/cryptobyte/builder.go create mode 100644 tests/vendor/golang.org/x/crypto/cryptobyte/string.go create mode 100644 tests/vendor/golang.org/x/crypto/ssh/control.go create mode 100644 tests/vendor/golang.org/x/net/http2/README.md create mode 100644 tests/vendor/golang.org/x/net/http2/clientconn.go create mode 100644 tests/vendor/golang.org/x/net/http2/server_common.go create mode 100644 tests/vendor/golang.org/x/net/http2/server_wrap.go create mode 100644 tests/vendor/golang.org/x/net/http2/transport_common.go create mode 100644 tests/vendor/golang.org/x/net/http2/transport_wrap.go create mode 100644 tests/vendor/golang.org/x/net/http2/writesched_common.go delete mode 100644 tests/vendor/golang.org/x/net/idna/go118.go rename tests/vendor/golang.org/x/net/idna/{idna10.0.0.go => idna.go} (81%) delete mode 100644 tests/vendor/golang.org/x/net/idna/idna9.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/pre_go118.go delete mode 100644 tests/vendor/golang.org/x/net/idna/tables10.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/tables11.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/tables12.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/tables13.0.0.go create mode 100644 tests/vendor/golang.org/x/net/idna/tables17.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/tables9.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/trie12.0.0.go delete mode 100644 tests/vendor/golang.org/x/net/idna/trie13.0.0.go create mode 100644 tests/vendor/golang.org/x/sys/cpu/cpu_windows.go create mode 100644 tests/vendor/golang.org/x/sys/cpu/cpu_windows_arm64.go create mode 100644 tests/vendor/golang.org/x/sys/cpu/zcpu_windows.go create mode 100644 tests/vendor/golang.org/x/sys/unix/readv_unix.go diff --git a/tests/go.mod b/tests/go.mod index 1668c86bc..14adbb694 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -6,7 +6,7 @@ require ( github.com/gruntwork-io/terratest v0.47.2 github.com/mittwald/go-helm-client v0.12.19 github.com/onsi/ginkgo/v2 v2.28.3 - github.com/onsi/gomega v1.40.0 + github.com/onsi/gomega v1.42.1 github.com/stretchr/testify v1.11.1 k8s.io/api v0.35.2 k8s.io/apiextensions-apiserver v0.35.2 @@ -128,16 +128,16 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.50.0 // indirect - golang.org/x/mod v0.35.0 // indirect - golang.org/x/net v0.53.0 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/term v0.42.0 // indirect - golang.org/x/text v0.36.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.38.0 // indirect golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.44.0 // indirect + golang.org/x/tools v0.45.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.8 // indirect diff --git a/tests/go.sum b/tests/go.sum index ccc97c0f2..d5324fcd9 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -282,8 +282,8 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.28.3 h1:4JvMdwtFU0imd8fHx25OJXoDMRexnf8v5NHKYSTTji4= github.com/onsi/ginkgo/v2 v2.28.3/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= -github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= -github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= +github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= +github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -433,26 +433,26 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -464,24 +464,24 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/tests/vendor/github.com/onsi/gomega/CHANGELOG.md b/tests/vendor/github.com/onsi/gomega/CHANGELOG.md index 9c94d0e6c..7cd26c2ce 100644 --- a/tests/vendor/github.com/onsi/gomega/CHANGELOG.md +++ b/tests/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -1,3 +1,21 @@ +## 1.42.1 + +Bump Dependencies + +## 1.42.0 + +Add a set of Claude skill as a marketplace plugin + +## 1.41.0 + +### Features + +Add `BeASlice` and `BeAnArray` matchers + +### Fixes + +Object formatting now detects pointer cycles to avoid runaway formatting output. + ## 1.40.0 We're adopting a new release strategy to minimize dependency bloat in projects that consume Gomega. It is a limitation of the go mod toolchain that _test_ subdependencies of your project's direct dependencies get pulled in as *indirect* dependencies. In the case of Gomega, this ends up pulling in all of Ginkgo into your `go.mod` even if you are only using Gomega (Gomega uses Ginkgo for its own tests). diff --git a/tests/vendor/github.com/onsi/gomega/README.md b/tests/vendor/github.com/onsi/gomega/README.md index d45a8c4e5..6eb36fdf8 100644 --- a/tests/vendor/github.com/onsi/gomega/README.md +++ b/tests/vendor/github.com/onsi/gomega/README.md @@ -6,6 +6,19 @@ Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega If you have a question, comment, bug report, feature request, etc. please open a GitHub issue. +## Using Gomega with Claude Code + +Gomega ships a set of [Claude Code](https://claude.com/claude-code) skills as a **plugin**, so an agent writing assertions in *your* suite has Gomega's idioms — the full matcher catalog, `Eventually`/`Consistently`, and the `gstruct`/`ghttp`/`gexec`/`gbytes`/`gleak`/`gmeasure` sub-libraries — on hand. The Gomega repo doubles as the plugin marketplace, so installation is two commands. From inside Claude Code: + +``` +/plugin marketplace add onsi/gomega +/plugin install gomega@gomega +``` + +(or non-interactively: `claude plugin marketplace add onsi/gomega` then `claude plugin install gomega@gomega`) + +This installs a family of `gomega:*` skills that activate automatically while you write tests. See the [docs](http://onsi.github.io/gomega/#using-gomega-with-claude-code) for the full list. + ## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang Learn more about Ginkgo [here](http://onsi.github.io/ginkgo/) diff --git a/tests/vendor/github.com/onsi/gomega/format/format.go b/tests/vendor/github.com/onsi/gomega/format/format.go index 6c23ba338..d56f9a475 100644 --- a/tests/vendor/github.com/onsi/gomega/format/format.go +++ b/tests/vendor/github.com/onsi/gomega/format/format.go @@ -262,7 +262,7 @@ func Object(object any, indentation uint) string { if err, ok := object.(error); ok && !isNilValue(value) { // isNilValue check needed here to avoid nil deref due to boxed nil commonRepresentation += "\n" + IndentString(err.Error(), indentation) + "\n" + indent } - return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation, true)) + return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation, true, map[uintptr]struct{}{})) } /* @@ -306,7 +306,7 @@ func formatType(v reflect.Value) string { } } -func formatValue(value reflect.Value, indentation uint, isTopLevel bool) string { +func formatValue(value reflect.Value, indentation uint, isTopLevel bool, visited map[uintptr]struct{}) string { if indentation > MaxDepth { return "..." } @@ -367,23 +367,28 @@ func formatValue(value reflect.Value, indentation uint, isTopLevel bool) string case reflect.Func: return fmt.Sprintf("0x%x", value.Pointer()) case reflect.Ptr: - return formatValue(value.Elem(), indentation, isTopLevel) + ptr := value.Pointer() + if _, ok := visited[ptr]; ok { + return fmt.Sprintf("0x%x (cyclic reference)", ptr) + } + visited[ptr] = struct{}{} + return formatValue(value.Elem(), indentation, isTopLevel, visited) case reflect.Slice: - return truncateLongStrings(formatSlice(value, indentation)) + return truncateLongStrings(formatSlice(value, indentation, visited)) case reflect.String: return truncateLongStrings(formatString(value.String(), indentation, isTopLevel)) case reflect.Array: - return truncateLongStrings(formatSlice(value, indentation)) + return truncateLongStrings(formatSlice(value, indentation, visited)) case reflect.Map: - return truncateLongStrings(formatMap(value, indentation)) + return truncateLongStrings(formatMap(value, indentation, visited)) case reflect.Struct: if value.Type() == timeType && value.CanInterface() { t, _ := value.Interface().(time.Time) return t.Format(time.RFC3339Nano) } - return truncateLongStrings(formatStruct(value, indentation)) + return truncateLongStrings(formatStruct(value, indentation, visited)) case reflect.Interface: - return formatInterface(value, indentation) + return formatInterface(value, indentation, visited) default: if value.CanInterface() { return truncateLongStrings(fmt.Sprintf("%#v", value.Interface())) @@ -414,7 +419,7 @@ func formatString(object any, indentation uint, isTopLevel bool) string { } } -func formatSlice(v reflect.Value, indentation uint) string { +func formatSlice(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string { if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) { return formatString(v.Bytes(), indentation, false) } @@ -423,7 +428,7 @@ func formatSlice(v reflect.Value, indentation uint) string { result := make([]string, l) longest := 0 for i := range l { - result[i] = formatValue(v.Index(i), indentation+1, false) + result[i] = formatValue(v.Index(i), indentation+1, false, visited) if len(result[i]) > longest { longest = len(result[i]) } @@ -436,14 +441,14 @@ func formatSlice(v reflect.Value, indentation uint) string { return fmt.Sprintf("[%s]", strings.Join(result, ", ")) } -func formatMap(v reflect.Value, indentation uint) string { +func formatMap(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string { l := v.Len() result := make([]string, l) longest := 0 for i, key := range v.MapKeys() { value := v.MapIndex(key) - result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1, false), formatValue(value, indentation+1, false)) + result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1, false, visited), formatValue(value, indentation+1, false, visited)) if len(result[i]) > longest { longest = len(result[i]) } @@ -456,7 +461,7 @@ func formatMap(v reflect.Value, indentation uint) string { return fmt.Sprintf("{%s}", strings.Join(result, ", ")) } -func formatStruct(v reflect.Value, indentation uint) string { +func formatStruct(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string { t := v.Type() l := v.NumField() @@ -465,7 +470,7 @@ func formatStruct(v reflect.Value, indentation uint) string { for i := range l { structField := t.Field(i) fieldEntry := v.Field(i) - representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1, false)) + representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1, false, visited)) result = append(result, representation) if len(representation) > longest { longest = len(representation) @@ -478,8 +483,8 @@ func formatStruct(v reflect.Value, indentation uint) string { return fmt.Sprintf("{%s}", strings.Join(result, ", ")) } -func formatInterface(v reflect.Value, indentation uint) string { - return fmt.Sprintf("<%s>%s", formatType(v.Elem()), formatValue(v.Elem(), indentation, false)) +func formatInterface(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string { + return fmt.Sprintf("<%s>%s", formatType(v.Elem()), formatValue(v.Elem(), indentation, false, visited)) } func isNilValue(a reflect.Value) bool { diff --git a/tests/vendor/github.com/onsi/gomega/gomega_dsl.go b/tests/vendor/github.com/onsi/gomega/gomega_dsl.go index af1341bdb..db84085be 100644 --- a/tests/vendor/github.com/onsi/gomega/gomega_dsl.go +++ b/tests/vendor/github.com/onsi/gomega/gomega_dsl.go @@ -22,7 +22,7 @@ import ( "github.com/onsi/gomega/types" ) -const GOMEGA_VERSION = "1.40.0" +const GOMEGA_VERSION = "1.42.1" const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler. If you're using Ginkgo then you probably forgot to put your assertion in an It(). diff --git a/tests/vendor/github.com/onsi/gomega/matchers.go b/tests/vendor/github.com/onsi/gomega/matchers.go index 16ca8f46d..bf5722605 100644 --- a/tests/vendor/github.com/onsi/gomega/matchers.go +++ b/tests/vendor/github.com/onsi/gomega/matchers.go @@ -621,6 +621,18 @@ func BeADirectory() types.GomegaMatcher { return &matchers.BeADirectoryMatcher{} } +// BeASlice succeeds if actual is a value of slice type. +// This is useful when actual has type any (interface{}) and you want to assert it is a slice. +func BeASlice() types.GomegaMatcher { + return &matchers.BeASliceMatcher{} +} + +// BeAnArray succeeds if actual is a value of array type. +// This is useful when actual has type any (interface{}) and you want to assert it is an array. +func BeAnArray() types.GomegaMatcher { + return &matchers.BeAnArrayMatcher{} +} + // HaveHTTPStatus succeeds if the Status or StatusCode field of an HTTP response matches. // Actual must be either a *http.Response or *httptest.ResponseRecorder. // Expected must be either an int or a string. diff --git a/tests/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go b/tests/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go new file mode 100644 index 000000000..4fcad5127 --- /dev/null +++ b/tests/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go @@ -0,0 +1,28 @@ +// untested sections: 1 + +package matchers + +import ( + "fmt" + "reflect" + + "github.com/onsi/gomega/format" +) + +type BeASliceMatcher struct { +} + +func (matcher *BeASliceMatcher) Match(actual any) (success bool, err error) { + if actual == nil { + return false, fmt.Errorf("BeASlice matcher expects a value, got nil") + } + return reflect.TypeOf(actual).Kind() == reflect.Slice, nil +} + +func (matcher *BeASliceMatcher) FailureMessage(actual any) (message string) { + return format.Message(actual, "to be a slice") +} + +func (matcher *BeASliceMatcher) NegatedFailureMessage(actual any) (message string) { + return format.Message(actual, "not to be a slice") +} diff --git a/tests/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go b/tests/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go new file mode 100644 index 000000000..573aa8198 --- /dev/null +++ b/tests/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go @@ -0,0 +1,28 @@ +// untested sections: 1 + +package matchers + +import ( + "fmt" + "reflect" + + "github.com/onsi/gomega/format" +) + +type BeAnArrayMatcher struct { +} + +func (matcher *BeAnArrayMatcher) Match(actual any) (success bool, err error) { + if actual == nil { + return false, fmt.Errorf("BeAnArray matcher expects a value, got nil") + } + return reflect.TypeOf(actual).Kind() == reflect.Array, nil +} + +func (matcher *BeAnArrayMatcher) FailureMessage(actual any) (message string) { + return format.Message(actual, "to be an array") +} + +func (matcher *BeAnArrayMatcher) NegatedFailureMessage(actual any) (message string) { + return format.Message(actual, "not to be an array") +} diff --git a/tests/vendor/github.com/onsi/gomega/types/types.go b/tests/vendor/github.com/onsi/gomega/types/types.go index 685a46f37..e444451ac 100644 --- a/tests/vendor/github.com/onsi/gomega/types/types.go +++ b/tests/vendor/github.com/onsi/gomega/types/types.go @@ -66,6 +66,12 @@ func MatchMayChangeInTheFuture(matcher GomegaMatcher, value any) bool { // AsyncAssertions are returned by Eventually and Consistently and enable matchers to be polled repeatedly to ensure // they are eventually satisfied +// +// The optional optionalDescription argument allows you to annotate the assertion with additional information. +// It is passed as the second argument and can be a format string followed by arguments, or a func() string. +// The description is included in failure messages to provide context. +// +// For details on annotating assertions, see: https://onsi.github.io/gomega/#annotating-assertions type AsyncAssertion interface { Should(matcher GomegaMatcher, optionalDescription ...any) bool ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool @@ -86,6 +92,12 @@ type AsyncAssertion interface { } // Assertions are returned by Ω and Expect and enable assertions against Gomega matchers +// +// The optional optionalDescription argument allows you to annotate the assertion with additional information. +// It is passed as the second argument and can be a format string followed by arguments, or a func() string. +// The description is included in failure messages to provide context. +// +// For details on annotating assertions, see: https://onsi.github.io/gomega/#annotating-assertions type Assertion interface { Should(matcher GomegaMatcher, optionalDescription ...any) bool ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool diff --git a/tests/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/tests/vendor/golang.org/x/crypto/cryptobyte/asn1.go new file mode 100644 index 000000000..d25979d9f --- /dev/null +++ b/tests/vendor/golang.org/x/crypto/cryptobyte/asn1.go @@ -0,0 +1,825 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + encoding_asn1 "encoding/asn1" + "fmt" + "math/big" + "reflect" + "time" + + "golang.org/x/crypto/cryptobyte/asn1" +) + +// This file contains ASN.1-related methods for String and Builder. + +// Builder + +// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Int64(v int64) { + b.addASN1Signed(asn1.INTEGER, v) +} + +// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the +// given tag. +func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) { + b.addASN1Signed(tag, v) +} + +// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. +func (b *Builder) AddASN1Enum(v int64) { + b.addASN1Signed(asn1.ENUM, v) +} + +func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) { + b.AddASN1(tag, func(c *Builder) { + length := 1 + for i := v; i >= 0x80 || i < -0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Uint64(v uint64) { + b.AddASN1(asn1.INTEGER, func(c *Builder) { + length := 1 + for i := v; i >= 0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1BigInt(n *big.Int) { + if b.err != nil { + return + } + + b.AddASN1(asn1.INTEGER, func(c *Builder) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement form. So we + // invert and subtract 1. If the most-significant-bit isn't set then + // we'll need to pad the beginning with 0xff in order to keep the number + // negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + c.add(0xff) + } + c.add(bytes...) + } else if n.Sign() == 0 { + c.add(0) + } else { + bytes := n.Bytes() + if bytes[0]&0x80 != 0 { + c.add(0) + } + c.add(bytes...) + } + }) +} + +// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING. +func (b *Builder) AddASN1OctetString(bytes []byte) { + b.AddASN1(asn1.OCTET_STRING, func(c *Builder) { + c.AddBytes(bytes) + }) +} + +const generalizedTimeFormatStr = "20060102150405Z0700" + +// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME. +func (b *Builder) AddASN1GeneralizedTime(t time.Time) { + if t.Year() < 0 || t.Year() > 9999 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t) + return + } + b.AddASN1(asn1.GeneralizedTime, func(c *Builder) { + c.AddBytes([]byte(t.Format(generalizedTimeFormatStr))) + }) +} + +// AddASN1UTCTime appends a DER-encoded ASN.1 UTCTime. +func (b *Builder) AddASN1UTCTime(t time.Time) { + b.AddASN1(asn1.UTCTime, func(c *Builder) { + // As utilized by the X.509 profile, UTCTime can only + // represent the years 1950 through 2049. + if t.Year() < 1950 || t.Year() >= 2050 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a UTCTime", t) + return + } + c.AddBytes([]byte(t.Format(defaultUTCTimeFormatStr))) + }) +} + +// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not +// support BIT STRINGs that are not a whole number of bytes. +func (b *Builder) AddASN1BitString(data []byte) { + b.AddASN1(asn1.BIT_STRING, func(b *Builder) { + b.AddUint8(0) + b.AddBytes(data) + }) +} + +func (b *Builder) addBase128Int(n int64) { + var length int + if n == 0 { + length = 1 + } else { + for i := n; i > 0; i >>= 7 { + length++ + } + } + + for i := length - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + + b.add(o) + } +} + +func isValidOID(oid encoding_asn1.ObjectIdentifier) bool { + if len(oid) < 2 { + return false + } + + if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) { + return false + } + + for _, v := range oid { + if v < 0 { + return false + } + } + + return true +} + +func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) { + b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) { + if !isValidOID(oid) { + b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid) + return + } + + b.addBase128Int(int64(oid[0])*40 + int64(oid[1])) + for _, v := range oid[2:] { + b.addBase128Int(int64(v)) + } + }) +} + +func (b *Builder) AddASN1Boolean(v bool) { + b.AddASN1(asn1.BOOLEAN, func(b *Builder) { + if v { + b.AddUint8(0xff) + } else { + b.AddUint8(0) + } + }) +} + +func (b *Builder) AddASN1NULL() { + b.add(uint8(asn1.NULL), 0) +} + +// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if +// successful or records an error if one occurred. +func (b *Builder) MarshalASN1(v interface{}) { + // NOTE(martinkr): This is somewhat of a hack to allow propagation of + // encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a + // value embedded into a struct, its tag information is lost. + if b.err != nil { + return + } + bytes, err := encoding_asn1.Marshal(v) + if err != nil { + b.err = err + return + } + b.AddBytes(bytes) +} + +// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag. +// Tags greater than 30 are not supported and result in an error (i.e. +// low-tag-number form only). The child builder passed to the +// BuilderContinuation can be used to build the content of the ASN.1 object. +func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { + if b.err != nil { + return + } + // Identifiers with the low five bits set indicate high-tag-number format + // (two or more octets), which we don't support. + if tag&0x1f == 0x1f { + b.err = fmt.Errorf("cryptobyte: high-tag number identifier octets not supported: 0x%x", tag) + return + } + b.AddUint8(uint8(tag)) + b.addLengthPrefixed(1, true, f) +} + +// String + +// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean +// representation into out and advances. It reports whether the read +// was successful. +func (s *String) ReadASN1Boolean(out *bool) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 { + return false + } + + switch bytes[0] { + case 0: + *out = false + case 0xff: + *out = true + default: + return false + } + + return true +} + +// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does +// not point to an integer, to a big.Int, or to a []byte it panics. Only +// positive and zero values can be decoded into []byte, and they are returned as +// big-endian binary values that share memory with s. Positive values will have +// no leading zeroes, and zero will be returned as a single zero byte. +// ReadASN1Integer reports whether the read was successful. +func (s *String) ReadASN1Integer(out interface{}) bool { + switch out := out.(type) { + case *int, *int8, *int16, *int32, *int64: + var i int64 + if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) { + return false + } + reflect.ValueOf(out).Elem().SetInt(i) + return true + case *uint, *uint8, *uint16, *uint32, *uint64: + var u uint64 + if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) { + return false + } + reflect.ValueOf(out).Elem().SetUint(u) + return true + case *big.Int: + return s.readASN1BigInt(out) + case *[]byte: + return s.readASN1Bytes(out) + default: + panic("out does not point to an integer type") + } +} + +func checkASN1Integer(bytes []byte) bool { + if len(bytes) == 0 { + // An INTEGER is encoded with at least one octet. + return false + } + if len(bytes) == 1 { + return true + } + if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 { + // Value is not minimally encoded. + return false + } + return true +} + +var bigOne = big.NewInt(1) + +func (s *String) readASN1BigInt(out *big.Int) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + // Negative number. + neg := make([]byte, len(bytes)) + for i, b := range bytes { + neg[i] = ^b + } + out.SetBytes(neg) + out.Add(out, bigOne) + out.Neg(out) + } else { + out.SetBytes(bytes) + } + return true +} + +func (s *String) readASN1Bytes(out *[]byte) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + return false + } + for len(bytes) > 1 && bytes[0] == 0 { + bytes = bytes[1:] + } + *out = bytes + return true +} + +func (s *String) readASN1Int64(out *int64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) { + return false + } + return true +} + +func asn1Signed(out *int64, n []byte) bool { + length := len(n) + if length > 8 { + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= int64(n[i]) + } + // Shift up and down in order to sign extend the result. + *out <<= 64 - uint8(length)*8 + *out >>= 64 - uint8(length)*8 + return true +} + +func (s *String) readASN1Uint64(out *uint64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) { + return false + } + return true +} + +func asn1Unsigned(out *uint64, n []byte) bool { + length := len(n) + if length > 9 || length == 9 && n[0] != 0 { + // Too large for uint64. + return false + } + if n[0]&0x80 != 0 { + // Negative number. + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= uint64(n[i]) + } + return true +} + +// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out +// and advances. It reports whether the read was successful and resulted in a +// value that can be represented in an int64. +func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool { + var bytes String + return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes) +} + +// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports +// whether the read was successful. +func (s *String) ReadASN1Enum(out *int) bool { + var bytes String + var i int64 + if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) { + return false + } + if int64(int(i)) != i { + return false + } + *out = int(i) + return true +} + +func (s *String) readBase128Int(out *int) bool { + ret := 0 + for i := 0; len(*s) > 0; i++ { + if i == 5 { + return false + } + // Avoid overflowing int on a 32-bit platform. + // We don't want different behavior based on the architecture. + if ret >= 1<<(31-7) { + return false + } + ret <<= 7 + b := s.read(1)[0] + + // ITU-T X.690, section 8.19.2: + // The subidentifier shall be encoded in the fewest possible octets, + // that is, the leading octet of the subidentifier shall not have the value 0x80. + if i == 0 && b == 0x80 { + return false + } + + ret |= int(b & 0x7f) + if b&0x80 == 0 { + *out = ret + return true + } + } + return false // truncated +} + +// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { + return false + } + + // In the worst case, we get two elements from the first byte (which is + // encoded differently) and then every varint is a single byte long. + components := make([]int, len(bytes)+1) + + // The first varint is 40*value1 + value2: + // According to this packing, value1 can take the values 0, 1 and 2 only. + // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, + // then there are no restrictions on value2. + var v int + if !bytes.readBase128Int(&v) { + return false + } + if v < 80 { + components[0] = v / 40 + components[1] = v % 40 + } else { + components[0] = 2 + components[1] = v - 80 + } + + i := 2 + for ; len(bytes) > 0; i++ { + if !bytes.readBase128Int(&v) { + return false + } + components[i] = v + } + *out = components[:i] + return true +} + +// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { + return false + } + t := string(bytes) + res, err := time.Parse(generalizedTimeFormatStr, t) + if err != nil { + return false + } + if serialized := res.Format(generalizedTimeFormatStr); serialized != t { + return false + } + *out = res + return true +} + +const defaultUTCTimeFormatStr = "060102150405Z0700" + +// ReadASN1UTCTime decodes an ASN.1 UTCTime into out and advances. +// It reports whether the read was successful. +func (s *String) ReadASN1UTCTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.UTCTime) { + return false + } + t := string(bytes) + + formatStr := defaultUTCTimeFormatStr + var err error + res, err := time.Parse(formatStr, t) + if err != nil { + // Fallback to minute precision if we can't parse second + // precision. If we are following X.509 or X.690 we shouldn't + // support this, but we do. + formatStr = "0601021504Z0700" + res, err = time.Parse(formatStr, t) + } + if err != nil { + return false + } + + if serialized := res.Format(formatStr); serialized != t { + return false + } + + if res.Year() >= 2050 { + // UTCTime interprets the low order digits 50-99 as 1950-99. + // This only applies to its use in the X.509 profile. + // See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 + res = res.AddDate(-100, 0, 0) + } + *out = res + return true +} + +// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. +// It reports whether the read was successful. +func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 || + len(bytes)*8/8 != len(bytes) { + return false + } + + paddingBits := bytes[0] + bytes = bytes[1:] + if paddingBits > 7 || + len(bytes) == 0 && paddingBits != 0 || + len(bytes) > 0 && bytes[len(bytes)-1]&(1< 4 || len(*s) < int(2+lenLen) { + return false + } + + lenBytes := String((*s)[2 : 2+lenLen]) + if !lenBytes.readUnsigned(&len32, int(lenLen)) { + return false + } + + // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length + // with the minimum number of octets. + if len32 < 128 { + // Length should have used short-form encoding. + return false + } + if len32>>((lenLen-1)*8) == 0 { + // Leading octet is 0. Length should have been at least one byte shorter. + return false + } + + headerLen = 2 + uint32(lenLen) + if headerLen+len32 < len32 { + // Overflow. + return false + } + length = headerLen + len32 + } + + if int(length) < 0 || !s.ReadBytes((*[]byte)(out), int(length)) { + return false + } + if skipHeader && !out.Skip(int(headerLen)) { + panic("cryptobyte: internal error") + } + + return true +} diff --git a/tests/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/tests/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go new file mode 100644 index 000000000..90ef6a241 --- /dev/null +++ b/tests/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go @@ -0,0 +1,46 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asn1 contains supporting types for parsing and building ASN.1 +// messages with the cryptobyte package. +package asn1 + +// Tag represents an ASN.1 identifier octet, consisting of a tag number +// (indicating a type) and class (such as context-specific or constructed). +// +// Methods in the cryptobyte package only support the low-tag-number form, i.e. +// a single identifier octet with bits 7-8 encoding the class and bits 1-6 +// encoding the tag number. +type Tag uint8 + +const ( + classConstructed = 0x20 + classContextSpecific = 0x80 +) + +// Constructed returns t with the constructed class bit set. +func (t Tag) Constructed() Tag { return t | classConstructed } + +// ContextSpecific returns t with the context-specific class bit set. +func (t Tag) ContextSpecific() Tag { return t | classContextSpecific } + +// The following is a list of standard tag and class combinations. +const ( + BOOLEAN = Tag(1) + INTEGER = Tag(2) + BIT_STRING = Tag(3) + OCTET_STRING = Tag(4) + NULL = Tag(5) + OBJECT_IDENTIFIER = Tag(6) + ENUM = Tag(10) + UTF8String = Tag(12) + SEQUENCE = Tag(16 | classConstructed) + SET = Tag(17 | classConstructed) + PrintableString = Tag(19) + T61String = Tag(20) + IA5String = Tag(22) + UTCTime = Tag(23) + GeneralizedTime = Tag(24) + GeneralString = Tag(27) +) diff --git a/tests/vendor/golang.org/x/crypto/cryptobyte/builder.go b/tests/vendor/golang.org/x/crypto/cryptobyte/builder.go new file mode 100644 index 000000000..cf254f5f1 --- /dev/null +++ b/tests/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -0,0 +1,350 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + "errors" + "fmt" +) + +// A Builder builds byte strings from fixed-length and length-prefixed values. +// Builders either allocate space as needed, or are ‘fixed’, which means that +// they write into a given buffer and produce an error if it's exhausted. +// +// The zero value is a usable Builder that allocates space as needed. +// +// Simple values are marshaled and appended to a Builder using methods on the +// Builder. Length-prefixed values are marshaled by providing a +// BuilderContinuation, which is a function that writes the inner contents of +// the value to a given Builder. See the documentation for BuilderContinuation +// for details. +type Builder struct { + err error + result []byte + fixedSize bool + child *Builder + offset int + pendingLenLen int + pendingIsASN1 bool + inContinuation *bool +} + +// NewBuilder creates a Builder that appends its output to the given buffer. +// Like append(), the slice will be reallocated if its capacity is exceeded. +// Use Bytes to get the final buffer. +func NewBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + } +} + +// NewFixedBuilder creates a Builder that appends its output into the given +// buffer. This builder does not reallocate the output buffer. Writes that +// would exceed the buffer's capacity are treated as an error. +func NewFixedBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + fixedSize: true, + } +} + +// SetError sets the value to be returned as the error from Bytes. Writes +// performed after calling SetError are ignored. +func (b *Builder) SetError(err error) { + b.err = err +} + +// Bytes returns the bytes written by the builder or an error if one has +// occurred during building. +func (b *Builder) Bytes() ([]byte, error) { + if b.err != nil { + return nil, b.err + } + return b.result[b.offset:], nil +} + +// BytesOrPanic returns the bytes written by the builder or panics if an error +// has occurred during building. +func (b *Builder) BytesOrPanic() []byte { + if b.err != nil { + panic(b.err) + } + return b.result[b.offset:] +} + +// AddUint8 appends an 8-bit value to the byte string. +func (b *Builder) AddUint8(v uint8) { + b.add(byte(v)) +} + +// AddUint16 appends a big-endian, 16-bit value to the byte string. +func (b *Builder) AddUint16(v uint16) { + b.add(byte(v>>8), byte(v)) +} + +// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest +// byte of the 32-bit input value is silently truncated. +func (b *Builder) AddUint24(v uint32) { + b.add(byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint32 appends a big-endian, 32-bit value to the byte string. +func (b *Builder) AddUint32(v uint32) { + b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint48 appends a big-endian, 48-bit value to the byte string. +func (b *Builder) AddUint48(v uint64) { + b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint64 appends a big-endian, 64-bit value to the byte string. +func (b *Builder) AddUint64(v uint64) { + b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddBytes appends a sequence of bytes to the byte string. +func (b *Builder) AddBytes(v []byte) { + b.add(v...) +} + +// BuilderContinuation is a continuation-passing interface for building +// length-prefixed byte sequences. Builder methods for length-prefixed +// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation +// supplied to them. The child builder passed to the continuation can be used +// to build the content of the length-prefixed sequence. For example: +// +// parent := cryptobyte.NewBuilder() +// parent.AddUint8LengthPrefixed(func (child *Builder) { +// child.AddUint8(42) +// child.AddUint8LengthPrefixed(func (grandchild *Builder) { +// grandchild.AddUint8(5) +// }) +// }) +// +// It is an error to write more bytes to the child than allowed by the reserved +// length prefix. After the continuation returns, the child must be considered +// invalid, i.e. users must not store any copies or references of the child +// that outlive the continuation. +// +// If the continuation panics with a value of type BuildError then the inner +// error will be returned as the error from Bytes. If the child panics +// otherwise then Bytes will repanic with the same value. +type BuilderContinuation func(child *Builder) + +// BuildError wraps an error. If a BuilderContinuation panics with this value, +// the panic will be recovered and the inner error will be returned from +// Builder.Bytes. +type BuildError struct { + Err error +} + +// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence. +func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(1, false, f) +} + +// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence. +func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(2, false, f) +} + +// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence. +func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(3, false, f) +} + +// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence. +func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(4, false, f) +} + +func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) { + if !*b.inContinuation { + *b.inContinuation = true + + defer func() { + *b.inContinuation = false + + r := recover() + if r == nil { + return + } + + if buildError, ok := r.(BuildError); ok { + b.err = buildError.Err + } else { + panic(r) + } + }() + } + + f(arg) +} + +func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) { + // Subsequent writes can be ignored if the builder has encountered an error. + if b.err != nil { + return + } + + offset := len(b.result) + b.add(make([]byte, lenLen)...) + + if b.inContinuation == nil { + b.inContinuation = new(bool) + } + + b.child = &Builder{ + result: b.result, + fixedSize: b.fixedSize, + offset: offset, + pendingLenLen: lenLen, + pendingIsASN1: isASN1, + inContinuation: b.inContinuation, + } + + b.callContinuation(f, b.child) + b.flushChild() + if b.child != nil { + panic("cryptobyte: internal error") + } +} + +func (b *Builder) flushChild() { + if b.child == nil { + return + } + b.child.flushChild() + child := b.child + b.child = nil + + if child.err != nil { + b.err = child.err + return + } + + length := len(child.result) - child.pendingLenLen - child.offset + + if length < 0 { + panic("cryptobyte: internal error") // result unexpectedly shrunk + } + + if child.pendingIsASN1 { + // For ASN.1, we reserved a single byte for the length. If that turned out + // to be incorrect, we have to move the contents along in order to make + // space. + if child.pendingLenLen != 1 { + panic("cryptobyte: internal error") + } + var lenLen, lenByte uint8 + if int64(length) > 0xfffffffe { + b.err = errors.New("pending ASN.1 child too long") + return + } else if length > 0xffffff { + lenLen = 5 + lenByte = 0x80 | 4 + } else if length > 0xffff { + lenLen = 4 + lenByte = 0x80 | 3 + } else if length > 0xff { + lenLen = 3 + lenByte = 0x80 | 2 + } else if length > 0x7f { + lenLen = 2 + lenByte = 0x80 | 1 + } else { + lenLen = 1 + lenByte = uint8(length) + length = 0 + } + + // Insert the initial length byte, make space for successive length bytes, + // and adjust the offset. + child.result[child.offset] = lenByte + extraBytes := int(lenLen - 1) + if extraBytes != 0 { + child.add(make([]byte, extraBytes)...) + childStart := child.offset + child.pendingLenLen + copy(child.result[childStart+extraBytes:], child.result[childStart:]) + } + child.offset++ + child.pendingLenLen = extraBytes + } + + l := length + for i := child.pendingLenLen - 1; i >= 0; i-- { + child.result[child.offset+i] = uint8(l) + l >>= 8 + } + if l != 0 { + b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen) + return + } + + if b.fixedSize && &b.result[0] != &child.result[0] { + panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer") + } + + b.result = child.result +} + +func (b *Builder) add(bytes ...byte) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted write while child is pending") + } + if len(b.result)+len(bytes) < len(bytes) { + b.err = errors.New("cryptobyte: length overflow") + } + if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) { + b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer") + return + } + b.result = append(b.result, bytes...) +} + +// Unwrite rolls back non-negative n bytes written directly to the Builder. +// An attempt by a child builder passed to a continuation to unwrite bytes +// from its parent will panic. +func (b *Builder) Unwrite(n int) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted unwrite while child is pending") + } + length := len(b.result) - b.pendingLenLen - b.offset + if length < 0 { + panic("cryptobyte: internal error") + } + if n < 0 { + panic("cryptobyte: attempted to unwrite negative number of bytes") + } + if n > length { + panic("cryptobyte: attempted to unwrite more than was written") + } + b.result = b.result[:len(b.result)-n] +} + +// A MarshalingValue marshals itself into a Builder. +type MarshalingValue interface { + // Marshal is called by Builder.AddValue. It receives a pointer to a builder + // to marshal itself into. It may return an error that occurred during + // marshaling, such as unset or invalid values. + Marshal(b *Builder) error +} + +// AddValue calls Marshal on v, passing a pointer to the builder to append to. +// If Marshal returns an error, it is set on the Builder so that subsequent +// appends don't have an effect. +func (b *Builder) AddValue(v MarshalingValue) { + err := v.Marshal(b) + if err != nil { + b.err = err + } +} diff --git a/tests/vendor/golang.org/x/crypto/cryptobyte/string.go b/tests/vendor/golang.org/x/crypto/cryptobyte/string.go new file mode 100644 index 000000000..4b0f8097f --- /dev/null +++ b/tests/vendor/golang.org/x/crypto/cryptobyte/string.go @@ -0,0 +1,183 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cryptobyte contains types that help with parsing and constructing +// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage +// contains useful ASN.1 constants.) +// +// The String type is for parsing. It wraps a []byte slice and provides helper +// functions for consuming structures, value by value. +// +// The Builder type is for constructing messages. It providers helper functions +// for appending values and also for appending length-prefixed submessages – +// without having to worry about calculating the length prefix ahead of time. +// +// See the documentation and examples for the Builder and String types to get +// started. +package cryptobyte + +// String represents a string of bytes. It provides methods for parsing +// fixed-length and length-prefixed values from it. +type String []byte + +// read advances a String by n bytes and returns them. If less than n bytes +// remain, it returns nil. +func (s *String) read(n int) []byte { + if len(*s) < n || n < 0 { + return nil + } + v := (*s)[:n] + *s = (*s)[n:] + return v +} + +// Skip advances the String by n byte and reports whether it was successful. +func (s *String) Skip(n int) bool { + return s.read(n) != nil +} + +// ReadUint8 decodes an 8-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint8(out *uint8) bool { + v := s.read(1) + if v == nil { + return false + } + *out = uint8(v[0]) + return true +} + +// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint16(out *uint16) bool { + v := s.read(2) + if v == nil { + return false + } + *out = uint16(v[0])<<8 | uint16(v[1]) + return true +} + +// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint24(out *uint32) bool { + v := s.read(3) + if v == nil { + return false + } + *out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2]) + return true +} + +// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint32(out *uint32) bool { + v := s.read(4) + if v == nil { + return false + } + *out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3]) + return true +} + +// ReadUint48 decodes a big-endian, 48-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint48(out *uint64) bool { + v := s.read(6) + if v == nil { + return false + } + *out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5]) + return true +} + +// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint64(out *uint64) bool { + v := s.read(8) + if v == nil { + return false + } + *out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7]) + return true +} + +func (s *String) readUnsigned(out *uint32, length int) bool { + v := s.read(length) + if v == nil { + return false + } + var result uint32 + for i := 0; i < length; i++ { + result <<= 8 + result |= uint32(v[i]) + } + *out = result + return true +} + +func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool { + lenBytes := s.read(lenLen) + if lenBytes == nil { + return false + } + var length uint32 + for _, b := range lenBytes { + length = length << 8 + length = length | uint32(b) + } + v := s.read(int(length)) + if v == nil { + return false + } + *outChild = v + return true +} + +// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value +// into out and advances over it. It reports whether the read was successful. +func (s *String) ReadUint8LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(1, out) +} + +// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit +// length-prefixed value into out and advances over it. It reports whether the +// read was successful. +func (s *String) ReadUint16LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(2, out) +} + +// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit +// length-prefixed value into out and advances over it. It reports whether +// the read was successful. +func (s *String) ReadUint24LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(3, out) +} + +// ReadBytes reads n bytes into out and advances over them. It reports +// whether the read was successful. +func (s *String) ReadBytes(out *[]byte, n int) bool { + v := s.read(n) + if v == nil { + return false + } + *out = v + return true +} + +// CopyBytes copies len(out) bytes into out and advances over them. It reports +// whether the copy operation was successful +func (s *String) CopyBytes(out []byte) bool { + n := len(out) + v := s.read(n) + if v == nil { + return false + } + return copy(out, v) == n +} + +// Empty reports whether the string does not contain any bytes. +func (s String) Empty() bool { + return len(s) == 0 +} diff --git a/tests/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/tests/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go index 28cd99c7f..b33212203 100644 --- a/tests/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ b/tests/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -2,24 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC -2898 / PKCS #5 v2.0. - -A key derivation function is useful when encrypting data based on a password -or any other not-fully-random data. It uses a pseudorandom function to derive -a secure encryption key based on the password. - -While v2.0 of the standard defines only one pseudorandom function to use, -HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved -Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To -choose, you can pass the `New` functions from the different SHA packages to -pbkdf2.Key. -*/ +// Package pbkdf2 implements the key derivation function PBKDF2 as defined in +// RFC 8018 (PKCS #5 v2.1). +// +// This package is a wrapper for the PBKDF2 implementation in the +// [crypto/pbkdf2] package. It is [frozen] and is not accepting new features. +// +// [frozen]: https://go.dev/wiki/Frozen package pbkdf2 import ( - "crypto/hmac" + "crypto/pbkdf2" "hash" ) @@ -27,51 +20,11 @@ import ( // []byte of length keylen that can be used as cryptographic key. The key is // derived based on the method described as PBKDF2 with the HMAC variant using // the supplied hash function. -// -// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you -// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by -// doing: -// -// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) -// -// Remember to get a good random salt. At least 8 bytes is recommended by the -// RFC. -// -// Using a higher iteration count will increase the cost of an exhaustive -// search but will also make derivation proportionally slower. func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { - prf := hmac.New(h, password) - hashLen := prf.Size() - numBlocks := (keyLen + hashLen - 1) / hashLen - - var buf [4]byte - dk := make([]byte, 0, numBlocks*hashLen) - U := make([]byte, hashLen) - for block := 1; block <= numBlocks; block++ { - // N.B.: || means concatenation, ^ means XOR - // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter - // U_1 = PRF(password, salt || uint(i)) - prf.Reset() - prf.Write(salt) - buf[0] = byte(block >> 24) - buf[1] = byte(block >> 16) - buf[2] = byte(block >> 8) - buf[3] = byte(block) - prf.Write(buf[:4]) - dk = prf.Sum(dk) - T := dk[len(dk)-hashLen:] - copy(U, T) - - // U_n = PRF(password, U_(n-1)) - for n := 2; n <= iter; n++ { - prf.Reset() - prf.Write(U) - U = U[:0] - U = prf.Sum(U) - for x := range U { - T[x] ^= U[x] - } - } + out, err := pbkdf2.Key(h, string(password), salt, iter, keyLen) + if err != nil { + // FIPS 140 enforcement, or an invalid key length. + panic(err) } - return dk[:keyLen] + return out } diff --git a/tests/vendor/golang.org/x/crypto/ssh/agent/client.go b/tests/vendor/golang.org/x/crypto/ssh/agent/client.go index b357e18b0..eb96184e4 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/tests/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -26,6 +26,7 @@ import ( "io" "math/big" "sync" + "sync/atomic" "golang.org/x/crypto/ssh" ) @@ -307,17 +308,50 @@ func parseKey(in []byte) (out *Key, rest []byte, err error) { }, record.Rest, nil } +// pipelineMaxInFlight is the maximum number of outstanding requests the +// client will pipeline to the agent before applying backpressure. +const pipelineMaxInFlight = 32 + // client is a client for an ssh-agent process. +// +// Exactly one of pipeline / (mu, conn) is set, chosen by NewClient +// based on whether the underlying transport implements io.Closer. type client struct { - // conn is typically a *net.UnixConn + // pipeline, if non-nil, dispatches requests over a pipelined + // connection: requests are written as soon as the wire is + // available and responses are routed back to per-call reply + // channels in FIFO order by a background reader goroutine. + pipeline *pipeline + + // mu and conn are used in fully-serialized mode, when the + // transport does not implement io.Closer. Each call takes mu, + // writes its request, reads the matching response, and releases + // mu before returning. There is no background goroutine. + mu sync.Mutex conn io.ReadWriter - // mu is used to prevent concurrent access to the agent - mu sync.Mutex } // NewClient returns an Agent that talks to an ssh-agent process over // the given connection. +// +// If rw also implements io.Closer (like *net.UnixConn and ssh.Channel +// do), the returned client pipelines concurrent requests over the +// connection: callers can issue Sign and other operations from +// multiple goroutines and they will be written to the agent as soon +// as the wire is available, rather than waiting for the previous +// responses. The ssh-agent protocol still requires responses to be +// returned in request order, so a slow request delays subsequent +// responses on the same connection (head-of-line blocking). +// +// Pipelining requires io.Closer because, on a Write error, the +// background reader goroutine must be unblocked by closing the +// underlying connection. When rw does not implement io.Closer +// this is not possible, so NewClient falls back to fully +// serializing each request: a single in-flight call at a time. func NewClient(rw io.ReadWriter) ExtendedAgent { + if rwc, ok := rw.(io.ReadWriteCloser); ok { + return &client{pipeline: newPipeline(rwc)} + } return &client{conn: rw} } @@ -340,6 +374,16 @@ func (c *client) call(req []byte) (reply interface{}, err error) { // bytes of the response are returned; no unmarshalling is // performed on the response. func (c *client) callRaw(req []byte) (reply []byte, err error) { + if c.pipeline != nil { + return c.pipeline.call(req) + } + return c.serialCall(req) +} + +// serialCall implements the fully-serialized request/response path +// used when the transport is not an io.Closer. It writes req under mu +// and reads the matching response before returning. +func (c *client) serialCall(req []byte) (reply []byte, err error) { c.mu.Lock() defer c.mu.Unlock() @@ -577,6 +621,9 @@ func (c *client) insertKey(s interface{}, comment string, constraints []byte) er Constraints: constraints, }) case ed25519.PrivateKey: + if len(k) != ed25519.PrivateKeySize { + return fmt.Errorf("agent: bad ED25519 key size: %d", len(k)) + } req = ssh.Marshal(ed25519KeyMsg{ Type: ssh.KeyAlgoED25519, Pub: []byte(k)[32:], @@ -588,6 +635,9 @@ func (c *client) insertKey(s interface{}, comment string, constraints []byte) er // general idiom is to pass ed25519.PrivateKey by value, not by pointer. // We still support the pointer variant for backwards compatibility. case *ed25519.PrivateKey: + if len(*k) != ed25519.PrivateKeySize { + return fmt.Errorf("agent: bad ED25519 key size: %d", len(*k)) + } req = ssh.Marshal(ed25519KeyMsg{ Type: ssh.KeyAlgoED25519, Pub: []byte(*k)[32:], @@ -663,6 +713,13 @@ func (c *client) Add(key AddedKey) error { constraints = append(constraints, agentConstrainConfirm) } + for _, ext := range key.ConstraintExtensions { + constraints = append(constraints, ssh.Marshal(constrainExtensionAgentMsg{ + ExtensionName: ext.ExtensionName, + ExtensionDetails: ext.ExtensionDetails, + })...) + } + cert := key.Certificate if cert == nil { return c.insertKey(key.PrivateKey, key.Comment, constraints) @@ -705,6 +762,9 @@ func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string Constraints: constraints, }) case ed25519.PrivateKey: + if len(k) != ed25519.PrivateKeySize { + return fmt.Errorf("agent: bad ED25519 key size: %d", len(k)) + } req = ssh.Marshal(ed25519CertMsg{ Type: cert.Type(), CertBytes: cert.Marshal(), @@ -717,6 +777,9 @@ func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string // general idiom is to pass ed25519.PrivateKey by value, not by pointer. // We still support the pointer variant for backwards compatibility. case *ed25519.PrivateKey: + if len(*k) != ed25519.PrivateKeySize { + return fmt.Errorf("agent: bad ED25519 key size: %d", len(*k)) + } req = ssh.Marshal(ed25519CertMsg{ Type: cert.Type(), CertBytes: cert.Marshal(), @@ -854,3 +917,170 @@ func (c *client) Extension(extensionType string, contents []byte) ([]byte, error return buf, nil } + +// pipelineResult carries either a raw agent reply or an error back to a +// caller waiting on the response channel. +type pipelineResult struct { + reply []byte + err error +} + +// pipeline implements request pipelining over a single agent connection. +// +// Writers serialize on writeMu to both register a reply channel in the +// pending FIFO queue and write the request bytes on the wire; the two +// must be atomic so the queue order matches the wire order. A single +// reader goroutine decodes responses from the connection and dispatches +// each one to the channel at the head of the queue. +// +// pending is a chan-of-chan acting as a FIFO queue with a fixed +// capacity of pipelineMaxInFlight. The outer channel provides ordering +// (reads happen in send order) and natural backpressure (a full queue +// blocks new writers). Each inner channel is buffered with capacity +// one and is sent to exactly once: either by the reader goroutine +// with the agent reply, or by shutdown with the terminal error during +// drain. The cap-one buffer makes the producer's send non-blocking, +// so the reader and shutdown never have to wait for the caller to be +// scheduled on the receive. +// +// When the reader goroutine exits (on read error or protocol +// violation), it closes exitCh to wake any writer blocked on the +// pending queue, then serializes with any in-flight writer to close +// the pending channel, and finally drains the remaining entries +// delivering the terminal error to each waiting caller. The +// pipeline relies on conn implementing io.Closer so a writer that +// hits a Write error can close the connection to unblock the reader +// goroutine; NewClient is responsible for only constructing a +// pipeline when this guarantee holds. +type pipeline struct { + conn io.ReadWriteCloser + + writeMu sync.Mutex + // pending is the FIFO queue of reply channels with capacity + // pipelineMaxInFlight. See type-level documentation. + pending chan chan pipelineResult + exitCh chan struct{} + + // err carries the terminal error to callers blocked on a closed + // pipeline. It is stored exactly once by the reader goroutine + // before exitCh is closed; every read happens after observing + // exitCh closed, so the load synchronises through the close and + // is guaranteed to return the stored value (never nil). + err atomic.Pointer[error] +} + +func newPipeline(conn io.ReadWriteCloser) *pipeline { + p := &pipeline{ + conn: conn, + pending: make(chan chan pipelineResult, pipelineMaxInFlight), + exitCh: make(chan struct{}), + } + go p.readLoop() + return p +} + +// readLoop decodes responses from conn and dispatches them in FIFO order +// to reply channels in pending. On any failure it invokes shutdown. +func (p *pipeline) readLoop() { + var finalErr error + for { + var sizeBuf [4]byte + if _, err := io.ReadFull(p.conn, sizeBuf[:]); err != nil { + finalErr = err + break + } + respSize := binary.BigEndian.Uint32(sizeBuf[:]) + if respSize > maxAgentResponseBytes { + finalErr = errors.New("response too large") + break + } + buf := make([]byte, respSize) + if _, err := io.ReadFull(p.conn, buf); err != nil { + finalErr = err + break + } + // Successful writes always enqueue before sending bytes, so + // pending has a waiting channel for this response. + ch := <-p.pending + // The reply channel is buffered with capacity 1 and is only + // ever written to once, so this send cannot block. + ch <- pipelineResult{reply: buf} + } + p.shutdown(clientErr(finalErr)) +} + +// shutdown is called exactly once, from readLoop, when the reader is +// terminating. It unblocks pending writers and fails all in-flight +// requests with finalErr. +func (p *pipeline) shutdown(finalErr error) { + // Publish the terminal error before closing exitCh so any + // writer that subsequently observes exitCh closed sees err. + p.err.Store(&finalErr) + + // Wake any writer blocked waiting for a slot in the pending queue. + close(p.exitCh) + + // Wait for any writer currently inside its critical section to + // complete. After this lock, no new writer can reach the send on + // pending: they will observe exitCh closed in the select and bail + // out before attempting the send. + p.writeMu.Lock() + close(p.pending) + p.writeMu.Unlock() + + // Drain entries that were enqueued but never answered, delivering + // the terminal error to their waiting callers. The reply channels + // are buffered (cap 1) and written to exactly once, so these sends + // cannot block. + for ch := range p.pending { + ch <- pipelineResult{err: finalErr} + } +} + +// call sends req to the agent and returns the matching raw response. +func (p *pipeline) call(req []byte) ([]byte, error) { + replyCh := make(chan pipelineResult, 1) + + p.writeMu.Lock() + + // Priority check: if the reader has already finished shutdown, + // pending is closed and sending to it would panic. Bail out now. + // Once we pass this check while holding writeMu, shutdown cannot + // complete close(pending) until we release writeMu, so the send + // below is safe against concurrent closure. + select { + case <-p.exitCh: + p.writeMu.Unlock() + return nil, *p.err.Load() + default: + } + + // Enqueue the reply channel before writing the request, so FIFO + // order on the wire matches FIFO order in the pending queue. The + // exitCh arm handles the case where the reader errors while we + // block on a full queue. + select { + case p.pending <- replyCh: + case <-p.exitCh: + p.writeMu.Unlock() + return nil, *p.err.Load() + } + + msg := make([]byte, 4+len(req)) + binary.BigEndian.PutUint32(msg, uint32(len(req))) + copy(msg[4:], req) + _, werr := p.conn.Write(msg) + p.writeMu.Unlock() + + if werr != nil { + // The connection is in an undefined state. Close it so the + // reader unblocks promptly and triggers shutdown for every + // other in-flight caller. NewClient guarantees conn is a + // real io.Closer when the pipeline is in use. + p.conn.Close() + return nil, clientErr(werr) + } + + res := <-replyCh + return res.reply, res.err +} diff --git a/tests/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/tests/vendor/golang.org/x/crypto/ssh/agent/keyring.go index d12987551..a9e29b6f8 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ b/tests/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -32,8 +32,10 @@ type keyring struct { var errLocked = errors.New("agent: locked") -// NewKeyring returns an Agent that holds keys in memory. It is safe -// for concurrent use by multiple goroutines. +// NewKeyring returns an Agent that holds keys in memory. It is safe for +// concurrent use by multiple goroutines. +// +// The returned Agent only supports the "lifetime" constraint. func NewKeyring() Agent { return &keyring{} } @@ -143,15 +145,26 @@ func (r *keyring) List() ([]*Key, error) { return ids, nil } -// Insert adds a private key to the keyring. If a certificate -// is given, that certificate is added as public key. Note that -// any constraints given are ignored. +// Add adds a private key to the keyring. If a certificate is given, that +// certificate is added as public key. +// +// Add returns an error if key contains ConstraintExtensions or +// ConfirmBeforeUse. func (r *keyring) Add(key AddedKey) error { r.mu.Lock() defer r.mu.Unlock() if r.locked { return errLocked } + + if key.ConfirmBeforeUse { + return errors.New("agent: confirm before use constraint is not supported") + } + + if len(key.ConstraintExtensions) > 0 { + return errors.New("agent: constraint extensions are present but not supported") + } + signer, err := ssh.NewSignerFromKey(key.PrivateKey) if err != nil { diff --git a/tests/vendor/golang.org/x/crypto/ssh/agent/server.go b/tests/vendor/golang.org/x/crypto/ssh/agent/server.go index 2a7658cf7..f05d22fb3 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/tests/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -240,13 +240,35 @@ func setConstraints(key *AddedKey, constraintBytes []byte) error { return nil } +// checkRSAKeyParams enforces the same bounds as parseRSA in the ssh +// package, and additionally caps the prime factors. Without this, +// the rsa.PrivateKey built from an Add request would call Precompute() +// on arbitrary inputs; the CRT coefficient recomputation is cubic in +// |p| and can consume excessive CPU on oversized keys. +func checkRSAKeyParams(N, E, P, Q *big.Int) error { + if N.BitLen() > 8192 { + return errors.New("agent: RSA modulus too large") + } + if P.BitLen() > 4096 || Q.BitLen() > 4096 { + return errors.New("agent: RSA prime too large") + } + if E.BitLen() > 24 { + return errors.New("agent: RSA public exponent too large") + } + e := E.Int64() + if e < 3 || e&1 == 0 { + return errors.New("agent: incorrect RSA public exponent") + } + return nil +} + func parseRSAKey(req []byte) (*AddedKey, error) { var k rsaKeyMsg if err := ssh.Unmarshal(req, &k); err != nil { return nil, err } - if k.E.BitLen() > 30 { - return nil, errors.New("agent: RSA public exponent too large") + if err := checkRSAKeyParams(k.N, k.E, k.P, k.Q); err != nil { + return nil, err } priv := &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ @@ -270,6 +292,9 @@ func parseEd25519Key(req []byte) (*AddedKey, error) { if err := ssh.Unmarshal(req, &k); err != nil { return nil, err } + if len(k.Priv) != ed25519.PrivateKeySize { + return nil, fmt.Errorf("agent: bad ED25519 key size: %d", len(k.Priv)) + } priv := ed25519.PrivateKey(k.Priv) addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} @@ -336,6 +361,9 @@ func parseEd25519Cert(req []byte) (*AddedKey, error) { if err != nil { return nil, err } + if len(k.Priv) != ed25519.PrivateKeySize { + return nil, fmt.Errorf("agent: bad ED25519 key size: %d", len(k.Priv)) + } priv := ed25519.PrivateKey(k.Priv) cert, ok := pubKey.(*ssh.Certificate) if !ok { @@ -393,8 +421,8 @@ func parseRSACert(req []byte) (*AddedKey, error) { return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) } - if rsaPub.E.BitLen() > 30 { - return nil, errors.New("agent: RSA public exponent too large") + if err := checkRSAKeyParams(rsaPub.N, rsaPub.E, k.P, k.Q); err != nil { + return nil, err } priv := rsa.PrivateKey{ diff --git a/tests/vendor/golang.org/x/crypto/ssh/certs.go b/tests/vendor/golang.org/x/crypto/ssh/certs.go index 139fa31e1..6f75d77ec 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/certs.go +++ b/tests/vendor/golang.org/x/crypto/ssh/certs.go @@ -348,6 +348,9 @@ func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) if cert.CertType != HostCert { return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) } + if c.IsHostAuthority == nil { + return errors.New("ssh: cannot verify certificate, IsHostAuthority not set") + } if !c.IsHostAuthority(cert.SignatureKey, addr) { return fmt.Errorf("ssh: no authorities for hostname: %v", addr) } @@ -375,6 +378,9 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis if cert.CertType != UserCert { return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) } + if c.IsUserAuthority == nil { + return nil, errors.New("ssh: cannot verify certificate, IsUserAuthority not set") + } if !c.IsUserAuthority(cert.SignatureKey) { return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") } @@ -438,7 +444,17 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { return fmt.Errorf("ssh: cert has expired") } - if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { + // Match OpenSSH: the SK user-presence flag is never enforced on a + // certificate's CA signature. OpenSSH calls sshkey_verify with + // detailsp==NULL in sshkey.c:cert_parse, so the UP/UV flags are + // not even extracted. The UP bit on a CA signature reflects the + // CA operator's presence at signing time, which has no bearing on + // whether the user being authenticated is present now; enforcing + // it here would only break interop with certificates issued by + // non-interactive SK CAs. skKeyWithoutUP is a no-op for non-SK + // keys (the common case). + caKey := skKeyWithoutUP(cert.SignatureKey) + if err := caKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { return fmt.Errorf("ssh: certificate signature does not verify") } diff --git a/tests/vendor/golang.org/x/crypto/ssh/channel.go b/tests/vendor/golang.org/x/crypto/ssh/channel.go index cc0bb7ab6..afc9aef18 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/channel.go +++ b/tests/vendor/golang.org/x/crypto/ssh/channel.go @@ -11,6 +11,7 @@ import ( "io" "log" "sync" + "sync/atomic" ) const ( @@ -131,11 +132,17 @@ func (r RejectionReason) String() string { return fmt.Sprintf("unknown reason %d", int(r)) } -func min(a uint32, b int) uint32 { - if a < uint32(b) { - return a +// minPayloadSize returns min(limit, length) clamped to a uint32. It is used +// to compute the size of the next channel data packet from the remaining +// payload. The comparison is done in int64 because length is an int — on +// 64-bit systems len(data) can exceed 2^32, and a direct uint32(length) +// cast would silently truncate to 0 at every multiple of 2^32, causing +// WriteExtended's loop to spin without making progress. +func minPayloadSize(limit uint32, length int) uint32 { + if int64(length) > int64(limit) { + return limit } - return uint32(b) + return uint32(length) } type channelDirection uint8 @@ -177,6 +184,12 @@ type channel struct { // with WantReply=true outstanding. This lock is held by a // goroutine that has such an outgoing request pending. sentRequestMu sync.Mutex + // sentRequestPending is set to true while a SendRequest call with + // WantReply=true is in flight. handlePacket uses it as a gate: responses + // arriving while no request is pending are dropped to prevent a + // misbehaving peer from stalling the mux read loop by filling ch.msg + // with unsolicited channelRequestSuccess/Failure messages. + sentRequestPending atomic.Bool incomingRequests chan *Request @@ -251,7 +264,7 @@ func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err e ch.writeMu.Unlock() for len(data) > 0 { - space := min(ch.maxRemotePayload, len(data)) + space := minPayloadSize(ch.maxRemotePayload, len(data)) if space, err = ch.remoteWin.reserve(space); err != nil { return n, err } @@ -460,6 +473,18 @@ func (ch *channel) handlePacket(packet []byte) error { } ch.incomingRequests <- &req + case *channelRequestSuccessMsg, *channelRequestFailureMsg: + // Drop responses that arrive when no SendRequest is waiting, to + // prevent a malicious peer from filling ch.msg and stalling the + // mux read loop. The non-blocking send additionally protects the + // loop if a well-behaved caller is slow to read. + if !ch.sentRequestPending.Load() { + return nil + } + select { + case ch.msg <- msg: + default: + } default: ch.msg <- msg } @@ -530,7 +555,17 @@ func (ch *channel) Reject(reason RejectionReason, message string) error { Language: "en", } ch.decided = true - return ch.sendMessage(reject) + err := ch.sendMessage(reject) + + // Remove the channel from the mux to prevent memory leaks. + // Do not call ch.close() here: no goroutine holds a reference to a + // rejected channel's internal channels (msg, incomingRequests), so + // removing it from chanList is sufficient for GC. Calling close() + // would race with the mux loop goroutine (handlePacket or dropAll), + // causing a panic from closing an already-closed channel. + ch.mux.chanList.remove(ch.localId) + + return err } func (ch *channel) Read(data []byte) (int, error) { @@ -586,6 +621,27 @@ func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo if wantReply { ch.sentRequestMu.Lock() defer ch.sentRequestMu.Unlock() + + // Open the gate so that responses arriving while this request is in + // flight are allowed to reach ch.msg. Responses arriving while no + // request is pending are dropped by handlePacket. + ch.sentRequestPending.Store(true) + defer ch.sentRequestPending.Store(false) + + // Drain any spurious responses that may have been buffered. This + // prevents a previously buffered unexpected response from being + // consumed instead of the actual response for this request. + drain: + for { + select { + case _, ok := <-ch.msg: + if !ok { + break drain + } + default: + break drain + } + } } msg := channelRequestMsg{ diff --git a/tests/vendor/golang.org/x/crypto/ssh/cipher.go b/tests/vendor/golang.org/x/crypto/ssh/cipher.go index ad2b37057..48d019954 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/cipher.go +++ b/tests/vendor/golang.org/x/crypto/ssh/cipher.go @@ -407,7 +407,7 @@ func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) return nil, fmt.Errorf("ssh: illegal padding %d", padding) } - if int(padding+1) >= len(plain) { + if int(padding)+1 >= len(plain) { return nil, fmt.Errorf("ssh: padding %d too large", padding) } plain = plain[1 : length-uint32(padding)] diff --git a/tests/vendor/golang.org/x/crypto/ssh/client.go b/tests/vendor/golang.org/x/crypto/ssh/client.go index 33079789b..89f0def9f 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/client.go +++ b/tests/vendor/golang.org/x/crypto/ssh/client.go @@ -88,6 +88,32 @@ func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil } +// NewControlClientConn establishes an SSH connection over an OpenSSH +// ControlMaster socket c in proxy mode. +// +// Note that this package only implements the client side of the multiplexing +// protocol. The provided net.Conn must be a local, secure connection (such as a +// Unix domain socket) connected to an already-running OpenSSH process acting as +// the ControlMaster. +// +// WARNING: Because proxy mode bypasses the standard cryptographic handshake +// passing a standard network connection (e.g., TCP) will result in plaintext +// data leakage. +// +// The Request and NewChannel channels must be serviced or the connection +// will hang. +func NewControlClientConn(c net.Conn) (Conn, <-chan NewChannel, <-chan *Request, error) { + conn := &connection{ + sshConn: sshConn{conn: c}, + } + var err error + if conn.transport, err = handshakeControlProxy(c); err != nil { + return nil, nil, nil, fmt.Errorf("ssh: control proxy handshake failed: %w", err) + } + conn.mux = newMux(conn.transport) + return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil +} + // clientHandshake performs the client side key exchange. See RFC 4253 Section // 7. func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { @@ -197,6 +223,59 @@ type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error // the server. A BannerCallback receives the message sent by the remote server. type BannerCallback func(message string) error +// ClientAuthContext contains information about the current state of the +// authentication process, passed to [ClientAuthCallback]. +type ClientAuthContext struct { + // Metadata contains the connection metadata. + Metadata ConnMetadata + + // Algorithms contains the negotiated algorithms. + Algorithms NegotiatedAlgorithms + + // AllowedMethods lists the authentication methods currently accepted + // by the server. These are the protocol-level names defined in RFC 4252 + // such as "publickey", "password". + AllowedMethods []string + + // PartialSuccessMethods lists the authentication methods that have already + // succeeded, indicating a multi-step authentication flow. This list + // represents the exact sequence of partial successes and may contain + // duplicates if the same method succeeded multiple times. + PartialSuccessMethods []string + + // TriedMethods lists the methods that have already been attempted and + // failed during this session. This list represents the exact sequence of + // failures and may contain duplicates. This allows the callback to also + // track the number of failed attempts for a specific method. + TriedMethods []string +} + +// ClientAuthCallback is a hook invoked before each authentication attempt. It +// allows the client to dynamically select an authentication method based on the +// current context, server capabilities, or previous failures. +// +// The callback is invoked after the initial "none" authentication method, once +// the server's supported authentication methods are known. +// +// Return values: +// - (AuthMethod, nil): The client will attempt this specific method next. +// The returned method does NOT need to be present in [ClientConfig.Auth]. +// This allows for dynamic authentication strategies (e.g., prompting +// for a password only if public key auth fails). Callers should inspect +// [ClientAuthContext.TriedMethods] to avoid repeatedly returning the +// same failing method. +// - (nil, nil): The client selects from [ClientConfig.Auth] the first +// instance of a method that has not been tried yet, or aborts if none +// are left. If authentication is not successful, the callback is invoked +// again before the following attempt. +// - (nil, error): The authentication process is aborted immediately, +// causing the ongoing SSH handshake to fail with the provided error. +// +// To bound resource use, the client caps the total number of authentication +// attempts (failures and partial successes combined) at 64. If the cap is +// exceeded the handshake aborts with an error. +type ClientAuthCallback func(ctx *ClientAuthContext) (AuthMethod, error) + // A ClientConfig structure is used to configure a Client. It must not be // modified after having been passed to an SSH function. type ClientConfig struct { @@ -210,6 +289,9 @@ type ClientConfig struct { // Auth contains possible authentication methods to use with the // server. Only the first instance of a particular RFC 4252 method will // be used during authentication. + // + // If AuthCallback is set, these AuthMethod are only used if the + // callback returns nil. Auth []AuthMethod // HostKeyCallback is called during the cryptographic @@ -240,6 +322,9 @@ type ClientConfig struct { // // A Timeout of zero means no timeout. Timeout time.Duration + + // AuthCallback, if non-nil, is invoked before each authentication attempt. + AuthCallback ClientAuthCallback } // InsecureIgnoreHostKey returns a function that can be used for diff --git a/tests/vendor/golang.org/x/crypto/ssh/client_auth.go b/tests/vendor/golang.org/x/crypto/ssh/client_auth.go index 4f2f75c36..60af2fc4d 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/tests/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -21,6 +21,12 @@ const ( authSuccess ) +// maxAuthClientTried bounds the total number of authentication attempts +// (failures and partial successes combined) the client makes before +// aborting the loop, to prevent unbounded growth when an AuthCallback +// keeps supplying methods. +const maxAuthClientTried = 64 + // clientAuthenticate authenticates with the remote server. See RFC 4252. func (c *connection) clientAuthenticate(config *ClientConfig) error { // initiate user auth session @@ -67,32 +73,62 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { // then any untried methods suggested by the server. var tried []string var lastMethods []string + var partialSuccess []string sessionID := c.transport.getSessionID() for auth := AuthMethod(new(noneAuth)); auth != nil; { ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions) if err != nil { // On disconnect, return error immediately - if _, ok := err.(*disconnectMsg); ok { + if _, isDisconnect := err.(*disconnectMsg); isDisconnect { return err } - // We return the error later if there is no other method left to - // try. + // We return the error later if there is no other method + // left to try. ok = authFailure } - if ok == authSuccess { - // success + + switch ok { + case authSuccess: return nil - } else if ok == authFailure { - if m := auth.method(); !slices.Contains(tried, m) { - tried = append(tried, m) - } + case authPartialSuccess: + partialSuccess = append(partialSuccess, auth.method()) + case authFailure: + tried = append(tried, auth.method()) } + if len(partialSuccess)+len(tried) > maxAuthClientTried { + return fmt.Errorf("ssh: too many authentication attempts (%d), aborting", + len(partialSuccess)+len(tried)) + } + if methods == nil { methods = lastMethods } lastMethods = methods + // If AuthCallback is set it takes precedence: it picks the next + // AuthMethod dynamically. The returned method need not be in + // config.Auth. If the callback returns (nil, nil) we fall back to + // selecting the next untried method from config.Auth below; on + // (nil, error) the handshake aborts. + if config.AuthCallback != nil { + ctx := &ClientAuthContext{ + Metadata: c, + Algorithms: c.Algorithms(), + AllowedMethods: slices.Clone(methods), + PartialSuccessMethods: slices.Clone(partialSuccess), + TriedMethods: slices.Clone(tried), + } + altAuth, cbErr := config.AuthCallback(ctx) + if cbErr != nil { + return cbErr + } + if altAuth != nil { + auth = altAuth + continue + } + } + auth = nil findNext: @@ -377,11 +413,11 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand return authFailure, nil, err } - // If authentication succeeds or the list of available methods does not - // contain the "publickey" method, do not attempt to authenticate with any - // other keys. According to RFC 4252 Section 7, the latter can occur when - // additional authentication methods are required. - if success == authSuccess || !slices.Contains(methods, cb.method()) { + // If authentication succeeds or partially succeeds, return immediately + // so the caller can select the next auth method. According to RFC 4252 + // Section 7, if the server no longer lists "publickey" among its + // allowed methods, do not attempt to authenticate with any other keys. + if success == authSuccess || success == authPartialSuccess || !slices.Contains(methods, cb.method()) { return success, methods, err } } diff --git a/tests/vendor/golang.org/x/crypto/ssh/connection.go b/tests/vendor/golang.org/x/crypto/ssh/connection.go index 613a71a7b..378f6407b 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/connection.go +++ b/tests/vendor/golang.org/x/crypto/ssh/connection.go @@ -91,9 +91,17 @@ func DiscardRequests(in <-chan *Request) { } } +// A connTransport represents the transport for a connection. +type connTransport interface { + packetConn + getAlgorithms() NegotiatedAlgorithms + getSessionID() []byte + waitSession() error +} + // A connection represents an incoming connection. type connection struct { - transport *handshakeTransport + transport connTransport sshConn // The connection protocol. diff --git a/tests/vendor/golang.org/x/crypto/ssh/control.go b/tests/vendor/golang.org/x/crypto/ssh/control.go new file mode 100644 index 000000000..9b14e4caf --- /dev/null +++ b/tests/vendor/golang.org/x/crypto/ssh/control.go @@ -0,0 +1,155 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + + "golang.org/x/crypto/cryptobyte" +) + +const ( + muxProtocolVersion = 4 + + muxMsgHello = 0x00000001 + muxCProxy = 0x1000000f + muxSProxy = 0x8000000f +) + +const controlProxyRequestID = 0 + +// handshakeControlProxy attempts to establish a transport connection with an +// OpenSSH ControlMaster socket in proxy mode. For details see: +// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.mux +func handshakeControlProxy(rw io.ReadWriteCloser) (connTransport, error) { + if err := controlProxyWritePacket(rw, func(b *cryptobyte.Builder) { + b.AddUint32(muxMsgHello) + b.AddUint32(muxProtocolVersion) + }); err != nil { + return nil, fmt.Errorf("mux hello write failed: %w", err) + } + if err := controlProxyWritePacket(rw, func(b *cryptobyte.Builder) { + b.AddUint32(muxCProxy) + b.AddUint32(controlProxyRequestID) + }); err != nil { + return nil, fmt.Errorf("mux client proxy write failed: %w", err) + } + + messageType, body, err := controlProxyReadMessage(rw) + if err != nil { + return nil, fmt.Errorf("mux hello read failed: %w", err) + } + if messageType != muxMsgHello { + return nil, fmt.Errorf("expected hello response, got %v", messageType) + } + var v uint32 + if !body.ReadUint32(&v) { + return nil, errors.New("EOF reading mux protocol version") + } + if v != muxProtocolVersion { + return nil, fmt.Errorf("mux server has unsupported version %v", v) + } + messageType, body, err = controlProxyReadMessage(rw) + if err != nil { + return nil, fmt.Errorf("mux server proxy read failed: %w", err) + } + if messageType != muxSProxy { + return nil, fmt.Errorf("expected server proxy response, got %v", messageType) + } + var reqID uint32 + if !body.ReadUint32(&reqID) { + return nil, errors.New("EOF reading request id") + } + if reqID != controlProxyRequestID { + return nil, fmt.Errorf("expected request id %v, got %v", controlProxyRequestID, reqID) + } + return &controlProxyTransport{rw}, nil +} + +// controlProxyTransport implements the connTransport interface for +// ControlMaster connections. Each controlMessage has zero length padding and +// no MAC. +type controlProxyTransport struct { + rw io.ReadWriteCloser +} + +func (p *controlProxyTransport) Close() error { + return p.rw.Close() +} + +func (p *controlProxyTransport) writePacket(controlMessage []byte) error { + return controlProxyWritePacket(p.rw, func(b *cryptobyte.Builder) { + b.AddUint8(0) // Padding length. + b.AddBytes(controlMessage) + }) +} + +func (p *controlProxyTransport) readPacket() ([]byte, error) { + buf, err := controlProxyReadPacket(p.rw) + if err != nil { + return nil, fmt.Errorf("ssh: error reading control message: %w", err) + } + // Discard the padding length. + if len(buf) < 1 { + return nil, errors.New("ssh: EOF reading padding length") + } + if buf[0] != 0 { + return nil, errors.New("ssh: unexpected non-zero padding in control message") + } + return buf[1:], nil +} + +func (p *controlProxyTransport) getAlgorithms() NegotiatedAlgorithms { + return NegotiatedAlgorithms{} +} + +func (p *controlProxyTransport) getSessionID() []byte { + return nil +} + +func (p *controlProxyTransport) waitSession() error { + return nil +} + +func controlProxyWritePacket(w io.Writer, f cryptobyte.BuilderContinuation) error { + var buf []byte + b := cryptobyte.NewBuilder(buf) + b.AddUint32LengthPrefixed(f) + out, err := b.Bytes() + if err != nil { + return err + } + _, err = w.Write(out) + return err +} + +func controlProxyReadPacket(r io.Reader) (cryptobyte.String, error) { + var l uint32 + if err := binary.Read(r, binary.BigEndian, &l); err != nil { + return nil, err + } + if l > maxPacket { + return nil, fmt.Errorf("message length %v exceeds maximum %v", l, maxPacket) + } + buf := make([]byte, l) + if _, err := io.ReadFull(r, buf); err != nil { + return nil, err + } + return buf, nil +} + +func controlProxyReadMessage(r io.Reader) (messageType uint32, body cryptobyte.String, err error) { + body, err = controlProxyReadPacket(r) + if err != nil { + return 0, nil, fmt.Errorf("error reading message body: %w", err) + } + if !body.ReadUint32(&messageType) { + return 0, nil, errors.New("EOF reading message type") + } + return messageType, body, nil +} diff --git a/tests/vendor/golang.org/x/crypto/ssh/kex.go b/tests/vendor/golang.org/x/crypto/ssh/kex.go index 5f7fdd851..91b771c4a 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/kex.go +++ b/tests/vendor/golang.org/x/crypto/ssh/kex.go @@ -16,6 +16,7 @@ import ( "io" "math/big" "slices" + "sync" "golang.org/x/crypto/curve25519" ) @@ -718,15 +719,9 @@ func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshak kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits) } - var p *big.Int - // We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072 - // bits) or Oakley Group 16 (4096 bits), based on the requested max size. - if kexDHGexRequest.MaxBits < 3072 { - p, _ = new(big.Int).SetString(oakleyGroup14, 16) - } else if kexDHGexRequest.MaxBits < 4096 { - p, _ = new(big.Int).SetString(oakleyGroup15, 16) - } else { - p, _ = new(big.Int).SetString(oakleyGroup16, 16) + p, err := chooseDH(kexDHGexRequest) + if err != nil { + return nil, err } g := big.NewInt(2) @@ -805,3 +800,65 @@ func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshak Hash: gex.hashFunc, }, err } + +type dhKEXGroup struct { + size int + p *big.Int +} + +// supportedDHKEXGroups returns the DH groups the server is willing to offer +// for diffie-hellman-group-exchange-* key exchanges. The list is built lazily +// on first use to keep the hex-to-big.Int parse out of package initialization. +var supportedDHKEXGroups = sync.OnceValue(func() []dhKEXGroup { + specs := []struct { + size int + hex string + }{ + {2048, oakleyGroup14}, + {3072, oakleyGroup15}, + {4096, oakleyGroup16}, + } + out := make([]dhKEXGroup, 0, len(specs)) + for _, s := range specs { + p, _ := new(big.Int).SetString(s.hex, 16) + out = append(out, dhKEXGroup{size: s.size, p: p}) + } + return out +}) + +// chooseDH picks a DH group for the given client request, mirroring the +// algorithm used by OpenSSH's choose_dh in dh.c: prefer the smallest known +// group larger than or equal to the client's PreferredBits, and otherwise pick +// the largest group within the accepted [MinBits, MaxBits] range. +func chooseDH(req kexDHGexRequestMsg) (*big.Int, error) { + var best *big.Int + bestSize := 0 + wantBits := int(req.PreferredBits) + + for _, group := range supportedDHKEXGroups() { + if uint32(group.size) < req.MinBits || uint32(group.size) > req.MaxBits { + continue + } + + if bestSize == 0 { + best = group.p + bestSize = group.size + continue + } + + closerFromAbove := group.size >= wantBits && group.size < bestSize + closerFromBelow := group.size > bestSize && bestSize < wantBits + + if closerFromAbove || closerFromBelow { + best = group.p + bestSize = group.size + } + } + + if bestSize == 0 { + return nil, fmt.Errorf("ssh: no suitable DH group found for request min: %d, preferred: %d, max: %d", + req.MinBits, req.PreferredBits, req.MaxBits) + } + + return best, nil +} diff --git a/tests/vendor/golang.org/x/crypto/ssh/keys.go b/tests/vendor/golang.org/x/crypto/ssh/keys.go index 47a07539d..334861b7f 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/keys.go +++ b/tests/vendor/golang.org/x/crypto/ssh/keys.go @@ -76,7 +76,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err case InsecureKeyAlgoDSA: return parseDSA(in) case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: - return parseECDSA(in) + return parseECDSA(in, algo) case KeyAlgoSKECDSA256: return parseSKECDSA(in) case KeyAlgoED25519: @@ -469,6 +469,12 @@ func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { return nil, nil, err } + // 8192 bits is also the maximum RSA key size accepted by crypto/tls for + // signature verification: + // https://github.com/golang/go/blob/69801b25/src/crypto/tls/handshake_client.go#L1096 + if w.N.BitLen() > 8192 { + return nil, nil, errors.New("ssh: rsa modulus too large") + } if w.E.BitLen() > 24 { return nil, nil, errors.New("ssh: exponent too large") } @@ -574,6 +580,24 @@ func checkDSAParams(param *dsa.Parameters) error { return fmt.Errorf("ssh: unsupported DSA key size %d", l) } + // FIPS 186-2 specifies that Q must be exactly 160 bits. We must enforce + // this to prevent DoS attacks where an attacker sends a huge Q which makes + // verification slow. + if l := param.Q.BitLen(); l != 160 { + return fmt.Errorf("ssh: unsupported DSA sub-prime size %d", l) + } + + // The generator G is an element of the group, so it must be strictly less + // than the modulus P. + if param.G.Cmp(param.P) >= 0 { + return errors.New("ssh: DSA generator larger than modulus") + } + + // G must be positive. + if param.G.Sign() <= 0 { + return errors.New("ssh: DSA generator must be positive") + } + return nil } @@ -596,6 +620,14 @@ func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { return nil, nil, err } + // The public value Y must be a non-zero element of the group, i.e. + // strictly between 0 and P. crypto/dsa.Verify does not range-check Y, + // so we reject out-of-range values here to prevent a maliciously + // oversized Y from slowing verification. + if w.Y.Sign() <= 0 || w.Y.Cmp(w.P) >= 0 { + return nil, nil, errors.New("ssh: DSA public value Y out of range") + } + key := &dsaPublicKey{ Parameters: param, Y: w.Y, @@ -774,7 +806,7 @@ func supportedEllipticCurve(curve elliptic.Curve) bool { } // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. -func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { +func parseECDSA(in []byte, expectedType string) (out PublicKey, rest []byte, err error) { var w struct { Curve string KeyBytes []byte @@ -785,6 +817,12 @@ func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { return nil, nil, err } + actualType := "ecdsa-sha2-" + w.Curve + if expectedType != actualType { + return nil, nil, fmt.Errorf("ssh: algorithm type mismatch: expected %q, found curve %q (type %q)", + expectedType, w.Curve, actualType) + } + key := new(ecdsa.PublicKey) switch w.Curve { @@ -869,11 +907,25 @@ type skFields struct { Counter uint32 } +// flagUserPresence is the "user present" bit (UP) in the SK signature +// flags, matching the FIDO CTAP2 authenticatorData UP flag. See +// openssh/PROTOCOL.u2f. +const flagUserPresence = 0x01 + +// errSKMissingUserPresence is returned by SK key Verify methods when +// the signature does not assert user presence and the key was not +// marked as no-touch-required. +var errSKMissingUserPresence = errors.New("ssh: signature missing required user presence flag") + type skECDSAPublicKey struct { // application is a URL-like string, typically "ssh:" for SSH. // see openssh/PROTOCOL.u2f for details. application string ecdsa.PublicKey + // noTouchRequired, when true, disables the default user-presence + // check in Verify. It is set by skKeyWithoutUP on a clone of the + // key, never on an instance shared across authentication attempts. + noTouchRequired bool } func (k *skECDSAPublicKey) Type() string { @@ -959,6 +1011,10 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error { return err } + if skf.Flags&flagUserPresence == 0 && !k.noTouchRequired { + return errSKMissingUserPresence + } + blob := struct { ApplicationDigest []byte `ssh:"rest"` Flags byte @@ -992,6 +1048,10 @@ type skEd25519PublicKey struct { // see openssh/PROTOCOL.u2f for details. application string ed25519.PublicKey + // noTouchRequired, when true, disables the default user-presence + // check in Verify. It is set by skKeyWithoutUP on a clone of the + // key, never on an instance shared across authentication attempts. + noTouchRequired bool } func (k *skEd25519PublicKey) Type() string { @@ -1066,6 +1126,10 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error { return err } + if skf.Flags&flagUserPresence == 0 && !k.noTouchRequired { + return errSKMissingUserPresence + } + blob := struct { ApplicationDigest []byte `ssh:"rest"` Flags byte @@ -1408,6 +1472,17 @@ func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc { return nil, err } + // OpenSSH does not impose an upper bound on the bcrypt round count + // stored in the key file, but bcrypt_pbkdf cost is linear in rounds: + // the default is 16, ssh-keygen lets users pick anything up to + // INT_MAX. Cap at 2048 (128x the default, a few seconds of CPU) so + // that an oversized value in the file cannot tie up the caller for + // months. + const maxRounds = 1 << 11 + if opts.Rounds > maxRounds { + return nil, fmt.Errorf("ssh: bcrypt KDF rounds %d exceed maximum %d", opts.Rounds, maxRounds) + } + k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16) if err != nil { return nil, err @@ -1577,10 +1652,28 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv return nil, err } + // Mirror the validation done in parseRSA for public keys: cap the + // modulus at the same limit enforced by crypto/tls, reject oversized + // or invalid exponents, and additionally bound the prime factors to + // avoid the expensive CRT coefficient recomputation in pk.Precompute. + if key.N.BitLen() > 8192 { + return nil, errors.New("ssh: rsa modulus too large") + } + if key.P.BitLen() > 4096 || key.Q.BitLen() > 4096 { + return nil, errors.New("ssh: rsa prime too large") + } + if key.E.BitLen() > 24 { + return nil, errors.New("ssh: exponent too large") + } + e := key.E.Int64() + if e < 3 || e&1 == 0 { + return nil, errors.New("ssh: incorrect exponent") + } + pk := &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: key.N, - E: int(key.E.Int64()), + E: int(e), }, D: key.D, Primes: []*big.Int{key.P, key.Q}, diff --git a/tests/vendor/golang.org/x/crypto/ssh/mux.go b/tests/vendor/golang.org/x/crypto/ssh/mux.go index d2d24c635..5775881c6 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/mux.go +++ b/tests/vendor/golang.org/x/crypto/ssh/mux.go @@ -91,9 +91,10 @@ type mux struct { incomingChannels chan NewChannel - globalSentMu sync.Mutex - globalResponses chan interface{} - incomingRequests chan *Request + globalSentMu sync.Mutex + globalSentPending atomic.Bool + globalResponses chan interface{} + incomingRequests chan *Request errCond *sync.Cond err error @@ -141,6 +142,27 @@ func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, [] if wantReply { m.globalSentMu.Lock() defer m.globalSentMu.Unlock() + + // Open the gate so that responses arriving while this request is in + // flight are allowed to reach globalResponses. Any response arriving + // while no request is pending is dropped by handleGlobalPacket. + m.globalSentPending.Store(true) + defer m.globalSentPending.Store(false) + + // Drain any spurious responses that may have been buffered. This prevents + // a previously buffered unexpected response from being consumed instead + // of the actual response for this request. + drain: + for { + select { + case _, ok := <-m.globalResponses: + if !ok { + break drain + } + default: + break drain + } + } } if err := m.sendMessage(globalRequestMsg{ @@ -267,7 +289,16 @@ func (m *mux) handleGlobalPacket(packet []byte) error { mux: m, } case *globalRequestSuccessMsg, *globalRequestFailureMsg: - m.globalResponses <- msg + // Drop responses that arrive when no SendRequest is waiting, to + // prevent a malicious peer from staging responses for a future + // caller. + if !m.globalSentPending.Load() { + return nil + } + select { + case m.globalResponses <- msg: + default: + } default: panic(fmt.Sprintf("not a global message %#v", msg)) } diff --git a/tests/vendor/golang.org/x/crypto/ssh/server.go b/tests/vendor/golang.org/x/crypto/ssh/server.go index 064dcbaf5..3c0fcc953 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/server.go +++ b/tests/vendor/golang.org/x/crypto/ssh/server.go @@ -34,21 +34,29 @@ type Permissions struct { // or not supported. CriticalOptions map[string]string - // Extensions are extra functionality that the server may - // offer on authenticated connections. Lack of support for an - // extension does not preclude authenticating a user. Common - // extensions are "permit-agent-forwarding", - // "permit-X11-forwarding". The Go SSH library currently does - // not act on any extension, and it is up to server - // implementations to honor them. Extensions can be used to - // pass data from the authentication callbacks to the server - // application layer. + // Extensions are extra functionality that the server may offer on + // authenticated connections. Lack of support for an extension does not + // preclude authenticating a user. Common extensions are + // "permit-agent-forwarding", "permit-X11-forwarding". In general the Go + // SSH library does not act on extensions and it is up to server + // implementations to honor them; extensions can also be used to pass data + // from the authentication callbacks to the server application layer. + // + // The one extension acted upon by this library is "no-touch-required", + // which applies only to security-key public keys + // (sk-ecdsa-sha2-nistp256@openssh.com and sk-ssh-ed25519@openssh.com). + // When present, it waives the default requirement that SK signatures + // assert user presence (i.e. a physical touch of the authenticator) + // during signature verification. Extensions map[string]string // ExtraData allows to store user defined data. ExtraData map[any]any } +// GSSAPIWithMICConfig includes the server callbacks for gssapi-with-mic +// authentication. If either field is nil, gssapi-with-mic is considered not +// configured. type GSSAPIWithMICConfig struct { // AllowLogin, must be set, is called when gssapi-with-mic // authentication is selected (RFC 4462 section 3). The srcName is from the @@ -63,6 +71,10 @@ type GSSAPIWithMICConfig struct { Server GSSAPIServer } +func gssapiWithMICConfigured(config *GSSAPIWithMICConfig) bool { + return config != nil && config.AllowLogin != nil && config.Server != nil +} + // SendAuthBanner implements [ServerPreAuthConn]. func (s *connection) SendAuthBanner(msg string) error { return s.transport.writePacket(Marshal(&userAuthBannerMsg{ @@ -84,6 +96,79 @@ type ServerPreAuthConn interface { SendAuthBanner(string) error } +// noTouchRequiredExtension is the extension name used by OpenSSH in +// authorized_keys options and certificate extensions to mark keys +// whose signatures do not need to assert user presence (touch). See +// ssh-keygen(1) and sshd(8). +const noTouchRequiredExtension = "no-touch-required" + +// noTouchAllowed reports whether the user presence requirement on +// SK signatures should be waived for this authentication attempt. The +// requirement is waived when the "no-touch-required" extension is +// present either in the Permissions returned by the auth callback +// (authorized_keys-level opt-out) or in the certificate's own +// Extensions (CA-level opt-out), matching OpenSSH behavior. OpenSSH +// reads the per-key opt-out only from cert Extensions and +// authorized_keys options (never from CriticalOptions); we follow the +// same rule. +func noTouchAllowed(pubKey PublicKey, perms *Permissions) bool { + if perms != nil { + if _, ok := perms.Extensions[noTouchRequiredExtension]; ok { + return true + } + } + if cert, ok := pubKey.(*Certificate); ok { + if _, ok := cert.Extensions[noTouchRequiredExtension]; ok { + return true + } + } + return false +} + +// skKeyWithoutUP returns a PublicKey equivalent to pubKey but whose +// Verify accepts SK signatures with the user-presence flag clear. If +// pubKey is not (and does not wrap) an SK key, pubKey is returned +// unchanged. The returned value never mutates pubKey: for SK keys a +// shallow copy is made so that the noTouchRequired flag is set only on +// the clone. +// +// The implementation is iterative rather than recursive. When pubKey +// is a *Certificate we unwrap exactly one level to look at the inner +// key. The SSH cert format forbids Certificate.Key from being another +// Certificate (parseCert rejects it), but nothing stops callers from +// constructing such a value directly in Go; a recursive descent could +// otherwise be driven to unbounded depth by a hand-crafted or cyclic +// Certificate. A malformed input of that shape simply returns +// unchanged here. +func skKeyWithoutUP(pubKey PublicKey) PublicKey { + cert, isCert := pubKey.(*Certificate) + target := pubKey + if isCert { + target = cert.Key + } + var cloned PublicKey + switch k := target.(type) { + case *skECDSAPublicKey: + c := *k + c.noTouchRequired = true + cloned = &c + case *skEd25519PublicKey: + c := *k + c.noTouchRequired = true + cloned = &c + default: + // Not an SK key (or a pathological *Certificate wrapping + // another *Certificate): pubKey is already usable for Verify. + return pubKey + } + if !isCert { + return cloned + } + c := *cert + c.Key = cloned + return &c +} + // ServerConfig holds server specific configuration data. type ServerConfig struct { // Config contains configuration shared between client and server. @@ -242,8 +327,10 @@ func (c *pubKeyCache) add(candidate cachedPubKey) { type ServerConn struct { Conn - // If the succeeding authentication callback returned a - // non-nil Permissions pointer, it is stored here. + // If the succeeding authentication callback returned a non-nil Permissions + // pointer, it is stored here. These are the permissions from the final, + // successful authentication method. Permissions returned by callbacks that + // return PartialSuccessError are not preserved and must be nil. Permissions *Permissions } @@ -302,8 +389,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) } if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && - config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil || - config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) { + config.KeyboardInteractiveCallback == nil && !gssapiWithMICConfigured(config.GSSAPIWithMICConfig) { return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") } @@ -527,6 +613,15 @@ func (b *BannerError) Error() string { return b.Err.Error() } +// maxAuthServerAttempts caps the total number of SSH_MSG_USERAUTH_REQUEST +// messages the server will process on a single connection, regardless of +// outcome (failure, partial success, public key query, or none). It is a +// backstop against clients that drive the authentication loop indefinitely +// without ever incurring a real failure — for example by repeatedly +// triggering PartialSuccessError or by spamming public key offer queries — +// neither of which increment the MaxAuthTries failure counter. +const maxAuthServerAttempts = 128 + func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { if config.PreAuthConnCallback != nil { config.PreAuthConnCallback(s) @@ -537,6 +632,7 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err var perms *Permissions authFailures := 0 + authAttempts := 0 noneAuthCount := 0 var authErrs []error var calledBannerCallback bool @@ -565,6 +661,19 @@ userAuthLoop: return nil, &ServerAuthError{Errors: authErrs} } + if authAttempts >= maxAuthServerAttempts { + discMsg := &disconnectMsg{ + Reason: 2, + Message: "too many authentication attempts", + } + if err := s.transport.writePacket(Marshal(discMsg)); err != nil { + return nil, err + } + authErrs = append(authErrs, discMsg) + return nil, &ServerAuthError{Errors: authErrs} + } + authAttempts++ + var userAuthReq userAuthRequestMsg if packet, err := s.transport.readPacket(); err != nil { if err == io.EOF { @@ -737,8 +846,15 @@ userAuthLoop: } signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData) - - if err := pubKey.Verify(signedData, sig); err != nil { + // pubKey is reused below for VerifiedPublicKeyCallback and + // must remain the key as presented by the client; derive a + // separate value for Verify that carries any applicable + // no-touch-required opt-out. + pubKeyForVerify := pubKey + if noTouchAllowed(pubKey, candidate.perms) { + pubKeyForVerify = skKeyWithoutUP(pubKey) + } + if err := pubKeyForVerify.Verify(signedData, sig); err != nil { return nil, err } @@ -750,9 +866,16 @@ userAuthLoop: // considered verified and the callback must not run. perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo) } + if authErr == nil && perms != nil && perms.CriticalOptions != nil { + if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" { + if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil { + authErr = err + } + } + } } case "gssapi-with-mic": - if authConfig.GSSAPIWithMICConfig == nil { + if !gssapiWithMICConfigured(authConfig.GSSAPIWithMICConfig) { authErr = errors.New("ssh: gssapi-with-mic auth not configured") break } @@ -824,6 +947,13 @@ userAuthLoop: var failureMsg userAuthFailureMsg if partialSuccess, ok := authErr.(*PartialSuccessError); ok { + // Permissions are not preserved between authentication steps. To + // avoid confusion about the final state of the connection, we + // disallow returning non-nil Permissions combined with + // PartialSuccessError. + if perms != nil { + return nil, errors.New("ssh: permissions must be nil when returning PartialSuccessError") + } // After a partial success error we don't allow changing the user // name and execute the NoClientAuthCallback. partialSuccessReturned = true @@ -878,8 +1008,7 @@ userAuthLoop: if authConfig.KeyboardInteractiveCallback != nil { failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") } - if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil && - authConfig.GSSAPIWithMICConfig.AllowLogin != nil { + if gssapiWithMICConfigured(authConfig.GSSAPIWithMICConfig) { failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") } diff --git a/tests/vendor/golang.org/x/crypto/ssh/session.go b/tests/vendor/golang.org/x/crypto/ssh/session.go index acef62259..ac6295578 100644 --- a/tests/vendor/golang.org/x/crypto/ssh/session.go +++ b/tests/vendor/golang.org/x/crypto/ssh/session.go @@ -423,6 +423,9 @@ func (s *Session) wait(reqs <-chan *Request) error { for msg := range reqs { switch msg.Type { case "exit-status": + if len(msg.Payload) < 4 { + return errors.New("ssh: malformed exit-status request") + } wm.status = int(binary.BigEndian.Uint32(msg.Payload)) case "exit-signal": var sigval struct { diff --git a/tests/vendor/golang.org/x/net/html/entity.go b/tests/vendor/golang.org/x/net/html/entity.go index b628880a0..4e8d5d55f 100644 --- a/tests/vendor/golang.org/x/net/html/entity.go +++ b/tests/vendor/golang.org/x/net/html/entity.go @@ -2156,9 +2156,8 @@ var entity = map[string]rune{ // HTML entities that are two unicode codepoints. var entity2 = map[string][2]rune{ - // TODO(nigeltao): Handle replacements that are wider than their names. - // "nLt;": {'\u226A', '\u20D2'}, - // "nGt;": {'\u226B', '\u20D2'}, + "nLt;": {'\u226A', '\u20D2'}, + "nGt;": {'\u226B', '\u20D2'}, "NotEqualTilde;": {'\u2242', '\u0338'}, "NotGreaterFullEqual;": {'\u2267', '\u0338'}, "NotGreaterGreater;": {'\u226B', '\u0338'}, diff --git a/tests/vendor/golang.org/x/net/html/escape.go b/tests/vendor/golang.org/x/net/html/escape.go index 12f227370..df3edc5b1 100644 --- a/tests/vendor/golang.org/x/net/html/escape.go +++ b/tests/vendor/golang.org/x/net/html/escape.go @@ -6,6 +6,7 @@ package html import ( "bytes" + "slices" "strings" "unicode/utf8" ) @@ -50,25 +51,24 @@ var replacementTable = [...]rune{ // 0x0D->'\u000D' is a no-op. } -// unescapeEntity reads an entity like "<" from b[src:] and writes the -// corresponding "<" to b[dst:], returning the incremented dst and src cursors. -// Precondition: b[src] == '&' && dst <= src. -// attribute should be true if parsing an attribute value. -func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { +// unescapeEntity attempts to consume a character reference from s[src:], +// returning the rune, potential second rune, and number of bytes consumed +// (which indicates the length of the character reference). It is assumed that +// the first byte of s is '&'. attribute should be true if parsing an attribute +// value. +func unescapeEntity(s []byte, attribute bool) (rune, rune, int) { // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference // i starts at 1 because we already know that s[0] == '&'. - i, s := 1, b[src:] + i := 1 if len(s) <= 1 { - b[dst] = b[src] - return dst + 1, src + 1 + return '&', 0, 1 } if s[i] == '#' { - if len(s) <= 3 { // We need to have at least "&#.". - b[dst] = b[src] - return dst + 1, src + 1 + if len(s) <= 2 { // We need to have at least "&#". + return '&', 0, 1 } i++ c := s[i] @@ -78,34 +78,43 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { i++ } + i0 := i x := '\x00' for i < len(s) { c = s[i] - i++ + var d rune + var mult rune if hex { + mult = 16 if '0' <= c && c <= '9' { - x = 16*x + rune(c) - '0' - continue + d = rune(c) - '0' } else if 'a' <= c && c <= 'f' { - x = 16*x + rune(c) - 'a' + 10 - continue + d = rune(c) - 'a' + 10 } else if 'A' <= c && c <= 'F' { - x = 16*x + rune(c) - 'A' + 10 - continue + d = rune(c) - 'A' + 10 + } else { + break + } + } else { + mult = 10 + if '0' <= c && c <= '9' { + d = rune(c) - '0' + } else { + break } - } else if '0' <= c && c <= '9' { - x = 10*x + rune(c) - '0' - continue } - if c != ';' { - i-- + if x <= 0x10FFFF { + x = mult*x + d } - break + i++ + } + + if i == i0 { // No characters matched. + return '&', 0, 1 } - if i <= 3 { // No characters matched. - b[dst] = b[src] - return dst + 1, src + 1 + if i < len(s) && s[i] == ';' { + i++ } if 0x80 <= x && x <= 0x9F { @@ -116,7 +125,7 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { x = '\uFFFD' } - return dst + utf8.EncodeRune(b[dst:], x), src + i + return x, 0, i } // Consume the maximum number of characters possible, with the @@ -141,10 +150,9 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { // No-op. } else if x := entity[entityName]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + i + return x, 0, i } else if x := entity2[entityName]; x[0] != 0 { - dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) - return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + return x[0], x[1], i } else if !attribute { maxLen := len(entityName) - 1 if maxLen > longestEntityWithoutSemicolon { @@ -152,35 +160,67 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { } for j := maxLen; j > 1; j-- { if x := entity[entityName[:j]]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + return x, 0, j + 1 } } } - dst1, src1 = dst+i, src+i - copy(b[dst:dst1], b[src:src1]) - return dst1, src1 + return '&', 0, 1 } -// unescape unescapes b's entities in-place, so that "a<b" becomes "a entityNameLen { + if reusingB { + out = slices.Clone(out) + reusingB = false } - return b[0:dst] + out = slices.Grow(out, replLen) + } + out = utf8.AppendRune(out, r1) + if r2 != 0 { + out = utf8.AppendRune(out, r2) } + + src += entityNameLen } - return b + + return out } // lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc". diff --git a/tests/vendor/golang.org/x/net/html/foreign.go b/tests/vendor/golang.org/x/net/html/foreign.go index e8515d8e8..65d01d1ed 100644 --- a/tests/vendor/golang.org/x/net/html/foreign.go +++ b/tests/vendor/golang.org/x/net/html/foreign.go @@ -23,7 +23,7 @@ func adjustForeignAttributes(aa []Attribute) { } switch a.Key { case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", - "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + "xlink:title", "xlink:type", "xml:lang", "xml:space", "xmlns:xlink": j := strings.Index(a.Key, ":") aa[i].Namespace = a.Key[:j] aa[i].Key = a.Key[j+1:] diff --git a/tests/vendor/golang.org/x/net/html/parse.go b/tests/vendor/golang.org/x/net/html/parse.go index 88fc0056a..165b6108d 100644 --- a/tests/vendor/golang.org/x/net/html/parse.go +++ b/tests/vendor/golang.org/x/net/html/parse.go @@ -5,9 +5,11 @@ package html import ( + "cmp" "errors" "fmt" "io" + "slices" "strings" a "golang.org/x/net/html/atom" @@ -61,7 +63,7 @@ func (p *parser) top() *Node { // Stop tags for use in popUntil. These come from section 12.2.4.2. var ( defaultScopeStopTags = map[string][]a.Atom{ - "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, + "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template, a.Select}, "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, "svg": {a.Desc, a.ForeignObject, a.Title}, } @@ -76,7 +78,6 @@ const ( tableScope tableRowScope tableBodyScope - selectScope ) // popUntil pops the stack of open elements at the highest element whose tag @@ -131,10 +132,6 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { return -1 } - case selectScope: - if tagAtom != a.Optgroup && tagAtom != a.Option { - return -1 - } default: panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s)) } @@ -328,6 +325,14 @@ func (p *parser) addText(text string) { }) } +func attrCompare(a, b Attribute) int { + return cmp.Or( + cmp.Compare(a.Namespace, b.Namespace), + cmp.Compare(a.Key, b.Key), + cmp.Compare(a.Val, b.Val), + ) +} + // addElement adds a child element based on the current token. func (p *parser) addElement() { p.addChild(&Node{ @@ -343,6 +348,10 @@ func (p *parser) addFormattingElement() { tagAtom, attr := p.tok.DataAtom, p.tok.Attr p.addElement() + // In order to optimize the search, we need the attributes to be sorted, so we + // can just use slices.Equal. + slices.SortFunc(attr, attrCompare) + // Implement the Noah's Ark clause, but with three per family instead of two. identicalElements := 0 findIdenticalElements: @@ -360,19 +369,7 @@ findIdenticalElements: if n.DataAtom != tagAtom { continue } - if len(n.Attr) != len(attr) { - continue - } - compareAttributes: - for _, t0 := range n.Attr { - for _, t1 := range attr { - if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { - // Found a match for this attribute, continue with the next attribute. - continue compareAttributes - } - } - // If we get here, there is no attribute that matches a. - // Therefore the element is not identical to the new one. + if !slices.Equal(n.Attr, attr) { continue findIdenticalElements } @@ -382,7 +379,11 @@ findIdenticalElements: } } - p.afe = append(p.afe, p.top()) + // Sort the attributes to optimize future identical-element searches. + top := p.top() + slices.SortFunc(top.Attr, attrCompare) + + p.afe = append(p.afe, top) } // Section 12.2.4.3. @@ -454,21 +455,6 @@ func (p *parser) resetInsertionMode() { } switch n.DataAtom { - case a.Select: - if !last { - for ancestor, first := n, p.oe[0]; ancestor != first; { - ancestor = p.oe[p.oe.index(ancestor)-1] - switch ancestor.DataAtom { - case a.Template: - p.im = inSelectIM - return - case a.Table: - p.im = inSelectInTableIM - return - } - } - } - p.im = inSelectIM case a.Td, a.Th: // TODO: remove this divergence from the HTML5 spec. // @@ -996,7 +982,10 @@ func inBodyIM(p *parser) bool { p.popUntil(buttonScope, a.P) p.addElement() case a.Button: - p.popUntil(defaultScope, a.Button) + if p.elementInScope(defaultScope, a.Button) { + p.generateImpliedEndTags() + p.popUntil(defaultScope, a.Button) + } p.reconstructActiveFormattingElements() p.addElement() p.framesetOK = false @@ -1034,7 +1023,18 @@ func inBodyIM(p *parser) bool { p.framesetOK = false p.im = inTableIM return true - case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr: + case a.Area, a.Br, a.Embed, a.Img, a.Keygen, a.Wbr: + p.reconstructActiveFormattingElements() + p.addElement() + p.oe.pop() + p.acknowledgeSelfClosingTag() + p.framesetOK = false + case a.Input: + if p.fragment && p.context.DataAtom == a.Select { + // Ignore the token. + return true + } + p.popUntil(defaultScope, a.Select) p.reconstructActiveFormattingElements() p.addElement() p.oe.pop() @@ -1055,7 +1055,13 @@ func inBodyIM(p *parser) bool { p.oe.pop() p.acknowledgeSelfClosingTag() case a.Hr: - p.popUntil(buttonScope, a.P) + if p.elementInScope(buttonScope, a.P) { + p.generateImpliedEndTags("p") + p.popUntil(defaultScope, a.P) + } + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags() + } p.addElement() p.oe.pop() p.acknowledgeSelfClosingTag() @@ -1089,13 +1095,30 @@ func inBodyIM(p *parser) bool { // Don't let the tokenizer go into raw text mode when scripting is disabled. p.tokenizer.NextIsNotRawText() case a.Select: + if p.fragment && p.context.DataAtom == a.Select { + // Ignore the token. + return true + } else if p.popUntil(defaultScope, a.Select) { + return true + } p.reconstructActiveFormattingElements() p.addElement() p.framesetOK = false - p.im = inSelectIM return true - case a.Optgroup, a.Option: - if p.top().DataAtom == a.Option { + case a.Option: + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags("optgroup") + // If oe has option element in scope, parse error? + } else if p.top().DataAtom == a.Option { + p.oe.pop() + } + p.reconstructActiveFormattingElements() + p.addElement() + case a.Optgroup: + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags() + // If oe has option or optgroup element in scope, parse error? + } else if p.top().DataAtom == a.Option { p.oe.pop() } p.reconstructActiveFormattingElements() @@ -1143,7 +1166,12 @@ func inBodyIM(p *parser) bool { return false } return true - case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Summary, a.Ul: + case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Select, a.Summary, a.Ul: + if !p.elementInScope(defaultScope, p.tok.DataAtom) { + // Ignore the token. + return true + } + p.generateImpliedEndTags() p.popUntil(defaultScope, p.tok.DataAtom) case a.Form: if p.oe.contains(a.Template) { @@ -1372,8 +1400,6 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) { } // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. -// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content -// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) { for i := len(p.oe) - 1; i >= 0; i-- { // Two element nodes have the same tag if they have the same Data (a @@ -1383,7 +1409,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) { // Uncommon (custom) tags get a zero DataAtom. // // The if condition here is equivalent to (p.oe[i].Data == tagName). - if (p.oe[i].DataAtom == tagAtom) && + if p.oe[i].Namespace == "" && (p.oe[i].DataAtom == tagAtom) && ((tagAtom != 0) || (p.oe[i].Data == tagName)) { p.oe = p.oe[:i] break @@ -1484,17 +1510,6 @@ func inTableIM(p *parser) bool { } p.addElement() p.form = p.oe.pop() - case a.Select: - p.reconstructActiveFormattingElements() - switch p.top().DataAtom { - case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: - p.fosterParenting = true - } - p.addElement() - p.fosterParenting = false - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1543,12 +1558,6 @@ func inCaptionIM(p *parser) bool { p.clearActiveFormattingElements() p.im = inTableIM return false - case a.Select: - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1758,12 +1767,6 @@ func inCellIM(p *parser) bool { } // Ignore the token. return true - case a.Select: - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1794,118 +1797,6 @@ func inCellIM(p *parser) bool { return inBodyIM(p) } -// Section 12.2.6.4.16. -func inSelectIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.addText(strings.Replace(p.tok.Data, "\x00", "", -1)) - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Option: - if p.top().DataAtom == a.Option { - p.oe.pop() - } - p.addElement() - case a.Optgroup: - if p.top().DataAtom == a.Option { - p.oe.pop() - } - if p.top().DataAtom == a.Optgroup { - p.oe.pop() - } - p.addElement() - case a.Select: - if !p.popUntil(selectScope, a.Select) { - // Ignore the token. - return true - } - p.resetInsertionMode() - case a.Input, a.Keygen, a.Textarea: - if p.elementInScope(selectScope, a.Select) { - p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) - return false - } - // In order to properly ignore