From 02ca61b21ea890c7bc4ce29af5295367e78763a1 Mon Sep 17 00:00:00 2001 From: Thomas Elsgaard Date: Wed, 28 Dec 2022 22:40:12 +0100 Subject: [PATCH] Add cert support --- README.md | 2 +- simplessh.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 086b0c8..98da5da 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ SimpleSSH is a simple wrapper around go ssh and sftp libraries. ## Features -* Multiple authentication methods (password, private key and ssh-agent) +* Multiple authentication methods (password, private key, certificate and ssh-agent) * Sudo support * Simple file upload/download support diff --git a/simplessh.go b/simplessh.go index c4d4fb3..cf6d951 100644 --- a/simplessh.go +++ b/simplessh.go @@ -83,6 +83,36 @@ func ConnectWithKeyFileTimeout(host, username, privKeyPath string, timeout time. return ConnectWithKeyTimeout(host, username, string(privKey), timeout) } +// Connect with a certificate file. +// If privKeyPath is an empty string it will attempt to use $HOME/.ssh/id_rsa. +// If pubCertPath is an empty string it will attempt to use $HOME/.ssh/id_rsa-cert.pub. +// If username is empty simplessh will attempt to get the current user. +func ConnectWithCertFile(host, username, privKeyPath, pubCertPath string) (*Client, error) { + if privKeyPath == "" { + currentUser, err := user.Current() + if err == nil { + privKeyPath = filepath.Join(currentUser.HomeDir, ".ssh", "id_rsa") + } + } + if pubCertPath == "" { + currentUser, err := user.Current() + if err == nil { + privKeyPath = filepath.Join(currentUser.HomeDir, ".ssh", "id_rsa-cert.pub") + } + } + + privKey, err := ioutil.ReadFile(privKeyPath) + if err != nil { + return nil, err + } + pubCert, err := ioutil.ReadFile(pubCertPath) + if err != nil { + return nil, err + } + + return ConnectWithCertTimeout(host, username, string(privKey), string(pubCert), DefaultTimeout) +} + // Connect with a private key with passphrase. If privKeyPath is an empty string it will attempt // to use $HOME/.ssh/id_rsa. If username is empty simplessh will attempt to get the current user. func ConnectWithKeyFilePassphraseTimeout(host, username, privKeyPath string, passPhrase string, timeout time.Duration) (*Client, error) { @@ -126,6 +156,28 @@ func ConnectWithKeyTimeout(host, username, privKey string, timeout time.Duration return connect(username, host, authMethod, timeout) } +// Connect with a certificate with a custom timeout. If username is empty simplessh will attempt to get the current user. +func ConnectWithCertTimeout(host, username, privKey, pubCert string, timeout time.Duration) (*Client, error) { + signer, err := ssh.ParsePrivateKey([]byte(privKey)) + if err != nil { + return nil, err + } + + cert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pubCert)) + if err != nil { + return nil, err + } + + certSigner, err := ssh.NewCertSigner(cert.(*ssh.Certificate), signer) + if err != nil { + return nil, err + } + + authMethod := ssh.PublicKeys(certSigner) + + return connect(username, host, authMethod, timeout) +} + // Connect with a private key with passphrase with a custom timeout. If username is empty simplessh will attempt to get the current user. func ConnectWithKeyPassphraseTimeout(host, username string, signer ssh.Signer, timeout time.Duration) (*Client, error) { authMethod := ssh.PublicKeys(signer)