Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e98487292d | ||
|
|
183630ada7 | ||
|
|
a9e447dde7 | ||
|
|
64c3993f5c | ||
|
|
5fe8145aca | ||
|
|
043e94c17a | ||
|
|
0d502d7cd6 | ||
|
|
0ff60057bb |
@@ -4,8 +4,8 @@ go 1.17
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/net v0.10.0 // tagx:ignore
|
golang.org/x/net v0.10.0 // tagx:ignore
|
||||||
golang.org/x/sys v0.9.0
|
golang.org/x/sys v0.10.0
|
||||||
golang.org/x/term v0.9.0
|
golang.org/x/term v0.10.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/text v0.10.0 // indirect
|
require golang.org/x/text v0.11.0 // indirect
|
||||||
|
|||||||
@@ -19,21 +19,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package testenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandContext is like exec.CommandContext, but:
|
||||||
|
// - skips t if the platform does not support os/exec,
|
||||||
|
// - sends SIGQUIT (if supported by the platform) instead of SIGKILL
|
||||||
|
// in its Cancel function
|
||||||
|
// - if the test has a deadline, adds a Context timeout and WaitDelay
|
||||||
|
// for an arbitrary grace period before the test's deadline expires,
|
||||||
|
// - fails the test if the command does not complete before the test's deadline, and
|
||||||
|
// - sets a Cleanup function that verifies that the test did not leak a subprocess.
|
||||||
|
func CommandContext(t testing.TB, ctx context.Context, name string, args ...string) *exec.Cmd {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
var (
|
||||||
|
cancelCtx context.CancelFunc
|
||||||
|
gracePeriod time.Duration // unlimited unless the test has a deadline (to allow for interactive debugging)
|
||||||
|
)
|
||||||
|
|
||||||
|
if t, ok := t.(interface {
|
||||||
|
testing.TB
|
||||||
|
Deadline() (time.Time, bool)
|
||||||
|
}); ok {
|
||||||
|
if td, ok := t.Deadline(); ok {
|
||||||
|
// Start with a minimum grace period, just long enough to consume the
|
||||||
|
// output of a reasonable program after it terminates.
|
||||||
|
gracePeriod = 100 * time.Millisecond
|
||||||
|
if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
|
||||||
|
scale, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid GO_TEST_TIMEOUT_SCALE: %v", err)
|
||||||
|
}
|
||||||
|
gracePeriod *= time.Duration(scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If time allows, increase the termination grace period to 5% of the
|
||||||
|
// test's remaining time.
|
||||||
|
testTimeout := time.Until(td)
|
||||||
|
if gp := testTimeout / 20; gp > gracePeriod {
|
||||||
|
gracePeriod = gp
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we run commands that execute subprocesses, we want to reserve two
|
||||||
|
// grace periods to clean up: one for the delay between the first
|
||||||
|
// termination signal being sent (via the Cancel callback when the Context
|
||||||
|
// expires) and the process being forcibly terminated (via the WaitDelay
|
||||||
|
// field), and a second one for the delay becween the process being
|
||||||
|
// terminated and and the test logging its output for debugging.
|
||||||
|
//
|
||||||
|
// (We want to ensure that the test process itself has enough time to
|
||||||
|
// log the output before it is also terminated.)
|
||||||
|
cmdTimeout := testTimeout - 2*gracePeriod
|
||||||
|
|
||||||
|
if cd, ok := ctx.Deadline(); !ok || time.Until(cd) > cmdTimeout {
|
||||||
|
// Either ctx doesn't have a deadline, or its deadline would expire
|
||||||
|
// after (or too close before) the test has already timed out.
|
||||||
|
// Add a shorter timeout so that the test will produce useful output.
|
||||||
|
ctx, cancelCtx = context.WithTimeout(ctx, cmdTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(ctx, name, args...)
|
||||||
|
// Set the Cancel and WaitDelay fields only if present (go 1.20 and later).
|
||||||
|
// TODO: When Go 1.19 is no longer supported, remove this use of reflection
|
||||||
|
// and instead set the fields directly.
|
||||||
|
if cmdCancel := reflect.ValueOf(cmd).Elem().FieldByName("Cancel"); cmdCancel.IsValid() {
|
||||||
|
cmdCancel.Set(reflect.ValueOf(func() error {
|
||||||
|
if cancelCtx != nil && ctx.Err() == context.DeadlineExceeded {
|
||||||
|
// The command timed out due to running too close to the test's deadline.
|
||||||
|
// There is no way the test did that intentionally — it's too close to the
|
||||||
|
// wire! — so mark it as a test failure. That way, if the test expects the
|
||||||
|
// command to fail for some other reason, it doesn't have to distinguish
|
||||||
|
// between that reason and a timeout.
|
||||||
|
t.Errorf("test timed out while running command: %v", cmd)
|
||||||
|
} else {
|
||||||
|
// The command is being terminated due to ctx being canceled, but
|
||||||
|
// apparently not due to an explicit test deadline that we added.
|
||||||
|
// Log that information in case it is useful for diagnosing a failure,
|
||||||
|
// but don't actually fail the test because of it.
|
||||||
|
t.Logf("%v: terminating command: %v", ctx.Err(), cmd)
|
||||||
|
}
|
||||||
|
return cmd.Process.Signal(Sigquit)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
if cmdWaitDelay := reflect.ValueOf(cmd).Elem().FieldByName("WaitDelay"); cmdWaitDelay.IsValid() {
|
||||||
|
cmdWaitDelay.Set(reflect.ValueOf(gracePeriod))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if cancelCtx != nil {
|
||||||
|
cancelCtx()
|
||||||
|
}
|
||||||
|
if cmd.Process != nil && cmd.ProcessState == nil {
|
||||||
|
t.Errorf("command was started, but test did not wait for it to complete: %v", cmd)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command is like exec.Command, but applies the same changes as
|
||||||
|
// testenv.CommandContext (with a default Context).
|
||||||
|
func Command(t testing.TB, name string, args ...string) *exec.Cmd {
|
||||||
|
t.Helper()
|
||||||
|
return CommandContext(t, context.Background(), name, args...)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows || plan9 || (js && wasm) || wasip1
|
||||||
|
|
||||||
|
package testenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sigquit is the signal to send to kill a hanging subprocess.
|
||||||
|
// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill.
|
||||||
|
var Sigquit = os.Kill
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build unix
|
||||||
|
|
||||||
|
package testenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sigquit is the signal to send to kill a hanging subprocess.
|
||||||
|
// Send SIGQUIT to get a stack trace.
|
||||||
|
var Sigquit = syscall.SIGQUIT
|
||||||
+1
-1
@@ -85,7 +85,7 @@ var supportedHostKeyAlgos = []string{
|
|||||||
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
||||||
// because they have reached the end of their useful life.
|
// because they have reached the end of their useful life.
|
||||||
var supportedMACs = []string{
|
var supportedMACs = []string{
|
||||||
"hmac-sha2-512-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
|
"hmac-sha2-512-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", "hmac-sha1-96",
|
||||||
}
|
}
|
||||||
|
|
||||||
var supportedCompressions = []string{compressionNone}
|
var supportedCompressions = []string{compressionNone}
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ var macModes = map[string]*macMode{
|
|||||||
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
|
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
|
||||||
return hmac.New(sha256.New, key)
|
return hmac.New(sha256.New, key)
|
||||||
}},
|
}},
|
||||||
|
"hmac-sha2-512": {64, false, func(key []byte) hash.Hash {
|
||||||
|
return hmac.New(sha512.New, key)
|
||||||
|
}},
|
||||||
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
|
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
|
||||||
return hmac.New(sha256.New, key)
|
return hmac.New(sha256.New, key)
|
||||||
}},
|
}},
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
func TestAgentForward(t *testing.T) {
|
func TestAgentForward(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
func TestBannerCallbackAgainstOpenSSH(t *testing.T) {
|
func TestBannerCallbackAgainstOpenSSH(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
|
|
||||||
clientConf := clientConfig()
|
clientConf := clientConfig()
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
// Test both logging in with a cert, and also that the certificate presented by an OpenSSH host can be validated correctly
|
// Test both logging in with a cert, and also that the certificate presented by an OpenSSH host can be validated correctly
|
||||||
func TestCertLogin(t *testing.T) {
|
func TestCertLogin(t *testing.T) {
|
||||||
s := newServer(t)
|
s := newServer(t)
|
||||||
defer s.Shutdown()
|
|
||||||
|
|
||||||
// Use a key different from the default.
|
// Use a key different from the default.
|
||||||
clientKey := testSigners["dsa"]
|
clientKey := testSigners["dsa"]
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ type dialTester interface {
|
|||||||
|
|
||||||
func testDial(t *testing.T, n, listenAddr string, x dialTester) {
|
func testDial(t *testing.T, n, listenAddr string, x dialTester) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
sshConn := server.Dial(clientConfig())
|
sshConn := server.Dial(clientConfig())
|
||||||
defer sshConn.Close()
|
defer sshConn.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ type closeWriter interface {
|
|||||||
|
|
||||||
func testPortForward(t *testing.T, n, listenAddr string) {
|
func testPortForward(t *testing.T, n, listenAddr string) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -120,7 +119,6 @@ func TestPortForwardUnix(t *testing.T) {
|
|||||||
|
|
||||||
func testAcceptClose(t *testing.T, n, listenAddr string) {
|
func testAcceptClose(t *testing.T, n, listenAddr string) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
|
|
||||||
sshListener, err := conn.Listen(n, listenAddr)
|
sshListener, err := conn.Listen(n, listenAddr)
|
||||||
@@ -162,10 +160,9 @@ func TestAcceptCloseUnix(t *testing.T) {
|
|||||||
// Check that listeners exit if the underlying client transport dies.
|
// Check that listeners exit if the underlying client transport dies.
|
||||||
func testPortForwardConnectionClose(t *testing.T, n, listenAddr string) {
|
func testPortForwardConnectionClose(t *testing.T, n, listenAddr string) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
client := server.Dial(clientConfig())
|
||||||
conn := server.Dial(clientConfig())
|
|
||||||
|
|
||||||
sshListener, err := conn.Listen(n, listenAddr)
|
sshListener, err := client.Listen(n, listenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -184,14 +181,10 @@ func testPortForwardConnectionClose(t *testing.T, n, listenAddr string) {
|
|||||||
|
|
||||||
// It would be even nicer if we closed the server side, but it
|
// It would be even nicer if we closed the server side, but it
|
||||||
// is more involved as the fd for that side is dup()ed.
|
// is more involved as the fd for that side is dup()ed.
|
||||||
server.clientConn.Close()
|
server.lastDialConn.Close()
|
||||||
|
|
||||||
select {
|
err = <-quit
|
||||||
case <-time.After(1 * time.Second):
|
t.Logf("quit as expected (error %v)", err)
|
||||||
t.Errorf("timeout: listener did not close.")
|
|
||||||
case err := <-quit:
|
|
||||||
t.Logf("quit as expected (error %v)", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPortForwardConnectionCloseTCP(t *testing.T) {
|
func TestPortForwardConnectionCloseTCP(t *testing.T) {
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ func TestMultiAuth(t *testing.T) {
|
|||||||
ctx := newMultiAuthTestCtx(t)
|
ctx := newMultiAuthTestCtx(t)
|
||||||
|
|
||||||
server := newServerForConfig(t, "MultiAuth", map[string]string{"AuthMethods": strings.Join(testCase.authMethods, ",")})
|
server := newServerForConfig(t, "MultiAuth", map[string]string{"AuthMethods": strings.Join(testCase.authMethods, ",")})
|
||||||
defer server.Shutdown()
|
|
||||||
|
|
||||||
clientConfig := clientConfig()
|
clientConfig := clientConfig()
|
||||||
server.setTestPassword(clientConfig.User, ctx.password)
|
server.setTestPassword(clientConfig.User, ctx.password)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
|
|
||||||
func TestRunCommandSuccess(t *testing.T) {
|
func TestRunCommandSuccess(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -42,7 +41,6 @@ func TestRunCommandSuccess(t *testing.T) {
|
|||||||
|
|
||||||
func TestHostKeyCheck(t *testing.T) {
|
func TestHostKeyCheck(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
|
|
||||||
conf := clientConfig()
|
conf := clientConfig()
|
||||||
hostDB := hostKeyDB()
|
hostDB := hostKeyDB()
|
||||||
@@ -64,7 +62,6 @@ func TestHostKeyCheck(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunCommandStdin(t *testing.T) {
|
func TestRunCommandStdin(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -87,7 +84,6 @@ func TestRunCommandStdin(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunCommandStdinError(t *testing.T) {
|
func TestRunCommandStdinError(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -111,7 +107,6 @@ func TestRunCommandStdinError(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunCommandFailed(t *testing.T) {
|
func TestRunCommandFailed(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -128,7 +123,6 @@ func TestRunCommandFailed(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunCommandWeClosed(t *testing.T) {
|
func TestRunCommandWeClosed(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -148,7 +142,6 @@ func TestRunCommandWeClosed(t *testing.T) {
|
|||||||
|
|
||||||
func TestFuncLargeRead(t *testing.T) {
|
func TestFuncLargeRead(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -180,7 +173,6 @@ func TestFuncLargeRead(t *testing.T) {
|
|||||||
|
|
||||||
func TestKeyChange(t *testing.T) {
|
func TestKeyChange(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conf := clientConfig()
|
conf := clientConfig()
|
||||||
hostDB := hostKeyDB()
|
hostDB := hostKeyDB()
|
||||||
conf.HostKeyCallback = hostDB.Check
|
conf.HostKeyCallback = hostDB.Check
|
||||||
@@ -227,7 +219,6 @@ func TestValidTerminalMode(t *testing.T) {
|
|||||||
t.Skipf("skipping on %s", runtime.GOOS)
|
t.Skipf("skipping on %s", runtime.GOOS)
|
||||||
}
|
}
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -292,7 +283,6 @@ func TestWindowChange(t *testing.T) {
|
|||||||
t.Skipf("skipping on %s", runtime.GOOS)
|
t.Skipf("skipping on %s", runtime.GOOS)
|
||||||
}
|
}
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -340,7 +330,6 @@ func TestWindowChange(t *testing.T) {
|
|||||||
|
|
||||||
func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conf := clientConfig()
|
conf := clientConfig()
|
||||||
conf.Ciphers = []string{cipher}
|
conf.Ciphers = []string{cipher}
|
||||||
// Don't fail if sshd doesn't have the cipher.
|
// Don't fail if sshd doesn't have the cipher.
|
||||||
@@ -399,7 +388,6 @@ func TestMACs(t *testing.T) {
|
|||||||
for _, mac := range macOrder {
|
for _, mac := range macOrder {
|
||||||
t.Run(mac, func(t *testing.T) {
|
t.Run(mac, func(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conf := clientConfig()
|
conf := clientConfig()
|
||||||
conf.MACs = []string{mac}
|
conf.MACs = []string{mac}
|
||||||
// Don't fail if sshd doesn't have the MAC.
|
// Don't fail if sshd doesn't have the MAC.
|
||||||
@@ -425,7 +413,6 @@ func TestKeyExchanges(t *testing.T) {
|
|||||||
for _, kex := range kexOrder {
|
for _, kex := range kexOrder {
|
||||||
t.Run(kex, func(t *testing.T) {
|
t.Run(kex, func(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
defer server.Shutdown()
|
|
||||||
conf := clientConfig()
|
conf := clientConfig()
|
||||||
// Don't fail if sshd doesn't have the kex.
|
// Don't fail if sshd doesn't have the kex.
|
||||||
conf.KeyExchanges = append([]string{kex}, kexOrder...)
|
conf.KeyExchanges = append([]string{kex}, kexOrder...)
|
||||||
@@ -460,8 +447,6 @@ func TestClientAuthAlgorithms(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Errorf("failed for key %q", key)
|
t.Errorf("failed for key %q", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Shutdown()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-37
@@ -23,6 +23,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/internal/testenv"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"golang.org/x/crypto/ssh/testdata"
|
"golang.org/x/crypto/ssh/testdata"
|
||||||
)
|
)
|
||||||
@@ -67,17 +68,13 @@ var configTmpl = map[string]*template.Template{
|
|||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
cleanup func() // executed during Shutdown
|
|
||||||
configfile string
|
configfile string
|
||||||
cmd *exec.Cmd
|
|
||||||
output bytes.Buffer // holds stderr from sshd process
|
|
||||||
|
|
||||||
testUser string // test username for sshd
|
testUser string // test username for sshd
|
||||||
testPasswd string // test password for sshd
|
testPasswd string // test password for sshd
|
||||||
sshdTestPwSo string // dynamic library to inject a custom password into sshd
|
sshdTestPwSo string // dynamic library to inject a custom password into sshd
|
||||||
|
|
||||||
// Client half of the network connection.
|
lastDialConn net.Conn
|
||||||
clientConn net.Conn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func username() string {
|
func username() string {
|
||||||
@@ -193,15 +190,15 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
|||||||
s.t.Fatalf("unixConnection: %v", err)
|
s.t.Fatalf("unixConnection: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
|
cmd := testenv.Command(s.t, sshd, "-f", s.configfile, "-i", "-e")
|
||||||
f, err := c2.File()
|
f, err := c2.File()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.t.Fatalf("UnixConn.File: %v", err)
|
s.t.Fatalf("UnixConn.File: %v", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
s.cmd.Stdin = f
|
cmd.Stdin = f
|
||||||
s.cmd.Stdout = f
|
cmd.Stdout = f
|
||||||
s.cmd.Stderr = &s.output
|
cmd.Stderr = new(bytes.Buffer)
|
||||||
|
|
||||||
if s.sshdTestPwSo != "" {
|
if s.sshdTestPwSo != "" {
|
||||||
if s.testUser == "" {
|
if s.testUser == "" {
|
||||||
@@ -210,18 +207,29 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
|||||||
if s.testPasswd == "" {
|
if s.testPasswd == "" {
|
||||||
s.t.Fatal("password missing from sshd_test_pw.so config")
|
s.t.Fatal("password missing from sshd_test_pw.so config")
|
||||||
}
|
}
|
||||||
s.cmd.Env = append(os.Environ(),
|
cmd.Env = append(os.Environ(),
|
||||||
fmt.Sprintf("LD_PRELOAD=%s", s.sshdTestPwSo),
|
fmt.Sprintf("LD_PRELOAD=%s", s.sshdTestPwSo),
|
||||||
fmt.Sprintf("TEST_USER=%s", s.testUser),
|
fmt.Sprintf("TEST_USER=%s", s.testUser),
|
||||||
fmt.Sprintf("TEST_PASSWD=%s", s.testPasswd))
|
fmt.Sprintf("TEST_PASSWD=%s", s.testPasswd))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
s.t.Fail()
|
|
||||||
s.Shutdown()
|
|
||||||
s.t.Fatalf("s.cmd.Start: %v", err)
|
s.t.Fatalf("s.cmd.Start: %v", err)
|
||||||
}
|
}
|
||||||
s.clientConn = c1
|
s.lastDialConn = c1
|
||||||
|
s.t.Cleanup(func() {
|
||||||
|
// Don't check for errors; if it fails it's most
|
||||||
|
// likely "os: process already finished", and we don't
|
||||||
|
// care about that. Use os.Interrupt, so child
|
||||||
|
// processes are killed too.
|
||||||
|
cmd.Process.Signal(os.Interrupt)
|
||||||
|
cmd.Wait()
|
||||||
|
if s.t.Failed() {
|
||||||
|
// log any output from sshd process
|
||||||
|
s.t.Logf("sshd:\n%s", cmd.Stderr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
conn, chans, reqs, err := ssh.NewClientConn(c1, addr, config)
|
conn, chans, reqs, err := ssh.NewClientConn(c1, addr, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -232,29 +240,11 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
|||||||
func (s *server) Dial(config *ssh.ClientConfig) *ssh.Client {
|
func (s *server) Dial(config *ssh.ClientConfig) *ssh.Client {
|
||||||
conn, err := s.TryDial(config)
|
conn, err := s.TryDial(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.t.Fail()
|
|
||||||
s.Shutdown()
|
|
||||||
s.t.Fatalf("ssh.Client: %v", err)
|
s.t.Fatalf("ssh.Client: %v", err)
|
||||||
}
|
}
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Shutdown() {
|
|
||||||
if s.cmd != nil && s.cmd.Process != nil {
|
|
||||||
// Don't check for errors; if it fails it's most
|
|
||||||
// likely "os: process already finished", and we don't
|
|
||||||
// care about that. Use os.Interrupt, so child
|
|
||||||
// processes are killed too.
|
|
||||||
s.cmd.Process.Signal(os.Interrupt)
|
|
||||||
s.cmd.Wait()
|
|
||||||
}
|
|
||||||
if s.t.Failed() {
|
|
||||||
// log any output from sshd process
|
|
||||||
s.t.Logf("sshd: %s", s.output.String())
|
|
||||||
}
|
|
||||||
s.cleanup()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(path string, contents []byte) {
|
func writeFile(path string, contents []byte) {
|
||||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -351,15 +341,15 @@ func newServerForConfig(t *testing.T, config string, configVars map[string]strin
|
|||||||
authkeys.Write(ssh.MarshalAuthorizedKey(testPublicKeys[k]))
|
authkeys.Write(ssh.MarshalAuthorizedKey(testPublicKeys[k]))
|
||||||
}
|
}
|
||||||
writeFile(filepath.Join(dir, "authorized_keys"), authkeys.Bytes())
|
writeFile(filepath.Join(dir, "authorized_keys"), authkeys.Bytes())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return &server{
|
return &server{
|
||||||
t: t,
|
t: t,
|
||||||
configfile: f.Name(),
|
configfile: f.Name(),
|
||||||
cleanup: func() {
|
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Code generated by gen.go at Mon, 17 Apr 2023 10:17:20 PDT; DO NOT EDIT.
|
// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
||||||
// list hash: ceaec72125bf99ab9f1a05b7883679481c07d23388cc10d40ca102f87f4e39a2
|
|
||||||
|
//go:build go1.20
|
||||||
|
|
||||||
package fallback
|
package fallback
|
||||||
|
|
||||||
@@ -433,6 +434,56 @@ StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
|
|||||||
Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
|
Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
|
||||||
jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
|
jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
# CN=BJCA Global Root CA1,O=BEIJING CERTIFICATE AUTHORITY,C=CN
|
||||||
|
# f3896f88fe7c0a882766a7fa6ad2749fb57a7f3e98fb769c1fa7b09c2c44d5ae
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
r/6zcCwupvI=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=BJCA Global Root CA2,O=BEIJING CERTIFICATE AUTHORITY,C=CN
|
||||||
|
# 574df6931e278039667b720afdc1600fc27eb66dd3092979fb73856487212882
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw
|
||||||
|
CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ
|
||||||
|
VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy
|
||||||
|
MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ
|
||||||
|
TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS
|
||||||
|
b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B
|
||||||
|
IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+
|
||||||
|
+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK
|
||||||
|
sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
|
||||||
|
AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA
|
||||||
|
94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B
|
||||||
|
43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
# CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE
|
# CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE
|
||||||
# 16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb
|
# 16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build go1.20
|
//go:build go1.20
|
||||||
// +build go1.20
|
|
||||||
|
|
||||||
// Package fallback embeds a set of fallback X.509 trusted roots in the
|
// Package fallback embeds a set of fallback X.509 trusted roots in the
|
||||||
// application by automatically invoking [x509.SetFallbackRoots]. This allows
|
// application by automatically invoking [x509.SetFallbackRoots]. This allows
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package goissue52287 is an empty internal package.
|
||||||
|
// It exists only to work around go.dev/issue/52287 and
|
||||||
|
// can be removed after Go 1.19 stops being supported.
|
||||||
|
package goissue52287
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build gen
|
//go:build generate
|
||||||
// +build gen
|
// +build generate
|
||||||
|
|
||||||
//go:generate go run gen_fallback_bundle.go
|
//go:generate go run gen_fallback_bundle.go
|
||||||
|
|
||||||
@@ -21,13 +21,13 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/x509roots/nss"
|
"golang.org/x/crypto/x509roots/nss"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tmpl = `// Code generated by gen.go at %s; DO NOT EDIT.
|
const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
||||||
// list hash: %x
|
|
||||||
|
//go:build go1.20
|
||||||
|
|
||||||
package fallback
|
package fallback
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func mustParse(b []byte) []*x509.Certificate {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if block.Type != "CERTIFICATE" {
|
if block.Type != "CERTIFICATE" {
|
||||||
panic("unexpected PEM block type: "+block.Type)
|
panic("unexpected PEM block type: " + block.Type)
|
||||||
}
|
}
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,18 +64,14 @@ var bundle = mustParse([]byte(pemRoots))
|
|||||||
`
|
`
|
||||||
|
|
||||||
var (
|
var (
|
||||||
certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (only one of certdata-url and certdata-path may be specified)")
|
certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (certdata-path overrides this, if provided)")
|
||||||
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (only one of certdata-url and certdata-path may be specified)")
|
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (this overrides certdata-url, if provided)")
|
||||||
output = flag.String("output", "fallback/bundle.go", "Path to file to write output to")
|
output = flag.String("output", "fallback/bundle.go", "Path to file to write output to")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *certDataPath != "" && *certDataURL != "" {
|
|
||||||
log.Fatal("Only one of --certdata-url and --certdata-path may be supplied")
|
|
||||||
}
|
|
||||||
|
|
||||||
var certdata io.Reader
|
var certdata io.Reader
|
||||||
|
|
||||||
if *certDataPath != "" {
|
if *certDataPath != "" {
|
||||||
@@ -100,18 +96,21 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(certs, func(i, j int) bool {
|
sort.Slice(certs, func(i, j int) bool {
|
||||||
return certs[i].X509.Subject.String() < certs[j].X509.Subject.String()
|
// Sort based on the stringified subject (which may not be unique), and
|
||||||
|
// break any ties by just sorting on the raw DER (which will be unique,
|
||||||
|
// but is expensive). This should produce a stable sorting, which should
|
||||||
|
// be mostly readable by a human looking for a specific root or set of
|
||||||
|
// roots.
|
||||||
|
subjI, subjJ := certs[i].X509.Subject.String(), certs[j].X509.Subject.String()
|
||||||
|
if subjI == subjJ {
|
||||||
|
return string(certs[i].X509.Raw) < string(certs[j].X509.Raw)
|
||||||
|
}
|
||||||
|
return subjI < subjJ
|
||||||
})
|
})
|
||||||
|
|
||||||
h := sha256.New()
|
b := new(bytes.Buffer)
|
||||||
for _, c := range certs {
|
b.WriteString(tmpl)
|
||||||
h.Write(c.X509.Raw)
|
fmt.Fprintln(b, "const pemRoots = `")
|
||||||
}
|
|
||||||
listHash := h.Sum(nil)
|
|
||||||
|
|
||||||
b := bytes.NewBuffer(nil)
|
|
||||||
b.Write([]byte(fmt.Sprintf(tmpl, time.Now().Format(time.RFC1123), listHash)))
|
|
||||||
b.Write([]byte("const pemRoots = `\n"))
|
|
||||||
for _, c := range certs {
|
for _, c := range certs {
|
||||||
if len(c.Constraints) > 0 {
|
if len(c.Constraints) > 0 {
|
||||||
// Until the constrained roots API lands, skip anything that has any
|
// Until the constrained roots API lands, skip anything that has any
|
||||||
@@ -120,10 +119,10 @@ func main() {
|
|||||||
// new version.
|
// new version.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.Write([]byte(fmt.Sprintf("# %s\n# %x\n", c.X509.Subject.String(), sha256.Sum256(c.X509.Raw))))
|
fmt.Fprintf(b, "# %s\n# %x\n", c.X509.Subject.String(), sha256.Sum256(c.X509.Raw))
|
||||||
pem.Encode(b, &pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw})
|
pem.Encode(b, &pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw})
|
||||||
}
|
}
|
||||||
b.Write([]byte("`\n"))
|
fmt.Fprintln(b, "`")
|
||||||
|
|
||||||
formatted, err := format.Source(b.Bytes())
|
formatted, err := format.Source(b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user