func (c *BaseCluster) sshConfig() (*ssh.ClientConfig, error) { signer, err := ssh.NewSignerFromKey(c.SSHKey.PrivateKey) if err != nil { return nil, err } sshConfig := &ssh.ClientConfig{ User: c.SSHUsername, Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)}, } return sshConfig, nil }
func testLockAgent(agent Agent, t *testing.T) { if err := agent.Add(testPrivateKeys["rsa"], nil, "comment 1"); err != nil { t.Errorf("Add: %v", err) } if err := agent.Add(testPrivateKeys["dsa"], nil, "comment dsa"); err != nil { t.Errorf("Add: %v", err) } if keys, err := agent.List(); err != nil { t.Errorf("List: %v", err) } else if len(keys) != 2 { t.Errorf("Want 2 keys, got %v", keys) } passphrase := []byte("secret") if err := agent.Lock(passphrase); err != nil { t.Errorf("Lock: %v", err) } if keys, err := agent.List(); err != nil { t.Errorf("List: %v", err) } else if len(keys) != 0 { t.Errorf("Want 0 keys, got %v", keys) } signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"]) if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil { t.Fatalf("Sign did not fail") } if err := agent.Remove(signer.PublicKey()); err == nil { t.Fatalf("Remove did not fail") } if err := agent.RemoveAll(); err == nil { t.Fatalf("RemoveAll did not fail") } if err := agent.Unlock(nil); err == nil { t.Errorf("Unlock with wrong passphrase succeeded") } if err := agent.Unlock(passphrase); err != nil { t.Errorf("Unlock: %v", err) } if err := agent.Remove(signer.PublicKey()); err != nil { t.Fatalf("Remove: %v", err) } if keys, err := agent.List(); err != nil { t.Errorf("List: %v", err) } else if len(keys) != 1 { t.Errorf("Want 1 keys, got %v", keys) } }
func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string) error { var req []byte switch k := s.(type) { case *rsa.PrivateKey: if len(k.Primes) != 2 { return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) } k.Precompute() req = ssh.Marshal(rsaCertMsg{ Type: cert.Type(), CertBytes: cert.Marshal(), D: k.D, Iqmp: k.Precomputed.Qinv, P: k.Primes[0], Q: k.Primes[1], Comments: comment, }) case *dsa.PrivateKey: req = ssh.Marshal(dsaCertMsg{ Type: cert.Type(), CertBytes: cert.Marshal(), X: k.X, Comments: comment, }) case *ecdsa.PrivateKey: req = ssh.Marshal(ecdsaCertMsg{ Type: cert.Type(), CertBytes: cert.Marshal(), D: k.D, Comments: comment, }) default: return fmt.Errorf("agent: unsupported key type %T", s) } signer, err := ssh.NewSignerFromKey(s) if err != nil { return err } if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { return errors.New("agent: signer and cert have different public key") } resp, err := c.call(req) if err != nil { return err } if _, ok := resp.(*successAgentMsg); ok { return nil } return errors.New("agent: failure") }
func (p privateKeySigner) Decrypt() (ssh.Signer, error) { if p.key == nil { pem, err := x509.DecryptPEMBlock(p.pem, []byte(p.Passphrase())) if err != nil { return nil, err } p.key, err = x509.ParsePKCS1PrivateKey(pem) if err != nil { return nil, err } p.Encrypted = false } return ssh.NewSignerFromKey(p.key) }
func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate) { signer, err := ssh.NewSignerFromKey(key) if err != nil { t.Fatalf("NewSignerFromKey(%T): %v", key, err) } // The agent should start up empty. if keys, err := agent.List(); err != nil { t.Fatalf("RequestIdentities: %v", err) } else if len(keys) > 0 { t.Fatalf("got %d keys, want 0: %v", len(keys), keys) } // Attempt to insert the key, with certificate if specified. var pubKey ssh.PublicKey if cert != nil { err = agent.Add(key, cert, "comment") pubKey = cert } else { err = agent.Add(key, nil, "comment") pubKey = signer.PublicKey() } if err != nil { t.Fatalf("insert(%T): %v", key, err) } // Did the key get inserted successfully? if keys, err := agent.List(); err != nil { t.Fatalf("List: %v", err) } else if len(keys) != 1 { t.Fatalf("got %v, want 1 key", keys) } else if keys[0].Comment != "comment" { t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment") } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) { t.Fatalf("key mismatch") } // Can the agent make a valid signature? data := []byte("hello") sig, err := agent.Sign(pubKey, data) if err != nil { t.Fatalf("Sign(%s): %v", pubKey.Type(), err) } if err := pubKey.Verify(data, sig); err != nil { t.Fatalf("Verify(%s): %v", pubKey.Type(), err) } }
func (c *SSHCluster) importSSHKeyPair(t *TargetServer) error { var buf bytes.Buffer _, file, readFileErrChan := c.base.PromptFileInput(fmt.Sprintf("Please provide your private key for %s@%s", t.User, t.IP)) if _, err := io.Copy(&buf, file); err != nil { readFileErrChan <- err return err } readFileErrChan <- nil // no error reading file b, _ := pem.Decode(buf.Bytes()) if b == nil { return fmt.Errorf("Invalid private key") } var pemBytes []byte if x509.IsEncryptedPEMBlock(b) { passphrase := c.base.PromptProtectedInput("Please enter the passphrase for the key") var err error pemBytes, err = x509.DecryptPEMBlock(b, []byte(passphrase)) if err != nil { return err } } else { pemBytes = b.Bytes } privateKey, err := x509.ParsePKCS1PrivateKey(pemBytes) if err != nil { return err } signer, err := ssh.NewSignerFromKey(privateKey) if err != nil { return err } auth := []ssh.AuthMethod{ssh.PublicKeys(signer)} sshConfig := c.sshConfigForAuth(t, auth) c.base.SendLog(fmt.Sprintf("Testing provided key for %s@%s", t.User, t.IP)) if !c.testAndAddAuthentication(t, sshConfig) { return fmt.Errorf("Provided key for %s@%s failed to authenticate", t.User, t.IP) } c.base.SendLog(fmt.Sprintf("Key verified for %s@%s", t.User, t.IP)) return nil }
func init() { var err error n := len(testdata.PEMBytes) testPrivateKeys = make(map[string]interface{}, n) testSigners = make(map[string]ssh.Signer, n) testPublicKeys = make(map[string]ssh.PublicKey, n) for t, k := range testdata.PEMBytes { testPrivateKeys[t], err = ssh.ParseRawPrivateKey(k) if err != nil { panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) } testSigners[t], err = ssh.NewSignerFromKey(testPrivateKeys[t]) if err != nil { panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) } testPublicKeys[t] = testSigners[t].PublicKey() } // Create a cert and sign it for use in tests. testCert := &ssh.Certificate{ Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage ValidAfter: 0, // unix epoch ValidBefore: ssh.CertTimeInfinity, // The end of currently representable time. Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil Key: testPublicKeys["ecdsa"], SignatureKey: testPublicKeys["rsa"], Permissions: ssh.Permissions{ CriticalOptions: map[string]string{}, Extensions: map[string]string{}, }, } testCert.SignCert(rand.Reader, testSigners["rsa"]) testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] testSigners["cert"], err = ssh.NewCertSigner(testCert, testSigners["ecdsa"]) if err != nil { panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) } }
func addKey(conf *ssh.ServerConfig, block *pem.Block) (err error) { var key interface{} switch block.Type { case "RSA PRIVATE KEY": key, err = x509.ParsePKCS1PrivateKey(block.Bytes) case "EC PRIVATE KEY": key, err = x509.ParseECPrivateKey(block.Bytes) case "DSA PRIVATE KEY": key, err = ssh.ParseDSAPrivateKey(block.Bytes) default: return fmt.Errorf("unsupported key type %q", block.Type) } if err != nil { return err } signer, err := ssh.NewSignerFromKey(key) if err != nil { return err } conf.AddHostKey(signer) return nil }
// Insert adds a private key to the keyring. If a certificate // is given, that certificate is added as public key. func (r *keyring) Add(priv interface{}, cert *ssh.Certificate, comment string) error { r.mu.Lock() defer r.mu.Unlock() if r.locked { return errLocked } signer, err := ssh.NewSignerFromKey(priv) if err != nil { return err } if cert != nil { signer, err = ssh.NewCertSigner(cert, signer) if err != nil { return err } } r.keys = append(r.keys, privKey{signer, comment}) return nil }
func (c *SSHCluster) findSSHAuth() error { c.base.SendLog("Detecting authentication") testAndAddAuthMethod := func(t *TargetServer, a ssh.AuthMethod) bool { sshConfig := c.sshConfigForAuth(t, []ssh.AuthMethod{a}) if c.testAndAddAuthentication(t, sshConfig) { c.base.SendLog(fmt.Sprintf("Verified authentication for %s@%s", t.User, t.IP)) return true } return false } testAndAddSigner := func(t *TargetServer, s ssh.Signer) bool { return testAndAddAuthMethod(t, ssh.PublicKeys(s)) } testAllAuthenticated := func(targets []*TargetServer) bool { for _, t := range targets { if t.SSHConfig == nil { return false } } return true } sshAgent := c.sshAgent() sshAgentAuth := ssh.PublicKeysCallback(sshAgent.Signers) for _, t := range c.Targets { testAndAddAuthMethod(t, sshAgentAuth) } if testAllAuthenticated(c.Targets) { return nil } var agentKeys [][]byte if keys, err := sshAgent.List(); err == nil { agentKeys = make([][]byte, len(keys)) for i, k := range keys { agentKeys[i] = k.Marshal() } } var signers []privateKeySigner signerloop: for _, s := range c.findSSHKeySigners() { if s.publicKey != nil { for _, k := range agentKeys { if bytes.Equal(k, s.publicKey.Marshal()) { continue signerloop } } } signers = append(signers, s) } outer: for _, t := range c.Targets { if t.SSHConfig != nil { continue } for _, s := range signers { if s.Encrypted { if s.publicKey == nil { signer, err := s.Decrypt() if err != nil { continue } if testAndAddSigner(t, signer) { continue outer } } else { if testAndAddSigner(t, s) { continue outer } } } else { signer, err := ssh.NewSignerFromKey(s.key) if err != nil { continue } if testAndAddSigner(t, signer) { continue outer } } } } for _, t := range c.Targets { if t.SSHConfig != nil { continue } answer, err := c.base.ChoicePrompt(Choice{ Message: "No working authentication found.\nPlease choose one of the following options:", Options: []ChoiceOption{ { Type: 1, Name: "Private key", Value: "1", }, { Name: "Password", Value: "2", }, { Name: "Abort", Value: "3", }, }, }) if err != nil { return err } switch answer { case "1": if err := c.importSSHKeyPair(t); err != nil { return err } else { continue } case "2": password := c.base.PromptProtectedInput(fmt.Sprintf("Please enter your password for %s@%s", t.User, t.IP)) if testAndAddAuthMethod(t, ssh.Password(password)) { continue } } return fmt.Errorf("No working authentication found") } return nil }