2019-08-19 18:51:59 +00:00
|
|
|
//+build !windows
|
|
|
|
|
|
|
|
package sshserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/gliderlabs/ssh"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-09-30 20:44:23 +00:00
|
|
|
systemConfigPath = "/usr/local/etc/cloudflared/"
|
|
|
|
rsaFilename = "ssh_host_rsa_key"
|
|
|
|
ecdsaFilename = "ssh_host_ecdsa_key"
|
2019-08-19 18:51:59 +00:00
|
|
|
)
|
|
|
|
|
2019-09-30 20:44:23 +00:00
|
|
|
func (s *SSHProxy) configureHostKeys() error {
|
2019-08-22 16:36:21 +00:00
|
|
|
if _, err := os.Stat(systemConfigPath); os.IsNotExist(err) {
|
|
|
|
if err := os.MkdirAll(systemConfigPath, 0755); err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("Error creating %s directory", systemConfigPath))
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.configureHostKey(s.ensureECDSAKeyExists); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.configureHostKey(s.ensureRSAKeyExists); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-30 20:44:23 +00:00
|
|
|
func (s *SSHProxy) configureHostKey(keyFunc func() (string, error)) error {
|
2019-08-19 18:51:59 +00:00
|
|
|
path, err := keyFunc()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.SetOption(ssh.HostKeyFile(path)); err != nil {
|
|
|
|
return errors.Wrap(err, "Could not set SSH host key")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-30 20:44:23 +00:00
|
|
|
func (s *SSHProxy) ensureRSAKeyExists() (string, error) {
|
2019-08-22 16:36:21 +00:00
|
|
|
keyPath := filepath.Join(systemConfigPath, rsaFilename)
|
2019-08-19 18:51:59 +00:00
|
|
|
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
|
|
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "Error generating RSA host key")
|
|
|
|
}
|
|
|
|
|
|
|
|
privateKey := &pem.Block{
|
|
|
|
Type: "RSA PRIVATE KEY",
|
|
|
|
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
s.logger.Debug("Created new RSA SSH host key: ", keyPath)
|
|
|
|
}
|
|
|
|
return keyPath, nil
|
|
|
|
}
|
|
|
|
|
2019-09-30 20:44:23 +00:00
|
|
|
func (s *SSHProxy) ensureECDSAKeyExists() (string, error) {
|
2019-08-22 16:36:21 +00:00
|
|
|
keyPath := filepath.Join(systemConfigPath, ecdsaFilename)
|
2019-08-19 18:51:59 +00:00
|
|
|
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
|
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "Error generating ECDSA host key")
|
|
|
|
}
|
|
|
|
|
|
|
|
keyBytes, err := x509.MarshalECPrivateKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "Error marshalling ECDSA key")
|
|
|
|
}
|
|
|
|
|
|
|
|
privateKey := &pem.Block{
|
|
|
|
Type: "EC PRIVATE KEY",
|
|
|
|
Bytes: keyBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
s.logger.Debug("Created new ECDSA SSH host key: ", keyPath)
|
|
|
|
}
|
|
|
|
return keyPath, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func writePrivateKey(keyPath string, privateKey *pem.Block) error {
|
|
|
|
if err := ioutil.WriteFile(keyPath, pem.EncodeToMemory(privateKey), 0600); err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("Error writing host key to %s", keyPath))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|