From 44ecf3af9978b32529ce689a6964bd557c79aa1c Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 13 Aug 2025 14:21:40 +0000 Subject: [PATCH 1/7] all: upgrade go directive to at least 1.24.0 [generated] By now Go 1.25.0 has been released, and Go 1.23 is no longer supported per the Go Release Policy (see https://go.dev/doc/devel/release#policy). For golang/go#69095. [git-generate] (cd . && go get go@1.24.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none) (cd x509roots/fallback && go get go@1.24.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none) Change-Id: Ia4c201e9611a2c13489e16d4ae81d7e3e32bf455 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/695715 Auto-Submit: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: David Chase --- go.mod | 2 +- x509roots/fallback/go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4ba08a1445..4ccce30fb4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module golang.org/x/crypto -go 1.23.0 +go 1.24.0 require ( golang.org/x/net v0.42.0 // tagx:ignore diff --git a/x509roots/fallback/go.mod b/x509roots/fallback/go.mod index 6ffde44ff8..5d4b07eee5 100644 --- a/x509roots/fallback/go.mod +++ b/x509roots/fallback/go.mod @@ -1,3 +1,3 @@ module golang.org/x/crypto/x509roots/fallback -go 1.23.0 +go 1.24.0 From f5a2eabcab987dc84f30d5479ed5c5605b5de634 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 18 Aug 2025 18:57:42 +0200 Subject: [PATCH 2/7] ssh: use curve25519.X25519 instead of curve25519.ScalarMult This lets us surface an error message instead of panicking if running in fips140=only mode, where ECDH on X25519 returns an error. Updates golang/go#75061 Change-Id: I6a6a6964c0591f3dca2dc946c99d44364314a3ab Reviewed-on: https://go-review.googlesource.com/c/crypto/+/696995 Reviewed-by: Carlos Amedee Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Nicola Murino --- ssh/kex.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/ssh/kex.go b/ssh/kex.go index cf388a92aa..368624759d 100644 --- a/ssh/kex.go +++ b/ssh/kex.go @@ -9,7 +9,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/subtle" "encoding/binary" "errors" "fmt" @@ -454,15 +453,17 @@ func (kp *curve25519KeyPair) generate(rand io.Reader) error { if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { return err } - curve25519.ScalarBaseMult(&kp.pub, &kp.priv) + p, err := curve25519.X25519(kp.priv[:], curve25519.Basepoint) + if err != nil { + return fmt.Errorf("curve25519: %w", err) + } + if len(p) != 32 { + return fmt.Errorf("curve25519: internal error: X25519 returned %d bytes, expected 32", len(p)) + } + copy(kp.pub[:], p) return nil } -// curve25519Zeros is just an array of 32 zero bytes so that we have something -// convenient to compare against in order to reject curve25519 points with the -// wrong order. -var curve25519Zeros [32]byte - func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { var kp curve25519KeyPair if err := kp.generate(rand); err != nil { @@ -485,11 +486,9 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh return nil, errors.New("ssh: peer's curve25519 public value has wrong length") } - var servPub, secret [32]byte - copy(servPub[:], reply.EphemeralPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &servPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + secret, err := curve25519.X25519(kp.priv[:], reply.EphemeralPubKey) + if err != nil { + return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err) } h := crypto.SHA256.New() @@ -531,11 +530,9 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh return nil, err } - var clientPub, secret [32]byte - copy(clientPub[:], kexInit.ClientPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &clientPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + secret, err := curve25519.X25519(kp.priv[:], kexInit.ClientPubKey) + if err != nil { + return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err) } hostKeyBytes := priv.PublicKey().Marshal() From b8d8dae13d7dda8706ca2ab98934ad404aacae22 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 18 Aug 2025 19:06:50 +0200 Subject: [PATCH 3/7] curve25519: include potential fips140=only error in panic message Updates golang/go#75061 Change-Id: I6a6a696474122a12c12696d8a2efec902572327d Reviewed-on: https://go-review.googlesource.com/c/crypto/+/696996 Reviewed-by: Nicola Murino Auto-Submit: Filippo Valsorda Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee --- curve25519/curve25519.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519/curve25519.go b/curve25519/curve25519.go index 21ca3b2ee4..8ff087df4c 100644 --- a/curve25519/curve25519.go +++ b/curve25519/curve25519.go @@ -36,7 +36,7 @@ func ScalarBaseMult(dst, scalar *[32]byte) { curve := ecdh.X25519() priv, err := curve.NewPrivateKey(scalar[:]) if err != nil { - panic("curve25519: internal error: scalarBaseMult was not 32 bytes") + panic("curve25519: " + err.Error()) } copy(dst[:], priv.PublicKey().Bytes()) } From a4d1237429d6056ef197b0b911b8b9d7dca8ecf6 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sat, 9 Aug 2025 19:56:31 +0200 Subject: [PATCH 4/7] ssh/knownhosts: improve IPv6 support in Normalize Correctly converts bracketed IPv6: - [abcd::abcd:abcd:abcd] => abcd::abcd:abcd:abcd - [abcd::abcd:abcd:abcd]:22 => abcd::abcd:abcd:abcd - [abcd::abcd:abcd:abcd]:23 => [abcd::abcd:abcd:abcd]:23 Fixes golang/go#53463 Change-Id: Id0a7460d8448a72e2a8c6d46137245bead9ecf9f Reviewed-on: https://go-review.googlesource.com/c/crypto/+/694575 LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Reviewed-by: David Chase Reviewed-by: Carlos Amedee --- ssh/knownhosts/knownhosts.go | 22 ++++++++++++++-------- ssh/knownhosts/knownhosts_test.go | 29 ++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/ssh/knownhosts/knownhosts.go b/ssh/knownhosts/knownhosts.go index c022e411f0..1ebd7e6da2 100644 --- a/ssh/knownhosts/knownhosts.go +++ b/ssh/knownhosts/knownhosts.go @@ -421,20 +421,26 @@ func New(files ...string) (ssh.HostKeyCallback, error) { return certChecker.CheckHostKey, nil } -// Normalize normalizes an address into the form used in known_hosts +// Normalize normalizes an address into the form used in known_hosts. Supports +// IPv4, hostnames, bracketed IPv6. Any other non-standard formats are returned +// with minimal transformation. func Normalize(address string) string { + const defaultSSHPort = "22" + host, port, err := net.SplitHostPort(address) if err != nil { host = address - port = "22" + port = defaultSSHPort + } + + if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { + host = host[1 : len(host)-1] } - entry := host - if port != "22" { - entry = "[" + entry + "]:" + port - } else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { - entry = "[" + entry + "]" + + if port == defaultSSHPort { + return host } - return entry + return "[" + host + "]:" + port } // Line returns a line to add append to the known_hosts files. diff --git a/ssh/knownhosts/knownhosts_test.go b/ssh/knownhosts/knownhosts_test.go index 156576ad07..552a556110 100644 --- a/ssh/knownhosts/knownhosts_test.go +++ b/ssh/knownhosts/knownhosts_test.go @@ -236,7 +236,7 @@ func TestLine(t *testing.T) { "server.org": "server.org " + edKeyStr, "server.org:22": "server.org " + edKeyStr, "server.org:23": "[server.org]:23 " + edKeyStr, - "[c629:1ec4:102:304:102:304:102:304]:22": "[c629:1ec4:102:304:102:304:102:304] " + edKeyStr, + "[c629:1ec4:102:304:102:304:102:304]:22": "c629:1ec4:102:304:102:304:102:304 " + edKeyStr, "[c629:1ec4:102:304:102:304:102:304]:23": "[c629:1ec4:102:304:102:304:102:304]:23 " + edKeyStr, } { if got := Line([]string{in}, edKey); got != want { @@ -310,14 +310,25 @@ func testHostHash(t *testing.T, hostname, encoded string) { func TestNormalize(t *testing.T) { for in, want := range map[string]string{ - "127.0.0.1:22": "127.0.0.1", - "[127.0.0.1]:22": "127.0.0.1", - "[127.0.0.1]:23": "[127.0.0.1]:23", - "127.0.0.1:23": "[127.0.0.1]:23", - "[a.b.c]:22": "a.b.c", - "[abcd:abcd:abcd:abcd]": "[abcd:abcd:abcd:abcd]", - "[abcd:abcd:abcd:abcd]:22": "[abcd:abcd:abcd:abcd]", - "[abcd:abcd:abcd:abcd]:23": "[abcd:abcd:abcd:abcd]:23", + "127.0.0.1": "127.0.0.1", + "127.0.0.1:22": "127.0.0.1", + "[127.0.0.1]:22": "127.0.0.1", + "[127.0.0.1]:23": "[127.0.0.1]:23", + "127.0.0.1:23": "[127.0.0.1]:23", + "[a.b.c]:22": "a.b.c", + "[a.b.c]:23": "[a.b.c]:23", + "abcd::abcd:abcd:abcd": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]:22": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]:23": "[abcd::abcd:abcd:abcd]:23", + "2001:db8::1": "2001:db8::1", + "2001:db8::1:22": "2001:db8::1:22", + "[2001:db8::1]:22": "2001:db8::1", + "2001:db8::1:2200": "2001:db8::1:2200", + "a.b.c.d.com:2200": "[a.b.c.d.com]:2200", + "2001::db8:1": "2001::db8:1", + "2001::db8:1:22": "2001::db8:1:22", + "2001::db8:1:2200": "2001::db8:1:2200", } { got := Normalize(in) if got != want { From 8f580defa01dec23898d3cd27f6369cdcc62f71f Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 24 Aug 2025 10:53:36 +0200 Subject: [PATCH 5/7] ssh: remove Go 1.24 build tag for ML-KEM kex Change-Id: Ia77ad1b6fef9919ab100fb10c42231725eb81c12 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/698775 LUCI-TryBot-Result: Go LUCI Auto-Submit: Nicola Murino Reviewed-by: Filippo Valsorda Reviewed-by: Cherry Mui Reviewed-by: Roland Shoemaker --- ssh/common.go | 2 ++ ssh/kex.go | 1 + ssh/mlkem.go | 15 --------------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ssh/common.go b/ssh/common.go index f2ec0896c2..8bfad16c41 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -83,6 +83,7 @@ var ( // supportedKexAlgos specifies key-exchange algorithms implemented by this // package in preference order, excluding those with security issues. supportedKexAlgos = []string{ + KeyExchangeMLKEM768X25519, KeyExchangeCurve25519, KeyExchangeECDHP256, KeyExchangeECDHP384, @@ -94,6 +95,7 @@ var ( // defaultKexAlgos specifies the default preference for key-exchange // algorithms in preference order. defaultKexAlgos = []string{ + KeyExchangeMLKEM768X25519, KeyExchangeCurve25519, KeyExchangeECDHP256, KeyExchangeECDHP384, diff --git a/ssh/kex.go b/ssh/kex.go index 368624759d..78aaf03103 100644 --- a/ssh/kex.go +++ b/ssh/kex.go @@ -438,6 +438,7 @@ func init() { kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{} kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} + kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} } // curve25519sha256 implements the curve25519-sha256 (formerly known as diff --git a/ssh/mlkem.go b/ssh/mlkem.go index 657e1079d4..ddc0ed1fc0 100644 --- a/ssh/mlkem.go +++ b/ssh/mlkem.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.24 - package ssh import ( @@ -13,23 +11,10 @@ import ( "errors" "fmt" "io" - "runtime" - "slices" "golang.org/x/crypto/curve25519" ) -func init() { - // After Go 1.24rc1 mlkem swapped the order of return values of Encapsulate. - // See #70950. - if runtime.Version() == "go1.24rc1" { - return - } - supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, KeyExchangeMLKEM768X25519) - defaultKexAlgos = slices.Insert(defaultKexAlgos, 0, KeyExchangeMLKEM768X25519) - kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} -} - // mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with // curve25519-sha256 key exchange method, as described by // draft-kampanakis-curdle-ssh-pq-ke-05 section 2.3.3. From 9d779377cff7ff1f58520cc044fb90b10ddfc561 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 11 Jun 2025 17:43:01 -0400 Subject: [PATCH 6/7] acme: include order problem in OrderError If client.WaitOrder or client.CreateOrderCert return an acme.OrderError it's helpful to include the order's problem field (if available). This will often have detailed information about why a particular order became invalid that's invaluable for debugging (e.g. a challenge response was incorrect, a name couldn't be resolved, etc). While it's possible for a consumer to poll the order themselves as part of handling the order to extract a fresh Order.Error field value, it would take an extra round-trip network request. Since we have the underlying error in-hand when we produce the OrderError we might as well include it directly. Since this field is a structured object with a number of sub-fields the OrderError.Error() function isn't updated to include the order problem error in the String description. Interested callers should instead use errors.Is to extract the problem information directly. Resolves golang/go#74430 Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest Change-Id: I3158f064793bbfdc292dd6b5e1a6bfd7729bd980 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/681037 Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Michael Pratt Reviewed-by: Ian Stapleton Cordasco LUCI-TryBot-Result: Go LUCI --- acme/pebble_test.go | 7 ++++++- acme/rfc8555.go | 4 ++-- acme/rfc8555_test.go | 19 ++++++++++++++++--- acme/types.go | 5 ++++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index b633435a71..bb4809faf7 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -382,7 +382,12 @@ func testIssuance(t *testing.T, env *environment, challSrv challengeServer) { // Wait for the order to become ready for finalization. order, err = client.WaitOrder(ctx, order.URI) if err != nil { - t.Fatalf("failed to wait for order %s: %s", orderURL, err) + var orderErr *acme.OrderError + if errors.Is(err, orderErr) { + t.Fatalf("failed to wait for order %s: %s: %s", orderURL, err, orderErr.Problem) + } else { + t.Fatalf("failed to wait for order %s: %s", orderURL, err) + } } if order.Status != acme.StatusReady { t.Fatalf("expected order %s status to be ready, got %v", diff --git a/acme/rfc8555.go b/acme/rfc8555.go index 3152e531b6..fc653f3f0b 100644 --- a/acme/rfc8555.go +++ b/acme/rfc8555.go @@ -272,7 +272,7 @@ func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) { case err != nil: // Skip and retry. case o.Status == StatusInvalid: - return nil, &OrderError{OrderURL: o.URI, Status: o.Status} + return nil, &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error} case o.Status == StatusReady || o.Status == StatusValid: return o, nil } @@ -369,7 +369,7 @@ func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bu } // The only acceptable status post finalize and WaitOrder is "valid". if o.Status != StatusValid { - return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status} + return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error} } crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle) return crt, o.CertURL, err diff --git a/acme/rfc8555_test.go b/acme/rfc8555_test.go index d65720a356..e9cedb5927 100644 --- a/acme/rfc8555_test.go +++ b/acme/rfc8555_test.go @@ -885,11 +885,17 @@ func TestRFC_WaitOrderError(t *testing.T) { s.handle("/orders/1", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", s.url("/orders/1")) w.WriteHeader(http.StatusOK) - s := StatusPending if count > 0 { - s = StatusInvalid + // https://www.rfc-editor.org/rfc/rfc8555#section-7.3.3 + errorData := `{ + "type": "urn:ietf:params:acme:error:userActionRequired", + "detail": "Terms of service have changed", + "instance": "https://example.com/acme/agreement/?token=W8Ih3PswD-8" + }` + fmt.Fprintf(w, `{"status": %q, "error": %s}`, StatusInvalid, errorData) + } else { + fmt.Fprintf(w, `{"status": %q}`, StatusPending) } - fmt.Fprintf(w, `{"status": %q}`, s) count++ }) s.start() @@ -910,6 +916,13 @@ func TestRFC_WaitOrderError(t *testing.T) { if e.Status != StatusInvalid { t.Errorf("e.Status = %q; want %q", e.Status, StatusInvalid) } + if e.Problem == nil { + t.Errorf("e.Problem = nil") + } + expectedProbType := "urn:ietf:params:acme:error:userActionRequired" + if e.Problem.ProblemType != expectedProbType { + t.Errorf("e.Problem.ProblemType = %q; want %q", e.Problem.ProblemType, expectedProbType) + } } func TestRFC_CreateOrderCert(t *testing.T) { diff --git a/acme/types.go b/acme/types.go index c466645ca1..322640c453 100644 --- a/acme/types.go +++ b/acme/types.go @@ -154,13 +154,16 @@ func (a *AuthorizationError) Error() string { // OrderError is returned from Client's order related methods. // It indicates the order is unusable and the clients should start over with -// AuthorizeOrder. +// AuthorizeOrder. A Problem description may be provided with details on +// what caused the order to become unusable. // // The clients can still fetch the order object from CA using GetOrder // to inspect its state. type OrderError struct { OrderURL string Status string + // Problem is the error that occurred while processing the order. + Problem *Error } func (oe *OrderError) Error() string { From 5307a0ce6db8057c8d7c4378dc4bd715b4985ba1 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Sun, 7 Sep 2025 20:55:38 -0700 Subject: [PATCH 7/7] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: I75e16a930bfe42cc082df82ab67802c42ad56a97 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/701303 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Michael Pratt Auto-Submit: Gopher Robot --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 4ccce30fb4..fd65b61893 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module golang.org/x/crypto go 1.24.0 require ( - golang.org/x/net v0.42.0 // tagx:ignore - golang.org/x/sys v0.35.0 - golang.org/x/term v0.34.0 + golang.org/x/net v0.43.0 // tagx:ignore + golang.org/x/sys v0.36.0 + golang.org/x/term v0.35.0 ) -require golang.org/x/text v0.28.0 // indirect +require golang.org/x/text v0.29.0 // indirect diff --git a/go.sum b/go.sum index b75af8566b..c3f2d576cb 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=