From 60165db50ac4760f8c83ee77dc383a968d7d8bb0 Mon Sep 17 00:00:00 2001 From: Jaime Pillora Date: Sun, 9 Jul 2023 21:53:02 +1000 Subject: [PATCH] Deterministic private key with Go 1.20 #427 commit 234a8f6b8cb032d508724978ca9da335e9282574 Author: cmeng Date: Tue May 16 10:26:19 2023 +1200 allow users to specify a private key file commit 85a7d96b0cc1b894fe7a51e978b2706c8ab65273 Author: cmeng Date: Tue May 16 10:25:20 2023 +1200 generate deterministic key with a given seed --- main.go | 9 +++++++-- server/server.go | 22 ++++++++++++++++++---- share/ccrypto/determ_rand.go | 9 ++++++++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index eb50e6c..f3aad1f 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "flag" "fmt" - "io/ioutil" "log" "net/http" "os" @@ -87,7 +86,7 @@ var commonHelp = ` func generatePidFile() { pid := []byte(strconv.Itoa(os.Getpid())) - if err := ioutil.WriteFile("chisel.pid", pid, 0644); err != nil { + if err := os.WriteFile("chisel.pid", pid, 0644); err != nil { log.Fatal(err) } } @@ -109,6 +108,11 @@ var serverHelp = ` of man-in-the-middle attacks (defaults to the CHISEL_KEY environment variable, otherwise a new key is generate each run). + --key-file, An optional path to a PEM-encoded SSH private key. When + this flag is set, the --key option is ignored. 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 +174,7 @@ func server(args []string) { config := &chserver.Config{} flags.StringVar(&config.KeySeed, "key", "", "") + flags.StringVar(&config.KeyFile, "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 b7df128..fa5a5af 100644 --- a/server/server.go +++ b/server/server.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httputil" "net/url" + "os" "regexp" "time" @@ -23,6 +24,7 @@ import ( // Config is the configuration for the chisel service type Config struct { KeySeed string + KeyFile string AuthFile string Auth string Proxy string @@ -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.KeyFile != "" { + //read private key from the file specified path + key, err = os.ReadFile(c.KeyFile) + 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 24ff444..5573709 100644 --- a/share/ccrypto/determ_rand.go +++ b/share/ccrypto/determ_rand.go @@ -34,7 +34,14 @@ 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 }