// updateSSHAgent takes the list of certificates and path to the private key (corresponding to the signed public key). Adds the cert if it's not present in the agent. func updateSSHAgent(certsWithKeyList []*api.CertificateAndPrivateKey, privateKeyPath string) error { conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { return err } defer conn.Close() sshAgent := agent.NewClient(conn) certsInSSHAgent, err := sshAgent.List() if err != nil { return err } privateKeyBytes, err := ioutil.ReadFile(privateKeyPath) if err != nil { return err } privateKeyInterface, err := ssh.ParseRawPrivateKey(privateKeyBytes) if err != nil { return err } // TODO optimize this. currently O(N^2) for _, certAndKey := range certsWithKeyList { cert, err := util.ParseSSHCert([]byte(certAndKey.Cert)) for _, key := range certsInSSHAgent { certBlob := key.Blob if err != nil { return err } if bytes.Equal(certBlob, cert.Marshal()) { break } } err = sshAgent.Add(privateKeyInterface, cert, "certificate added by shortbread") if err != nil { return err } } 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)) } }