diff --git a/main.go b/main.go index eb50e6ca..142ec428 100644 --- a/main.go +++ b/main.go @@ -109,6 +109,11 @@ var serverHelp = ` of man-in-the-middle attacks (defaults to the CHISEL_KEY environment variable, otherwise a new key is generate each run). + --private-key-file, An optional path to a PEM-encoded TLS private key. When + this flag is set, the --key option is omitted, and the provided private key + is used to secure all communications. A private key file can be generated by: + openssl ecparam -name prime256v1 -genkey -out private_key.pem + --authfile, An optional path to a users.json file. This file should be an object with users defined like: { @@ -170,6 +175,7 @@ func server(args []string) { config := &chserver.Config{} flags.StringVar(&config.KeySeed, "key", "", "") + flags.StringVar(&config.PrivateKeyFile, "private-key-file", "", "") flags.StringVar(&config.AuthFile, "authfile", "", "") flags.StringVar(&config.Auth, "auth", "", "") flags.DurationVar(&config.KeepAlive, "keepalive", 25*time.Second, "") diff --git a/server/server.go b/server/server.go index b7df1282..88ef2a2c 100644 --- a/server/server.go +++ b/server/server.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httputil" "net/url" + "os" "regexp" "time" @@ -22,14 +23,15 @@ import ( // Config is the configuration for the chisel service type Config struct { - KeySeed string - AuthFile string - Auth string - Proxy string - Socks5 bool - Reverse bool - KeepAlive time.Duration - TLS TLSConfig + KeySeed string + AuthFile string + Auth string + Proxy string + Socks5 bool + Reverse bool + KeepAlive time.Duration + TLS TLSConfig + PrivateKeyFile string } // Server respresent a chisel service @@ -73,11 +75,23 @@ func NewServer(c *Config) (*Server, error) { server.users.AddUser(u) } } - //generate private key (optionally using seed) - key, err := ccrypto.GenerateKey(c.KeySeed) - if err != nil { - log.Fatal("Failed to generate key") + + var key []byte + var err error + if c.PrivateKeyFile != "" { + //read private key from the file specified by the --private-key-file flag + key, err = os.ReadFile(c.PrivateKeyFile) + if err != nil { + log.Fatal("Failed to read private key from disk") + } + } else { + //generate private key (optionally using seed) + key, err = ccrypto.GenerateKey(c.KeySeed) + if err != nil { + log.Fatal("Failed to generate key") + } } + //convert into ssh.PrivateKey private, err := ssh.ParsePrivateKey(key) if err != nil { diff --git a/share/ccrypto/determ_rand.go b/share/ccrypto/determ_rand.go index 24ff444b..63646bdf 100644 --- a/share/ccrypto/determ_rand.go +++ b/share/ccrypto/determ_rand.go @@ -34,7 +34,15 @@ func (d *determRand) Read(b []byte) (int, error) { for n < l { next, out := hash(d.next) n += copy(b[n:], out) - d.next = next + + // In Golang 1.20, ecdsa.GenerateKey() introduced a function called + // MaybeReadRand() which reads 1 byte from the determRand reader + // with 50% chance. As a result, GenerateKey() generates + // nondeterministic keys. + // The following conditional check neutralizes this effect. + if l > 1 { + d.next = next + } } return n, nil }