// Remove removes all identities with the given public key. func (r *keyring) Remove(key ssh.PublicKey) error { r.mu.Lock() defer r.mu.Unlock() if r.locked { return errLocked } want := key.Marshal() found := false for i := 0; i < len(r.keys); { if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { found = true r.keys[i] = r.keys[len(r.keys)-1] r.keys = r.keys[len(r.keys)-1:] continue } else { i++ } } if !found { return errors.New("agent: key not found") } return nil }
// Generates a MD5 based fingerprint of a SSH key. func pubKeyFingerprint(key ssh.PublicKey) (string, error) { h := md5.New() _, err := h.Write(key.Marshal()) if err != nil { return "", err } fp := fmt.Sprintf("%x", h.Sum(nil)) return fp, nil }
// Sign returns a signature for the data. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { r.mu.Lock() defer r.mu.Unlock() if r.locked { return nil, errLocked } wanted := key.Marshal() for _, k := range r.keys { if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { return k.signer.Sign(rand.Reader, data) } } return nil, errors.New("not found") }
// Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, }) msg, err := c.call(req) if err != nil { return nil, err } switch msg := msg.(type) { case *signResponseAgentMsg: var sig ssh.Signature if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { return nil, err } return &sig, nil case *failureAgentMsg: return nil, errors.New("agent: failed to sign challenge") } panic("unreachable") }
func (c *client) Remove(key ssh.PublicKey) error { req := ssh.Marshal(&agentRemoveIdentityMsg{ KeyBlob: key.Marshal(), }) return c.simpleCall(req) }
// Callback function responsible for authenticating the SSH client. func keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { log.Printf("(keyAuth) >> New client conn from '%s' authenticating with '%s'\n", conn.RemoteAddr(), key.Type()) // Create a fingerprint of the external provided pub key. fpProvidedPubKey, err := pubKeyFingerprint(key) if err != nil { log.Printf("(keyAuth) >> Error: Unable to create fingerprint for provided PubKey: %s\n", err.Error()) } log.Printf("(keyAuth) >> Fingerprint of provided PubKey : %s\n", fpProvidedPubKey) // Get all the pub keys for a given user. authorizedPubKeys, err := getPubKeysForUser(conn.User()) if err != nil { return nil, fmt.Errorf("(keyAuth) >> No pub key for user '%s' found / user not allowed to connect.", conn.User()) } // Check if the user is allowed to connect at all (meaning: the must be a subdirectory in the 'data' dir // matching the provided SSH username). var authSuccess bool = false for i, authPubKey := range authorizedPubKeys { fpAuthorizedPubKey, err := pubKeyFingerprint(authPubKey) if err != nil { log.Printf("(keyAuth) >> Error: Unable to create fingerprint for authorized PubKey %d: %s\n", i, err.Error()) } log.Printf("(keyAuth) >> Fingerprint of authorized PubKey %d: %s\n", i, fpAuthorizedPubKey) // Check if username and Public Key combination is allowed to establish a connection. if theseTwoPublicKeysAreEqual(key, authPubKey) { authSuccess = true break } } if authSuccess { log.Printf("(keyAuth) >> Correct username '%s' and public key provided.", conn.User()) // Signaling success / authentication passed. return nil, nil } log.Printf("(keyAuth) >> Wrong username '%s' and/or public key provided.", conn.User()) return nil, fmt.Errorf("Wrong username and/or public key.") }