mirror of https://github.com/docker/docs.git
125 lines
2.4 KiB
Go
125 lines
2.4 KiB
Go
package ssh
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"runtime"
|
|
|
|
gossh "golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
var (
|
|
ErrKeyGeneration = errors.New("Unable to generate key")
|
|
ErrValidation = errors.New("Unable to validate key")
|
|
ErrPublicKey = errors.New("Unable to convert public key")
|
|
ErrUnableToWriteFile = errors.New("Unable to write file")
|
|
)
|
|
|
|
type KeyPair struct {
|
|
PrivateKey []byte
|
|
PublicKey []byte
|
|
}
|
|
|
|
// Generate a new SSH keypair
|
|
// This will return a private & public key encoded as DER.
|
|
func NewKeyPair() (keyPair *KeyPair, err error) {
|
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, ErrKeyGeneration
|
|
}
|
|
|
|
if err := priv.Validate(); err != nil {
|
|
return nil, ErrValidation
|
|
}
|
|
|
|
privDer := x509.MarshalPKCS1PrivateKey(priv)
|
|
|
|
pubSSH, err := gossh.NewPublicKey(&priv.PublicKey)
|
|
if err != nil {
|
|
return nil, ErrPublicKey
|
|
}
|
|
|
|
return &KeyPair{
|
|
PrivateKey: privDer,
|
|
PublicKey: gossh.MarshalAuthorizedKey(pubSSH),
|
|
}, nil
|
|
}
|
|
|
|
// Write keypair to files
|
|
func (kp *KeyPair) WriteToFile(privateKeyPath string, publicKeyPath string) error {
|
|
files := []struct {
|
|
File string
|
|
Type string
|
|
Value []byte
|
|
}{
|
|
{
|
|
File: privateKeyPath,
|
|
Value: pem.EncodeToMemory(&pem.Block{"RSA PRIVATE KEY", nil, kp.PrivateKey}),
|
|
},
|
|
{
|
|
File: publicKeyPath,
|
|
Value: kp.PublicKey,
|
|
},
|
|
}
|
|
|
|
for _, v := range files {
|
|
f, err := os.Create(v.File)
|
|
if err != nil {
|
|
return ErrUnableToWriteFile
|
|
}
|
|
|
|
if _, err := f.Write(v.Value); err != nil {
|
|
return ErrUnableToWriteFile
|
|
}
|
|
|
|
// windows does not support chmod
|
|
switch runtime.GOOS {
|
|
case "darwin", "linux":
|
|
if err := f.Chmod(0600); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Calculate the fingerprint of the public key
|
|
func (kp *KeyPair) Fingerprint() string {
|
|
b, _ := base64.StdEncoding.DecodeString(string(kp.PublicKey))
|
|
h := md5.New()
|
|
|
|
io.WriteString(h, string(b))
|
|
|
|
return fmt.Sprintf("%x", h.Sum(nil))
|
|
}
|
|
|
|
// Generate SSH keypair based on path of the private key
|
|
// The public key would be generated to the same path with ".pub" added
|
|
func GenerateSSHKey(path string) error {
|
|
if _, err := os.Stat(path); err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
|
|
kp, err := NewKeyPair()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := kp.WriteToFile(path, fmt.Sprintf("%s.pub", path)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|