grim/convey

closing merged branch
hostnames
2017-10-13, Gary Kramlich
33eae19fcbbe
closing merged branch
/*
* Convey
* Copyright 2016-2017 Gary Kramlich <grim@reaperworld.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ssh
import (
"fmt"
"io"
"net"
"os"
"strings"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
// KeysAvailable returns True if there is at least one key that the ssh agent
// knows about, otherwise false. err will be set if there is an error along
// the way.
func KeysAvailable(identites []string) (bool, error) {
sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
return false, err
}
return keysAvailable(sshAgent, identites)
}
func keysAvailable(rw io.ReadWriter, identities []string) (bool, error) {
keys, err := agent.NewClient(rw).List()
if err != nil {
return false, err
}
// this runs in O(m * n) but thankful the number of keys should be low.
for _, identity := range identities {
if identity == "*" {
// if the user doesn't care which key and we have a key, return true
if len(keys) > 0 {
return true, nil
} else {
// if the user doesn't care which key but we have no keys, return an error
return false, fmt.Errorf("no ssh keys available")
}
}
uIdentity := strings.ToUpper(identity)
for _, pubKey := range keys {
fpSHA256 := strings.ToUpper(ssh.FingerprintSHA256(pubKey))
fpMD5 := strings.ToUpper(ssh.FingerprintLegacyMD5(pubKey))
if strings.HasPrefix(uIdentity, "SHA256:") {
if uIdentity == fpSHA256 {
return true, nil
}
} else if strings.HasPrefix(uIdentity, "MD5:") {
if uIdentity[4:] == fpMD5 {
return true, nil
}
} else {
// no known prefix check sha256 then md5, then give up
if uIdentity == fpSHA256[7:] || uIdentity == fpMD5 {
return true, nil
}
}
}
}
if err == nil {
err = fmt.Errorf("no usable ssh identities found")
}
return false, err
}
func ShouldEnable(identities []string) (bool, error) {
if len(identities) <= 0 {
return false, nil
}
haveKeys, err := KeysAvailable(identities)
if err != nil {
return false, fmt.Errorf("error talking to ssh-agent: %s", err)
}
if !haveKeys {
return false, fmt.Errorf("no keys available in ssh-agent")
}
return true, nil
}