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 (
|
2020-04-29 20:51:32 +00:00
|
|
|
rsaFilename = "ssh_host_rsa_key"
|
|
|
|
ecdsaFilename = "ssh_host_ecdsa_key"
|
2019-08-19 18:51:59 +00:00
|
|
|
)
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
var defaultHostKeyDir = filepath.Join(".cloudflared", "host_keys")
|
|
|
|
|
|
|
|
func (s *SSHProxy) configureHostKeys(hostKeyDir string) error {
|
|
|
|
if hostKeyDir == "" {
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
2019-10-17 21:23:06 +00:00
|
|
|
hostKeyDir = filepath.Join(homeDir, defaultHostKeyDir)
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
if _, err := os.Stat(hostKeyDir); os.IsNotExist(err) {
|
|
|
|
if err := os.MkdirAll(hostKeyDir, 0755); err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("Error creating %s directory", hostKeyDir))
|
|
|
|
}
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
if err := s.configureECDSAKey(hostKeyDir); err != nil {
|
2019-08-19 18:51:59 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
if err := s.configureRSAKey(hostKeyDir); err != nil {
|
2019-08-19 18:51:59 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
func (s *SSHProxy) configureRSAKey(basePath string) error {
|
|
|
|
keyPath := filepath.Join(basePath, 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 {
|
2019-10-17 21:23:06 +00:00
|
|
|
return errors.Wrap(err, "Error generating RSA host key")
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
privateKey := &pem.Block{
|
|
|
|
Type: "RSA PRIVATE KEY",
|
|
|
|
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
2019-10-17 21:23:06 +00:00
|
|
|
return err
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
2020-04-29 20:51:32 +00:00
|
|
|
s.logger.Debugf("Created new RSA SSH host key: %s", keyPath)
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
2019-10-17 21:23:06 +00:00
|
|
|
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
|
|
|
return errors.Wrap(err, "Could not set SSH RSA host key")
|
|
|
|
}
|
|
|
|
return nil
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 21:23:06 +00:00
|
|
|
func (s *SSHProxy) configureECDSAKey(basePath string) error {
|
|
|
|
keyPath := filepath.Join(basePath, 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 {
|
2019-10-17 21:23:06 +00:00
|
|
|
return errors.Wrap(err, "Error generating ECDSA host key")
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
keyBytes, err := x509.MarshalECPrivateKey(key)
|
|
|
|
if err != nil {
|
2019-10-17 21:23:06 +00:00
|
|
|
return errors.Wrap(err, "Error marshalling ECDSA key")
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
privateKey := &pem.Block{
|
|
|
|
Type: "EC PRIVATE KEY",
|
|
|
|
Bytes: keyBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
2019-10-17 21:23:06 +00:00
|
|
|
return err
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
2020-04-29 20:51:32 +00:00
|
|
|
s.logger.Debugf("Created new ECDSA SSH host key: %s", keyPath)
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
2019-10-17 21:23:06 +00:00
|
|
|
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
|
|
|
return errors.Wrap(err, "Could not set SSH ECDSA host key")
|
|
|
|
}
|
|
|
|
return nil
|
2019-08-19 18:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|