Copyright 2012 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 (
	
	
	
	
	
	
	
	
	
	

	
	
)
Server wraps an Agent and uses it to implement the agent side of the SSH-agent, wire protocol.
type server struct {
	agent Agent
}

func ( *server) ( []byte) []byte {
	,  := .processRequest()
	if  != nil {
TODO(hanwen): provide better logging interface?
			log.Printf("agent %d: %v", [0], )
		}
		return []byte{agentFailure}
	}

	if  == nil &&  == nil {
		return []byte{agentSuccess}
	}

	return ssh.Marshal()
}

func ( *Key) []byte {
	var  struct {
		    []byte
		 string
	}
	. = .Marshal()
	. = .Comment

	return ssh.Marshal(&)
}
See [PROTOCOL.agent], section 2.5.1.
const agentV1IdentitiesAnswer = 2

type agentV1IdentityMsg struct {
	Numkeys uint32 `sshtype:"2"`
}

type agentRemoveIdentityMsg struct {
	KeyBlob []byte `sshtype:"18"`
}

type agentLockMsg struct {
	Passphrase []byte `sshtype:"22"`
}

type agentUnlockMsg struct {
	Passphrase []byte `sshtype:"23"`
}

func ( *server) ( []byte) (interface{}, error) {
	switch [0] {
	case agentRequestV1Identities:
		return &agentV1IdentityMsg{0}, nil

	case agentRemoveAllV1Identities:
		return nil, nil

	case agentRemoveIdentity:
		var  agentRemoveIdentityMsg
		if  := ssh.Unmarshal(, &);  != nil {
			return nil, 
		}

		var  wireKey
		if  := ssh.Unmarshal(.KeyBlob, &);  != nil {
			return nil, 
		}

		return nil, .agent.Remove(&Key{Format: .Format, Blob: .KeyBlob})

	case agentRemoveAllIdentities:
		return nil, .agent.RemoveAll()

	case agentLock:
		var  agentLockMsg
		if  := ssh.Unmarshal(, &);  != nil {
			return nil, 
		}

		return nil, .agent.Lock(.Passphrase)

	case agentUnlock:
		var  agentUnlockMsg
		if  := ssh.Unmarshal(, &);  != nil {
			return nil, 
		}
		return nil, .agent.Unlock(.Passphrase)

	case agentSignRequest:
		var  signRequestAgentMsg
		if  := ssh.Unmarshal(, &);  != nil {
			return nil, 
		}

		var  wireKey
		if  := ssh.Unmarshal(.KeyBlob, &);  != nil {
			return nil, 
		}

		 := &Key{
			Format: .Format,
			Blob:   .KeyBlob,
		}

		var  *ssh.Signature
		var  error
		if ,  := .agent.(ExtendedAgent);  {
			,  = .SignWithFlags(, .Data, SignatureFlags(.Flags))
		} else {
			,  = .agent.Sign(, .Data)
		}

		if  != nil {
			return nil, 
		}
		return &signResponseAgentMsg{SigBlob: ssh.Marshal()}, nil

	case agentRequestIdentities:
		,  := .agent.List()
		if  != nil {
			return nil, 
		}

		 := identitiesAnswerAgentMsg{
			NumKeys: uint32(len()),
		}
		for ,  := range  {
			.Keys = append(.Keys, marshalKey()...)
		}
		return , nil

	case agentAddIDConstrained, agentAddIdentity:
		return nil, .insertIdentity()

Return a stub object where the whole contents of the response gets marshaled.
		var  struct {
			 []byte `ssh:"rest"`
		}

If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 requires that we return a standard SSH_AGENT_FAILURE message.
			. = []byte{agentFailure}
		} else {
			var  extensionAgentMsg
			if  := ssh.Unmarshal(, &);  != nil {
				return nil, 
			}
			,  := .Extension(.ExtensionType, .Contents)
If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE message as required by [PROTOCOL.agent] section 4.7.
				if  == ErrExtensionUnsupported {
					. = []byte{agentFailure}
As the result of any other error processing an extension request, [PROTOCOL.agent] section 4.7 requires that we return a SSH_AGENT_EXTENSION_FAILURE code.
					. = []byte{agentExtensionFailure}
				}
			} else {
				if len() == 0 {
					return nil, nil
				}
				. = 
			}
		}

		return , nil
	}

	return nil, fmt.Errorf("unknown opcode %d", [0])
}

func ( []byte) ( uint32,  bool,  []ConstraintExtension,  error) {
	for len() != 0 {
		switch [0] {
		case agentConstrainLifetime:
			 = binary.BigEndian.Uint32([1:5])
			 = [5:]
		case agentConstrainConfirm:
			 = true
			 = [1:]
		case agentConstrainExtension:
			var  constrainExtensionAgentMsg
			if  = ssh.Unmarshal(, &);  != nil {
				return 0, false, nil, 
			}
			 = append(, ConstraintExtension{
				ExtensionName:    .ExtensionName,
				ExtensionDetails: .ExtensionDetails,
			})
			 = .Rest
		default:
			return 0, false, nil, fmt.Errorf("unknown constraint type: %d", [0])
		}
	}
	return
}

func ( *AddedKey,  []byte) error {
	, , ,  := parseConstraints()
	if  != nil {
		return 
	}

	.LifetimeSecs = 
	.ConfirmBeforeUse = 
	.ConstraintExtensions = 
	return nil
}

func ( []byte) (*AddedKey, error) {
	var  rsaKeyMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}
	if .E.BitLen() > 30 {
		return nil, errors.New("agent: RSA public exponent too large")
	}
	 := &rsa.PrivateKey{
		PublicKey: rsa.PublicKey{
			E: int(.E.Int64()),
			N: .N,
		},
		D:      .D,
		Primes: []*big.Int{.P, .Q},
	}
	.Precompute()

	 := &AddedKey{PrivateKey: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  ed25519KeyMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}
	 := ed25519.PrivateKey(.Priv)

	 := &AddedKey{PrivateKey: &, Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  dsaKeyMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}
	 := &dsa.PrivateKey{
		PublicKey: dsa.PublicKey{
			Parameters: dsa.Parameters{
				P: .P,
				Q: .Q,
				G: .G,
			},
			Y: .Y,
		},
		X: .X,
	}

	 := &AddedKey{PrivateKey: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( string,  []byte,  *big.Int) ( *ecdsa.PrivateKey,  error) {
	 = &ecdsa.PrivateKey{
		D: ,
	}

	switch  {
	case "nistp256":
		.Curve = elliptic.P256()
	case "nistp384":
		.Curve = elliptic.P384()
	case "nistp521":
		.Curve = elliptic.P521()
	default:
		return nil, fmt.Errorf("agent: unknown curve %q", )
	}

	.X, .Y = elliptic.Unmarshal(.Curve, )
	if .X == nil || .Y == nil {
		return nil, errors.New("agent: point not on curve")
	}

	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  ed25519CertMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}
	,  := ssh.ParsePublicKey(.CertBytes)
	if  != nil {
		return nil, 
	}
	 := ed25519.PrivateKey(.Priv)
	,  := .(*ssh.Certificate)
	if ! {
		return nil, errors.New("agent: bad ED25519 certificate")
	}

	 := &AddedKey{PrivateKey: &, Certificate: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  ecdsaKeyMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}

	,  := unmarshalECDSA(.Curve, .KeyBytes, .D)
	if  != nil {
		return nil, 
	}

	 := &AddedKey{PrivateKey: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  rsaCertMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}

	,  := ssh.ParsePublicKey(.CertBytes)
	if  != nil {
		return nil, 
	}

	,  := .(*ssh.Certificate)
	if ! {
		return nil, errors.New("agent: bad RSA certificate")
	}
An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
	var  struct {
		 string
		    *big.Int
		    *big.Int
	}
	if  := ssh.Unmarshal(.Key.Marshal(), &);  != nil {
		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", )
	}

	if ..BitLen() > 30 {
		return nil, errors.New("agent: RSA public exponent too large")
	}

	 := rsa.PrivateKey{
		PublicKey: rsa.PublicKey{
			E: int(..Int64()),
			N: .,
		},
		D:      .D,
		Primes: []*big.Int{.Q, .P},
	}
	.Precompute()

	 := &AddedKey{PrivateKey: &, Certificate: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  dsaCertMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}
	,  := ssh.ParsePublicKey(.CertBytes)
	if  != nil {
		return nil, 
	}
	,  := .(*ssh.Certificate)
	if ! {
		return nil, errors.New("agent: bad DSA certificate")
	}
A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
	var  struct {
		       string
		, , ,  *big.Int
	}
	if  := ssh.Unmarshal(.Key.Marshal(), &);  != nil {
		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", )
	}

	 := &dsa.PrivateKey{
		PublicKey: dsa.PublicKey{
			Parameters: dsa.Parameters{
				P: .,
				Q: .,
				G: .,
			},
			Y: .,
		},
		X: .X,
	}

	 := &AddedKey{PrivateKey: , Certificate: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( []byte) (*AddedKey, error) {
	var  ecdsaCertMsg
	if  := ssh.Unmarshal(, &);  != nil {
		return nil, 
	}

	,  := ssh.ParsePublicKey(.CertBytes)
	if  != nil {
		return nil, 
	}
	,  := .(*ssh.Certificate)
	if ! {
		return nil, errors.New("agent: bad ECDSA certificate")
	}
An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
	var  struct {
		 string
		   string
		  []byte
	}
	if  := ssh.Unmarshal(.Key.Marshal(), &);  != nil {
		return nil, 
	}

	,  := unmarshalECDSA(., ., .D)
	if  != nil {
		return nil, 
	}

	 := &AddedKey{PrivateKey: , Certificate: , Comment: .Comments}
	if  := setConstraints(, .Constraints);  != nil {
		return nil, 
	}
	return , nil
}

func ( *server) ( []byte) error {
	var  struct {
		 string `sshtype:"17|25"`
		 []byte `ssh:"rest"`
	}

	if  := ssh.Unmarshal(, &);  != nil {
		return 
	}

	var  *AddedKey
	var  error

	switch . {
	case ssh.KeyAlgoRSA:
		,  = parseRSAKey()
	case ssh.KeyAlgoDSA:
		,  = parseDSAKey()
	case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
		,  = parseECDSAKey()
	case ssh.KeyAlgoED25519:
		,  = parseEd25519Key()
	case ssh.CertAlgoRSAv01:
		,  = parseRSACert()
	case ssh.CertAlgoDSAv01:
		,  = parseDSACert()
	case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
		,  = parseECDSACert()
	case ssh.CertAlgoED25519v01:
		,  = parseEd25519Cert()
	default:
		return fmt.Errorf("agent: not implemented: %q", .)
	}

	if  != nil {
		return 
	}
	return .agent.Add(*)
}
ServeAgent serves the agent protocol on the given connection. It returns when an I/O error occurs.
func ( Agent,  io.ReadWriter) error {
	 := &server{}

	var  [4]byte
	for {
		if ,  := io.ReadFull(, [:]);  != nil {
			return 
		}
		 := binary.BigEndian.Uint32([:])
		if  == 0 {
			return fmt.Errorf("agent: request size is 0")
		}
We also cap requests.
			return fmt.Errorf("agent: request too large: %d", )
		}

		 := make([]byte, )
		if ,  := io.ReadFull(, );  != nil {
			return 
		}

		 := .processRequestBytes()
		if len() > maxAgentResponseBytes {
			return fmt.Errorf("agent: reply too large: %d bytes", len())
		}

		binary.BigEndian.PutUint32([:], uint32(len()))
		if ,  := .Write([:]);  != nil {
			return 
		}
		if ,  := .Write();  != nil {
			return 
		}
	}