github.com/supr/packer@v0.3.10-0.20131015195147-7b09e24ac3c1/communicator/ssh/keychain.go (about)

     1  package ssh
     2  
     3  import (
     4  	"code.google.com/p/go.crypto/ssh"
     5  	"crypto"
     6  	"crypto/dsa"
     7  	"crypto/rsa"
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"errors"
    11  	"io"
    12  )
    13  
    14  // SimpleKeychain makes it easy to use private keys in order to connect
    15  // via SSH, since the interface exposed by Go isn't the easiest to use
    16  // right away.
    17  type SimpleKeychain struct {
    18  	keys []interface{}
    19  }
    20  
    21  // AddPEMKey adds a simple PEM encoded private key to the keychain.
    22  func (k *SimpleKeychain) AddPEMKey(key string) (err error) {
    23  	block, _ := pem.Decode([]byte(key))
    24  	if block == nil {
    25  		return errors.New("no block in key")
    26  	}
    27  
    28  	var rsakey interface{}
    29  	rsakey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
    30  	if err != nil {
    31  		rsakey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
    32  	}
    33  
    34  	if err != nil {
    35  		return
    36  	}
    37  
    38  	k.keys = append(k.keys, rsakey)
    39  	return
    40  }
    41  
    42  // AddPEMKeyPassword adds a PEM encoded private key that is protected by
    43  // a password to the keychain.
    44  func (k *SimpleKeychain) AddPEMKeyPassword(key string, password string) (err error) {
    45  	block, _ := pem.Decode([]byte(key))
    46  	bytes, _ := x509.DecryptPEMBlock(block, []byte(password))
    47  	rsakey, err := x509.ParsePKCS1PrivateKey(bytes)
    48  	if err != nil {
    49  		return
    50  	}
    51  
    52  	k.keys = append(k.keys, rsakey)
    53  	return
    54  }
    55  
    56  // Key method for ssh.ClientKeyring interface
    57  func (k *SimpleKeychain) Key(i int) (ssh.PublicKey, error) {
    58  	if i < 0 || i >= len(k.keys) {
    59  		return nil, nil
    60  	}
    61  	switch key := k.keys[i].(type) {
    62  	case *rsa.PrivateKey:
    63  		return ssh.NewPublicKey(&key.PublicKey)
    64  	case *dsa.PrivateKey:
    65  		return ssh.NewPublicKey(&key.PublicKey)
    66  	}
    67  	panic("unknown key type")
    68  }
    69  
    70  // Sign method for ssh.ClientKeyring interface
    71  func (k *SimpleKeychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
    72  	hashFunc := crypto.SHA1
    73  	h := hashFunc.New()
    74  	h.Write(data)
    75  	digest := h.Sum(nil)
    76  	switch key := k.keys[i].(type) {
    77  	case *rsa.PrivateKey:
    78  		return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
    79  	}
    80  	return nil, errors.New("ssh: unknown key type")
    81  }