From 39b86be02595cd6a8d889d81bb880a29e7790cb9 Mon Sep 17 00:00:00 2001 From: David Cowden <dcow@smallstep.com> Date: Sat, 20 Jun 2020 21:45:57 -0700 Subject: [PATCH] keys: Add cert utilities and polish/cleanup * Add utility funcs to load ssh certs. * Rename key loading funcs to mirror the ssh package. * Replace the example server key with an unencrypted key. --- example/hostkey/main.go | 2 +- example/server.key | 16 ++++++------ example/shutdown/main.go | 2 +- keys.go | 55 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/example/hostkey/main.go b/example/hostkey/main.go index 2b5011a..9d15a79 100644 --- a/example/hostkey/main.go +++ b/example/hostkey/main.go @@ -13,7 +13,7 @@ func main() { // initialization to be skipped. Config: sshutil.DefaultServerConfig(), } - key, err := sshutil.LoadHostKeyFromFile("example/server.key", "") + key, err := sshutil.LoadKeyFromFile("example/server.key") if err != nil { log.Fatalf("error loading key: %v", err) } diff --git a/example/server.key b/example/server.key index 41c13c1..cebd4d6 100644 --- a/example/server.key +++ b/example/server.key @@ -1,8 +1,8 @@ ------BEGIN EC PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-256-CBC,8baf741fa93dda7c63627c9dfd0c27db - -QR2/pYnAnzkbXY6zLY7FjzTO5YkKPjMad/Sf0vl/SMfWdMf2hNhu5vg6NT33VnJZ -g2saTuAubdmwlbdwK59Xdid2CNKlFol+sHXfiyOv9/mEHXo5okLt2RykLZn/YqEu -YkYTwTuRcbZsFdO0RjbzlyBbMFuf/Mugwn+15QUMebM= ------END EC PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSS676S0EQA8E15kIWgWCxxLHJ9+GOC +2gfT9WTfcDrugGZclQgcuoTRruw2LdKurR8nWO4bTG92+VJWKPyM8lDMAAAAoKsLCAqrCw +gKAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJLrvpLQRADwTXmQ +haBYLHEscn34Y4LaB9P1ZN9wOu6AZlyVCBy6hNGu7DYt0q6tHydY7htMb3b5UlYo/IzyUM +wAAAAgKH54GDXLjYqPfHs1b6nDzJ8dHseFkYjVyojf1qJQ+B8AAAAEbGVhZgECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/example/shutdown/main.go b/example/shutdown/main.go index a482a36..aa00ca8 100644 --- a/example/shutdown/main.go +++ b/example/shutdown/main.go @@ -22,7 +22,7 @@ func main() { L: log.New(os.Stderr, "", log.LstdFlags), } { // scope err - key, err := sshutil.LoadHostKeyFromFile("example/server.key", "") + key, err := sshutil.LoadKeyFromFile("example/server.key") if err != nil { log.Fatalf("error loading key: %v", err) } diff --git a/keys.go b/keys.go index 6b737e5..d71194c 100644 --- a/keys.go +++ b/keys.go @@ -10,9 +10,58 @@ import ( "golang.org/x/crypto/ssh" ) -// LoadHostKeyFromFile returns an ssh.Signer from the key stored at the given -// filesystem path, decrypted using pass. -func LoadHostKeyFromFile(path, pass string) (ssh.Signer, error) { +// LoadCertFromKeyFileOpenSSH returns an ssh.Signer from the unencrypted key +// stored at the given filesystem path with a public key that is the ssh +// certificate loaded from the file "<path>-cert.pub". This is how ssh-add looks +// for certs when adding keys to ssh-agent. +func LoadCertFromKeyFileOpenSSH(keypath string) (ssh.Signer, error) { + certpath := keypath + "-cert.pub" + return LoadCertFromFiles(keypath, certpath) +} + +// LoadCertFromFiles returns an ssh.Signer with private key loaded from the +// unecrypted path keypath and a public cert component loaded from certpath. +func LoadCertFromFiles(keypath, certpath string) (ssh.Signer, error) { + // Read host key from a file, parse using x/crypto/ssh. + kb, err := ioutil.ReadFile(keypath) + if err != nil { + return nil, err + } + key, err := ssh.ParsePrivateKey(kb) + if err != nil { + return nil, err + } + cb, err := ioutil.ReadFile(certpath) + if err != nil { + return nil, err + } + pub, err := ssh.ParsePublicKey(cb) + if err != nil { + return nil, err + } + cert := pub.(*ssh.Certificate) + signer, err := ssh.NewCertSigner(cert, key) + return signer, nil +} + +// LoadKeyFromFile returns an ssh.Signer from the unencrypted key stored +// at the given filesystem path. +func LoadKeyFromFile(path string) (ssh.Signer, error) { + // Read host key from a file, parse using x/crypto/ssh. + bytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + key, err := ssh.ParsePrivateKey(bytes) + if err != nil { + return nil, err + } + return key, nil +} + +// LoadKeyFromFileWithPass returns an ssh.Signer from the key stored at the +// given filesystem path, decrypted using pass. +func LoadKeyFromFileWithPass(path, pass string) (ssh.Signer, error) { // Read host key from a file, parse using x/crypto/ssh. bytes, err := ioutil.ReadFile(path) if err != nil { -- GitLab