Skip to content
ecdsa.com
golang.org/x/crypto/ssh (Go)Go

Error message

ssh: this private key is passphrase protected

Also printed as

  • ssh: no key found

"ssh: no key found" (listed as an alias) is a different condition from the same parser: the bytes contain no PEM key block — for example a public key, a PuTTY `.ppk` file or an empty file.

golang.org/x/crypto/ssh (Go) — *ssh.PassphraseMissingError from ssh.ParsePrivateKey

What it means

`ssh.ParsePrivateKey` recognised an encrypted private key and stopped, because it has no passphrase to decrypt it with. The returned `*ssh.PassphraseMissingError` even carries the public key, but signing needs the decrypted private key: call `ssh.ParsePrivateKeyWithPassphrase` or let an SSH agent do the signing. Its sibling "ssh: no key found" means the input contains no recognisable key at all.

Why it happens

How to fix it

  1. 1.

    Detect the error and supply the passphrase

    `errors.As` identifies the missing passphrase; read it from a secret store, never from source code.

    go
    signer, err := ssh.ParsePrivateKey(keyBytes)
    var missing *ssh.PassphraseMissingError
    if errors.As(err, &missing) {
    	passphrase := []byte(os.Getenv("SSH_KEY_PASSPHRASE"))
    	signer, err = ssh.ParsePrivateKeyWithPassphrase(keyBytes, passphrase)
    }
    if err != nil {
    	return err
    }
  2. 2.

    Sign through the SSH agent

    With `golang.org/x/crypto/ssh/agent`, the private key never enters your process and the passphrase is handled by the agent.

    go
    import "golang.org/x/crypto/ssh/agent"
    
    conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
    if err != nil {
    	return err
    }
    agentClient := agent.NewClient(conn)
    auth := ssh.PublicKeysCallback(agentClient.Signers) // the agent holds the decrypted key

Related errors

Browse the full signature error database