github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/server.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package agent
     6  
     7  import (
     8  	"crypto/rsa"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"math/big"
    14  
    15  	"golang.org/x/crypto/ssh"
    16  )
    17  
    18  // Server wraps an Agent and uses it to implement the agent side of
    19  // the SSH-agent, wire protocol.
    20  type server struct {
    21  	agent Agent
    22  }
    23  
    24  func (s *server) processRequestBytes(reqData []byte) []byte {
    25  	rep, err := s.processRequest(reqData)
    26  	if err != nil {
    27  		if err != errLocked {
    28  			// TODO(hanwen): provide better logging interface?
    29  			log.Printf("agent %d: %v", reqData[0], err)
    30  		}
    31  		return []byte{agentFailure}
    32  	}
    33  
    34  	if err == nil && rep == nil {
    35  		return []byte{agentSuccess}
    36  	}
    37  
    38  	return ssh.Marshal(rep)
    39  }
    40  
    41  func marshalKey(k *Key) []byte {
    42  	var record struct {
    43  		Blob    []byte
    44  		Comment string
    45  	}
    46  	record.Blob = k.Marshal()
    47  	record.Comment = k.Comment
    48  
    49  	return ssh.Marshal(&record)
    50  }
    51  
    52  type agentV1IdentityMsg struct {
    53  	Numkeys uint32 `sshtype:"2"`
    54  }
    55  
    56  type agentRemoveIdentityMsg struct {
    57  	KeyBlob []byte `sshtype:"18"`
    58  }
    59  
    60  type agentLockMsg struct {
    61  	Passphrase []byte `sshtype:"22"`
    62  }
    63  
    64  type agentUnlockMsg struct {
    65  	Passphrase []byte `sshtype:"23"`
    66  }
    67  
    68  func (s *server) processRequest(data []byte) (interface{}, error) {
    69  	switch data[0] {
    70  	case agentRequestV1Identities:
    71  		return &agentV1IdentityMsg{0}, nil
    72  	case agentRemoveIdentity:
    73  		var req agentRemoveIdentityMsg
    74  		if err := ssh.Unmarshal(data, &req); err != nil {
    75  			return nil, err
    76  		}
    77  
    78  		var wk wireKey
    79  		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
    80  			return nil, err
    81  		}
    82  
    83  		return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob})
    84  
    85  	case agentRemoveAllIdentities:
    86  		return nil, s.agent.RemoveAll()
    87  
    88  	case agentLock:
    89  		var req agentLockMsg
    90  		if err := ssh.Unmarshal(data, &req); err != nil {
    91  			return nil, err
    92  		}
    93  
    94  		return nil, s.agent.Lock(req.Passphrase)
    95  
    96  	case agentUnlock:
    97  		var req agentLockMsg
    98  		if err := ssh.Unmarshal(data, &req); err != nil {
    99  			return nil, err
   100  		}
   101  		return nil, s.agent.Unlock(req.Passphrase)
   102  
   103  	case agentSignRequest:
   104  		var req signRequestAgentMsg
   105  		if err := ssh.Unmarshal(data, &req); err != nil {
   106  			return nil, err
   107  		}
   108  
   109  		var wk wireKey
   110  		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
   111  			return nil, err
   112  		}
   113  
   114  		k := &Key{
   115  			Format: wk.Format,
   116  			Blob:   req.KeyBlob,
   117  		}
   118  
   119  		sig, err := s.agent.Sign(k, req.Data) //  TODO(hanwen): flags.
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  		return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil
   124  	case agentRequestIdentities:
   125  		keys, err := s.agent.List()
   126  		if err != nil {
   127  			return nil, err
   128  		}
   129  
   130  		rep := identitiesAnswerAgentMsg{
   131  			NumKeys: uint32(len(keys)),
   132  		}
   133  		for _, k := range keys {
   134  			rep.Keys = append(rep.Keys, marshalKey(k)...)
   135  		}
   136  		return rep, nil
   137  	case agentAddIdentity:
   138  		return nil, s.insertIdentity(data)
   139  	}
   140  
   141  	return nil, fmt.Errorf("unknown opcode %d", data[0])
   142  }
   143  
   144  func (s *server) insertIdentity(req []byte) error {
   145  	var record struct {
   146  		Type string `sshtype:"17"`
   147  		Rest []byte `ssh:"rest"`
   148  	}
   149  	if err := ssh.Unmarshal(req, &record); err != nil {
   150  		return err
   151  	}
   152  
   153  	switch record.Type {
   154  	case ssh.KeyAlgoRSA:
   155  		var k rsaKeyMsg
   156  		if err := ssh.Unmarshal(req, &k); err != nil {
   157  			return err
   158  		}
   159  
   160  		priv := rsa.PrivateKey{
   161  			PublicKey: rsa.PublicKey{
   162  				E: int(k.E.Int64()),
   163  				N: k.N,
   164  			},
   165  			D:      k.D,
   166  			Primes: []*big.Int{k.P, k.Q},
   167  		}
   168  		priv.Precompute()
   169  
   170  		return s.agent.Add(&priv, nil, k.Comments)
   171  	}
   172  	return fmt.Errorf("not implemented: %s", record.Type)
   173  }
   174  
   175  // ServeAgent serves the agent protocol on the given connection. It
   176  // returns when an I/O error occurs.
   177  func ServeAgent(agent Agent, c io.ReadWriter) error {
   178  	s := &server{agent}
   179  
   180  	var length [4]byte
   181  	for {
   182  		if _, err := io.ReadFull(c, length[:]); err != nil {
   183  			return err
   184  		}
   185  		l := binary.BigEndian.Uint32(length[:])
   186  		if l > maxAgentResponseBytes {
   187  			// We also cap requests.
   188  			return fmt.Errorf("agent: request too large: %d", l)
   189  		}
   190  
   191  		req := make([]byte, l)
   192  		if _, err := io.ReadFull(c, req); err != nil {
   193  			return err
   194  		}
   195  
   196  		repData := s.processRequestBytes(req)
   197  		if len(repData) > maxAgentResponseBytes {
   198  			return fmt.Errorf("agent: reply too large: %d bytes", len(repData))
   199  		}
   200  
   201  		binary.BigEndian.PutUint32(length[:], uint32(len(repData)))
   202  		if _, err := c.Write(length[:]); err != nil {
   203  			return err
   204  		}
   205  		if _, err := c.Write(repData); err != nil {
   206  			return err
   207  		}
   208  	}
   209  }