Copyright 2014 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package agent

import (
	
	
	
	
	
	
	

	
)

type privKey struct {
	signer  ssh.Signer
	comment string
	expire  *time.Time
}

type keyring struct {
	mu   sync.Mutex
	keys []privKey

	locked     bool
	passphrase []byte
}

var errLocked = errors.New("agent: locked")
NewKeyring returns an Agent that holds keys in memory. It is safe for concurrent use by multiple goroutines.
func () Agent {
	return &keyring{}
}
RemoveAll removes all identities.
func ( *keyring) () error {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return errLocked
	}

	.keys = nil
	return nil
}
removeLocked does the actual key removal. The caller must already be holding the keyring mutex.
func ( *keyring) ( []byte) error {
	 := false
	for  := 0;  < len(.keys); {
		if bytes.Equal(.keys[].signer.PublicKey().Marshal(), ) {
			 = true
			.keys[] = .keys[len(.keys)-1]
			.keys = .keys[:len(.keys)-1]
			continue
		} else {
			++
		}
	}

	if ! {
		return errors.New("agent: key not found")
	}
	return nil
}
Remove removes all identities with the given public key.
func ( *keyring) ( ssh.PublicKey) error {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return errLocked
	}

	return .removeLocked(.Marshal())
}
Lock locks the agent. Sign and Remove will fail, and List will return an empty list.
func ( *keyring) ( []byte) error {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return errLocked
	}

	.locked = true
	.passphrase = 
	return nil
}
Unlock undoes the effect of Lock
func ( *keyring) ( []byte) error {
	.mu.Lock()
	defer .mu.Unlock()
	if !.locked {
		return errors.New("agent: not locked")
	}
	if 1 != subtle.ConstantTimeCompare(, .passphrase) {
		return fmt.Errorf("agent: incorrect passphrase")
	}

	.locked = false
	.passphrase = nil
	return nil
}
expireKeysLocked removes expired keys from the keyring. If a key was added with a lifetimesecs contraint and seconds >= lifetimesecs seconds have ellapsed, it is removed. The caller *must* be holding the keyring mutex.
func ( *keyring) () {
	for ,  := range .keys {
		if .expire != nil && time.Now().After(*.expire) {
			.removeLocked(.signer.PublicKey().Marshal())
		}
	}
}
List returns the identities known to the agent.
func ( *keyring) () ([]*Key, error) {
	.mu.Lock()
	defer .mu.Unlock()
section 2.7: locked agents return empty.
		return nil, nil
	}

	.expireKeysLocked()
	var  []*Key
	for ,  := range .keys {
		 := .signer.PublicKey()
		 = append(, &Key{
			Format:  .Type(),
			Blob:    .Marshal(),
			Comment: .comment})
	}
	return , nil
}
Insert adds a private key to the keyring. If a certificate is given, that certificate is added as public key. Note that any constraints given are ignored.
func ( *keyring) ( AddedKey) error {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return errLocked
	}
	,  := ssh.NewSignerFromKey(.PrivateKey)

	if  != nil {
		return 
	}

	if  := .Certificate;  != nil {
		,  = ssh.NewCertSigner(, )
		if  != nil {
			return 
		}
	}

	 := privKey{
		signer:  ,
		comment: .Comment,
	}

	if .LifetimeSecs > 0 {
		 := time.Now().Add(time.Duration(.LifetimeSecs) * time.Second)
		.expire = &
	}

	.keys = append(.keys, )

	return nil
}
Sign returns a signature for the data.
func ( *keyring) ( ssh.PublicKey,  []byte) (*ssh.Signature, error) {
	return .SignWithFlags(, , 0)
}

func ( *keyring) ( ssh.PublicKey,  []byte,  SignatureFlags) (*ssh.Signature, error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return nil, errLocked
	}

	.expireKeysLocked()
	 := .Marshal()
	for ,  := range .keys {
		if bytes.Equal(.signer.PublicKey().Marshal(), ) {
			if  == 0 {
				return .signer.Sign(rand.Reader, )
			} else {
				if ,  := .signer.(ssh.AlgorithmSigner); ! {
					return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", .signer)
				} else {
					var  string
					switch  {
					case SignatureFlagRsaSha256:
						 = ssh.SigAlgoRSASHA2256
					case SignatureFlagRsaSha512:
						 = ssh.SigAlgoRSASHA2512
					default:
						return nil, fmt.Errorf("agent: unsupported signature flags: %d", )
					}
					return .SignWithAlgorithm(rand.Reader, , )
				}
			}
		}
	}
	return nil, errors.New("not found")
}
Signers returns signers for all the known keys.
func ( *keyring) () ([]ssh.Signer, error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .locked {
		return nil, errLocked
	}

	.expireKeysLocked()
	 := make([]ssh.Signer, 0, len(.keys))
	for ,  := range .keys {
		 = append(, .signer)
	}
	return , nil
}
The keyring does not support any extensions
func ( *keyring) ( string,  []byte) ([]byte, error) {
	return nil, ErrExtensionUnsupported