From 321e26fae746e661d713cedfb6642609e680cafe Mon Sep 17 00:00:00 2001 From: fuero Date: Mon, 5 Jun 2017 23:28:13 +0200 Subject: Saving private keys (#61) * enables saving private keys * renames public_file_prefix to key_file_prefix and updates its docs to better reflect the changes --- client/client.go | 21 +++++++++++++++++++-- client/config.go | 4 ++-- client/keys.go | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) (limited to 'client') diff --git a/client/client.go b/client/client.go index 305d0d2..8ebe29a 100644 --- a/client/client.go +++ b/client/client.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "encoding/base64" "encoding/json" + "encoding/pem" "fmt" "io/ioutil" "net/http" @@ -33,14 +34,30 @@ func SavePublicFiles(prefix string, cert *ssh.Certificate, pub ssh.PublicKey) er pubTxt := ssh.MarshalAuthorizedKey(pub) certPubTxt := []byte(cert.Type() + " " + base64.StdEncoding.EncodeToString(cert.Marshal())) - if err := ioutil.WriteFile(prefix+".pub", pubTxt, 0644); err != nil { + _prefix := prefix + "/id_" + cert.KeyId + + if err := ioutil.WriteFile(_prefix+".pub", pubTxt, 0644); err != nil { return err } - err := ioutil.WriteFile(prefix+"-cert.pub", certPubTxt, 0644) + err := ioutil.WriteFile(_prefix+"-cert.pub", certPubTxt, 0644) return err } +// SavePrivateFiles installs the private part of the key. +func SavePrivateFiles(prefix string, cert *ssh.Certificate, key Key) error { + if prefix == "" { + return nil + } + _prefix := prefix + "/id_" + cert.KeyId + pemBlock, err := pemBlockForKey(key); + if err != nil { + return err + } + err = ioutil.WriteFile(_prefix, pem.EncodeToMemory(pemBlock), 0600) + return err +} + // InstallCert adds the private key and signed certificate to the ssh agent. func InstallCert(a agent.Agent, cert *ssh.Certificate, key Key) error { t := time.Unix(int64(cert.ValidBefore), 0) diff --git a/client/config.go b/client/config.go index 07bbb8c..eae3bfa 100644 --- a/client/config.go +++ b/client/config.go @@ -13,7 +13,7 @@ type Config struct { Keysize int `mapstructure:"key_size"` Validity string `mapstructure:"validity"` ValidateTLSCertificate bool `mapstructure:"validate_tls_certificate"` - PublicFilePrefix string `mapstructure:"public_file_prefix"` + PublicFilePrefix string `mapstructure:"key_file_prefix"` } func setDefaults() { @@ -21,7 +21,7 @@ func setDefaults() { viper.BindPFlag("key_type", pflag.Lookup("key_type")) viper.BindPFlag("key_size", pflag.Lookup("key_size")) viper.BindPFlag("validity", pflag.Lookup("validity")) - viper.BindPFlag("public_file_prefix", pflag.Lookup("public_file_prefix")) + viper.BindPFlag("key_file_prefix", pflag.Lookup("key_file_prefix")) viper.SetDefault("validateTLSCertificate", true) } diff --git a/client/keys.go b/client/keys.go index 73983a8..b488ea2 100644 --- a/client/keys.go +++ b/client/keys.go @@ -6,12 +6,16 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + "crypto/x509" + "encoding/pem" "fmt" "github.com/pkg/errors" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" + + "github.com/mikesmitty/edkey" ) // Key is a private key. @@ -32,6 +36,24 @@ var defaultOptions = options{ // A KeyOption is used to generate keys of different types and sizes. type KeyOption func(*options) +func pemBlockForKey(priv interface{}) (*pem.Block, error) { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + return nil, err + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil + case *ed25519.PrivateKey: + b := edkey.MarshalED25519PrivateKey(*k) + return &pem.Block{Type: "OPENSSH PRIVATE KEY", Bytes: b}, nil + default: + return nil, fmt.Errorf("Unable to create PEM blck from key") + } +} + // KeyType sets the type of key to generate. // Valid types are: "rsa", "ecdsa", "ed25519". // Default is "rsa" -- cgit v1.2.3