2013-05-21 01:50:13 -04:00
|
|
|
package ssh
|
|
|
|
|
|
|
|
import (
|
2013-09-16 02:13:05 -04:00
|
|
|
"code.google.com/p/go.crypto/ssh"
|
2013-05-21 01:50:13 -04:00
|
|
|
"crypto"
|
|
|
|
"crypto/dsa"
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2013-08-11 19:15:10 -04:00
|
|
|
// SimpleKeychain makes it easy to use private keys in order to connect
|
|
|
|
// via SSH, since the interface exposed by Go isn't the easiest to use
|
|
|
|
// right away.
|
2013-05-21 01:50:13 -04:00
|
|
|
type SimpleKeychain struct {
|
|
|
|
keys []interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddPEMKey adds a simple PEM encoded private key to the keychain.
|
|
|
|
func (k *SimpleKeychain) AddPEMKey(key string) (err error) {
|
|
|
|
block, _ := pem.Decode([]byte(key))
|
2013-08-28 01:54:56 -04:00
|
|
|
if block == nil {
|
|
|
|
return errors.New("no block in key")
|
|
|
|
}
|
|
|
|
|
2013-09-01 00:54:23 -04:00
|
|
|
var rsakey interface{}
|
|
|
|
rsakey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
rsakey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
|
|
}
|
|
|
|
|
2013-05-21 01:50:13 -04:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
k.keys = append(k.keys, rsakey)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-08-11 19:15:10 -04:00
|
|
|
// AddPEMKeyPassword adds a PEM encoded private key that is protected by
|
|
|
|
// a password to the keychain.
|
2013-08-11 12:46:28 -04:00
|
|
|
func (k *SimpleKeychain) AddPEMKeyPassword(key string, password string) (err error) {
|
|
|
|
block, _ := pem.Decode([]byte(key))
|
|
|
|
bytes, _ := x509.DecryptPEMBlock(block, []byte(password))
|
|
|
|
rsakey, err := x509.ParsePKCS1PrivateKey(bytes)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
k.keys = append(k.keys, rsakey)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-05-21 01:50:13 -04:00
|
|
|
// Key method for ssh.ClientKeyring interface
|
2013-09-15 15:21:21 -04:00
|
|
|
func (k *SimpleKeychain) Key(i int) (ssh.PublicKey, error) {
|
2013-05-21 01:50:13 -04:00
|
|
|
if i < 0 || i >= len(k.keys) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
switch key := k.keys[i].(type) {
|
|
|
|
case *rsa.PrivateKey:
|
2013-09-20 00:30:22 -04:00
|
|
|
return ssh.NewPublicKey(&key.PublicKey)
|
2013-05-21 01:50:13 -04:00
|
|
|
case *dsa.PrivateKey:
|
2013-09-20 00:30:22 -04:00
|
|
|
return ssh.NewPublicKey(&key.PublicKey)
|
2013-05-21 01:50:13 -04:00
|
|
|
}
|
|
|
|
panic("unknown key type")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign method for ssh.ClientKeyring interface
|
|
|
|
func (k *SimpleKeychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
|
|
|
|
hashFunc := crypto.SHA1
|
|
|
|
h := hashFunc.New()
|
|
|
|
h.Write(data)
|
|
|
|
digest := h.Sum(nil)
|
|
|
|
switch key := k.keys[i].(type) {
|
|
|
|
case *rsa.PrivateKey:
|
|
|
|
return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
|
|
|
|
}
|
|
|
|
return nil, errors.New("ssh: unknown key type")
|
|
|
|
}
|