package main import ( "crypto/x509" "encoding/pem" "errors" "fmt" "golang.org/x/crypto/ssh" ) func signerFromPem(pemBytes []byte, password []byte) (ssh.Signer, error) { // read pem block err := errors.New("Pem decode failed, no key found") pemBlock, _ := pem.Decode(pemBytes) if pemBlock == nil { return nil, err } // handle encrypted key if x509.IsEncryptedPEMBlock(pemBlock) { // decrypt PEM pemBlock.Bytes, err = x509.DecryptPEMBlock(pemBlock, password) if err != nil { return nil, fmt.Errorf("Decrypting PEM block failed %v", err) } // get RSA, EC or DSA key key, err := parsePemBlock(pemBlock) if err != nil { return nil, err } // generate signer instance from key signer, err := ssh.NewSignerFromKey(key) if err != nil { return nil, fmt.Errorf("Creating signer from encrypted key failed %v", err) } return signer, nil } else { // generate signer instance from plain key signer, err := ssh.ParsePrivateKey(pemBytes) if err != nil { return nil, fmt.Errorf("Parsing plain private key failed %v", err) } return signer, nil } } func parsePemBlock(block *pem.Block) (interface{}, error) { switch block.Type { case "RSA PRIVATE KEY": key, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("Parsing PKCS private key failed %v", err) } else { return key, nil } case "EC PRIVATE KEY": key, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("Parsing EC private key failed %v", err) } else { return key, nil } case "DSA PRIVATE KEY": key, err := ssh.ParseDSAPrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("Parsing DSA private key failed %v", err) } else { return key, nil } default: return nil, fmt.Errorf("Parsing private key failed, unsupported key type %q", block.Type) } }