github.com/glycerine/xcryptossh@v7.0.4+incompatible/agent/client.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 implements the ssh-agent protocol, and provides both
     6  // a client and a server. The client can talk to a standard ssh-agent
     7  // that uses UNIX sockets, and one could implement an alternative
     8  // ssh-agent process using the sample server.
     9  //
    10  // References:
    11  //  [PROTOCOL.agent]:    http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
    12  package agent
    13  
    14  import (
    15  	"bytes"
    16  	"crypto/dsa"
    17  	"crypto/ecdsa"
    18  	"crypto/elliptic"
    19  	"crypto/rsa"
    20  	"encoding/base64"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"math/big"
    26  	"sync"
    27  
    28  	"github.com/glycerine/xcryptossh"
    29  	"golang.org/x/crypto/ed25519"
    30  )
    31  
    32  // Agent represents the capabilities of an ssh-agent.
    33  type Agent interface {
    34  	// List returns the identities known to the agent.
    35  	List() ([]*Key, error)
    36  
    37  	// Sign has the agent sign the data using a protocol 2 key as defined
    38  	// in [PROTOCOL.agent] section 2.6.2.
    39  	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
    40  
    41  	// Add adds a private key to the agent.
    42  	Add(key AddedKey) error
    43  
    44  	// Remove removes all identities with the given public key.
    45  	Remove(key ssh.PublicKey) error
    46  
    47  	// RemoveAll removes all identities.
    48  	RemoveAll() error
    49  
    50  	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
    51  	Lock(passphrase []byte) error
    52  
    53  	// Unlock undoes the effect of Lock
    54  	Unlock(passphrase []byte) error
    55  
    56  	// Signers returns signers for all the known keys.
    57  	Signers() ([]ssh.Signer, error)
    58  }
    59  
    60  // ConstraintExtension describes an optional constraint defined by users.
    61  type ConstraintExtension struct {
    62  	// ExtensionName consist of a UTF-8 string suffixed by the
    63  	// implementation domain following the naming scheme defined
    64  	// in Section 4.2 of [RFC4251], e.g.  "foo@example.com".
    65  	ExtensionName string
    66  	// ExtensionDetails contains the actual content of the extended
    67  	// constraint.
    68  	ExtensionDetails []byte
    69  }
    70  
    71  // AddedKey describes an SSH key to be added to an Agent.
    72  type AddedKey struct {
    73  	// PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or
    74  	// *ecdsa.PrivateKey, which will be inserted into the agent.
    75  	PrivateKey interface{}
    76  	// Certificate, if not nil, is communicated to the agent and will be
    77  	// stored with the key.
    78  	Certificate *ssh.Certificate
    79  	// Comment is an optional, free-form string.
    80  	Comment string
    81  	// LifetimeSecs, if not zero, is the number of seconds that the
    82  	// agent will store the key for.
    83  	LifetimeSecs uint32
    84  	// ConfirmBeforeUse, if true, requests that the agent confirm with the
    85  	// user before each use of this key.
    86  	ConfirmBeforeUse bool
    87  	// ConstraintExtensions are the experimental or private-use constraints
    88  	// defined by users.
    89  	ConstraintExtensions []ConstraintExtension
    90  }
    91  
    92  // See [PROTOCOL.agent], section 3.
    93  const (
    94  	agentRequestV1Identities   = 1
    95  	agentRemoveAllV1Identities = 9
    96  
    97  	// 3.2 Requests from client to agent for protocol 2 key operations
    98  	agentAddIdentity         = 17
    99  	agentRemoveIdentity      = 18
   100  	agentRemoveAllIdentities = 19
   101  	agentAddIdConstrained    = 25
   102  
   103  	// 3.3 Key-type independent requests from client to agent
   104  	agentAddSmartcardKey            = 20
   105  	agentRemoveSmartcardKey         = 21
   106  	agentLock                       = 22
   107  	agentUnlock                     = 23
   108  	agentAddSmartcardKeyConstrained = 26
   109  
   110  	// 3.7 Key constraint identifiers
   111  	agentConstrainLifetime  = 1
   112  	agentConstrainConfirm   = 2
   113  	agentConstrainExtension = 3
   114  )
   115  
   116  // maxAgentResponseBytes is the maximum agent reply size that is accepted. This
   117  // is a sanity check, not a limit in the spec.
   118  const maxAgentResponseBytes = 16 << 20
   119  
   120  // Agent messages:
   121  // These structures mirror the wire format of the corresponding ssh agent
   122  // messages found in [PROTOCOL.agent].
   123  
   124  // 3.4 Generic replies from agent to client
   125  const agentFailure = 5
   126  
   127  type failureAgentMsg struct{}
   128  
   129  const agentSuccess = 6
   130  
   131  type successAgentMsg struct{}
   132  
   133  // See [PROTOCOL.agent], section 2.5.2.
   134  const agentRequestIdentities = 11
   135  
   136  type requestIdentitiesAgentMsg struct{}
   137  
   138  // See [PROTOCOL.agent], section 2.5.2.
   139  const agentIdentitiesAnswer = 12
   140  
   141  type identitiesAnswerAgentMsg struct {
   142  	NumKeys uint32 `sshtype:"12"`
   143  	Keys    []byte `ssh:"rest"`
   144  }
   145  
   146  // See [PROTOCOL.agent], section 2.6.2.
   147  const agentSignRequest = 13
   148  
   149  type signRequestAgentMsg struct {
   150  	KeyBlob []byte `sshtype:"13"`
   151  	Data    []byte
   152  	Flags   uint32
   153  }
   154  
   155  // See [PROTOCOL.agent], section 2.6.2.
   156  
   157  // 3.6 Replies from agent to client for protocol 2 key operations
   158  const agentSignResponse = 14
   159  
   160  type signResponseAgentMsg struct {
   161  	SigBlob []byte `sshtype:"14"`
   162  }
   163  
   164  type publicKey struct {
   165  	Format string
   166  	Rest   []byte `ssh:"rest"`
   167  }
   168  
   169  // 3.7 Key constraint identifiers
   170  type constrainLifetimeAgentMsg struct {
   171  	LifetimeSecs uint32 `sshtype:"1"`
   172  }
   173  
   174  type constrainExtensionAgentMsg struct {
   175  	ExtensionName    string `sshtype:"3"`
   176  	ExtensionDetails []byte
   177  
   178  	// Rest is a field used for parsing, not part of message
   179  	Rest []byte `ssh:"rest"`
   180  }
   181  
   182  // Key represents a protocol 2 public key as defined in
   183  // [PROTOCOL.agent], section 2.5.2.
   184  type Key struct {
   185  	Format  string
   186  	Blob    []byte
   187  	Comment string
   188  }
   189  
   190  func clientErr(err error) error {
   191  	return fmt.Errorf("agent: client error: %v", err)
   192  }
   193  
   194  // String returns the storage form of an agent key with the format, base64
   195  // encoded serialized key, and the comment if it is not empty.
   196  func (k *Key) String() string {
   197  	s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
   198  
   199  	if k.Comment != "" {
   200  		s += " " + k.Comment
   201  	}
   202  
   203  	return s
   204  }
   205  
   206  // Type returns the public key type.
   207  func (k *Key) Type() string {
   208  	return k.Format
   209  }
   210  
   211  // Marshal returns key blob to satisfy the ssh.PublicKey interface.
   212  func (k *Key) Marshal() []byte {
   213  	return k.Blob
   214  }
   215  
   216  // Verify satisfies the ssh.PublicKey interface.
   217  func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
   218  	pubKey, err := ssh.ParsePublicKey(k.Blob)
   219  	if err != nil {
   220  		return fmt.Errorf("agent: bad public key: %v", err)
   221  	}
   222  	return pubKey.Verify(data, sig)
   223  }
   224  
   225  type wireKey struct {
   226  	Format string
   227  	Rest   []byte `ssh:"rest"`
   228  }
   229  
   230  func parseKey(in []byte) (out *Key, rest []byte, err error) {
   231  	var record struct {
   232  		Blob    []byte
   233  		Comment string
   234  		Rest    []byte `ssh:"rest"`
   235  	}
   236  
   237  	if err := ssh.Unmarshal(in, &record); err != nil {
   238  		return nil, nil, err
   239  	}
   240  
   241  	var wk wireKey
   242  	if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
   243  		return nil, nil, err
   244  	}
   245  
   246  	return &Key{
   247  		Format:  wk.Format,
   248  		Blob:    record.Blob,
   249  		Comment: record.Comment,
   250  	}, record.Rest, nil
   251  }
   252  
   253  // client is a client for an ssh-agent process.
   254  type client struct {
   255  	// conn is typically a *net.UnixConn
   256  	conn io.ReadWriter
   257  	// mu is used to prevent concurrent access to the agent
   258  	mu sync.Mutex
   259  }
   260  
   261  // NewClient returns an Agent that talks to an ssh-agent process over
   262  // the given connection.
   263  func NewClient(rw io.ReadWriter) Agent {
   264  	return &client{conn: rw}
   265  }
   266  
   267  // call sends an RPC to the agent. On success, the reply is
   268  // unmarshaled into reply and replyType is set to the first byte of
   269  // the reply, which contains the type of the message.
   270  func (c *client) call(req []byte) (reply interface{}, err error) {
   271  	c.mu.Lock()
   272  	defer c.mu.Unlock()
   273  
   274  	msg := make([]byte, 4+len(req))
   275  	binary.BigEndian.PutUint32(msg, uint32(len(req)))
   276  	copy(msg[4:], req)
   277  	if _, err = c.conn.Write(msg); err != nil {
   278  		return nil, clientErr(err)
   279  	}
   280  
   281  	var respSizeBuf [4]byte
   282  	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
   283  		return nil, clientErr(err)
   284  	}
   285  	respSize := binary.BigEndian.Uint32(respSizeBuf[:])
   286  	if respSize > maxAgentResponseBytes {
   287  		return nil, clientErr(err)
   288  	}
   289  
   290  	buf := make([]byte, respSize)
   291  	if _, err = io.ReadFull(c.conn, buf); err != nil {
   292  		return nil, clientErr(err)
   293  	}
   294  	reply, err = unmarshal(buf)
   295  	if err != nil {
   296  		return nil, clientErr(err)
   297  	}
   298  	return reply, err
   299  }
   300  
   301  func (c *client) simpleCall(req []byte) error {
   302  	resp, err := c.call(req)
   303  	if err != nil {
   304  		return err
   305  	}
   306  	if _, ok := resp.(*successAgentMsg); ok {
   307  		return nil
   308  	}
   309  	return errors.New("agent: failure")
   310  }
   311  
   312  func (c *client) RemoveAll() error {
   313  	return c.simpleCall([]byte{agentRemoveAllIdentities})
   314  }
   315  
   316  func (c *client) Remove(key ssh.PublicKey) error {
   317  	req := ssh.Marshal(&agentRemoveIdentityMsg{
   318  		KeyBlob: key.Marshal(),
   319  	})
   320  	return c.simpleCall(req)
   321  }
   322  
   323  func (c *client) Lock(passphrase []byte) error {
   324  	req := ssh.Marshal(&agentLockMsg{
   325  		Passphrase: passphrase,
   326  	})
   327  	return c.simpleCall(req)
   328  }
   329  
   330  func (c *client) Unlock(passphrase []byte) error {
   331  	req := ssh.Marshal(&agentUnlockMsg{
   332  		Passphrase: passphrase,
   333  	})
   334  	return c.simpleCall(req)
   335  }
   336  
   337  // List returns the identities known to the agent.
   338  func (c *client) List() ([]*Key, error) {
   339  	// see [PROTOCOL.agent] section 2.5.2.
   340  	req := []byte{agentRequestIdentities}
   341  
   342  	msg, err := c.call(req)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  
   347  	switch msg := msg.(type) {
   348  	case *identitiesAnswerAgentMsg:
   349  		if msg.NumKeys > maxAgentResponseBytes/8 {
   350  			return nil, errors.New("agent: too many keys in agent reply")
   351  		}
   352  		keys := make([]*Key, msg.NumKeys)
   353  		data := msg.Keys
   354  		for i := uint32(0); i < msg.NumKeys; i++ {
   355  			var key *Key
   356  			var err error
   357  			if key, data, err = parseKey(data); err != nil {
   358  				return nil, err
   359  			}
   360  			keys[i] = key
   361  		}
   362  		return keys, nil
   363  	case *failureAgentMsg:
   364  		return nil, errors.New("agent: failed to list keys")
   365  	}
   366  	panic("unreachable")
   367  }
   368  
   369  // Sign has the agent sign the data using a protocol 2 key as defined
   370  // in [PROTOCOL.agent] section 2.6.2.
   371  func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
   372  	req := ssh.Marshal(signRequestAgentMsg{
   373  		KeyBlob: key.Marshal(),
   374  		Data:    data,
   375  	})
   376  
   377  	msg, err := c.call(req)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  
   382  	switch msg := msg.(type) {
   383  	case *signResponseAgentMsg:
   384  		var sig ssh.Signature
   385  		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
   386  			return nil, err
   387  		}
   388  
   389  		return &sig, nil
   390  	case *failureAgentMsg:
   391  		return nil, errors.New("agent: failed to sign challenge")
   392  	}
   393  	panic("unreachable")
   394  }
   395  
   396  // unmarshal parses an agent message in packet, returning the parsed
   397  // form and the message type of packet.
   398  func unmarshal(packet []byte) (interface{}, error) {
   399  	if len(packet) < 1 {
   400  		return nil, errors.New("agent: empty packet")
   401  	}
   402  	var msg interface{}
   403  	switch packet[0] {
   404  	case agentFailure:
   405  		return new(failureAgentMsg), nil
   406  	case agentSuccess:
   407  		return new(successAgentMsg), nil
   408  	case agentIdentitiesAnswer:
   409  		msg = new(identitiesAnswerAgentMsg)
   410  	case agentSignResponse:
   411  		msg = new(signResponseAgentMsg)
   412  	case agentV1IdentitiesAnswer:
   413  		msg = new(agentV1IdentityMsg)
   414  	default:
   415  		return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
   416  	}
   417  	if err := ssh.Unmarshal(packet, msg); err != nil {
   418  		return nil, err
   419  	}
   420  	return msg, nil
   421  }
   422  
   423  type rsaKeyMsg struct {
   424  	Type        string `sshtype:"17|25"`
   425  	N           *big.Int
   426  	E           *big.Int
   427  	D           *big.Int
   428  	Iqmp        *big.Int // IQMP = Inverse Q Mod P
   429  	P           *big.Int
   430  	Q           *big.Int
   431  	Comments    string
   432  	Constraints []byte `ssh:"rest"`
   433  }
   434  
   435  type dsaKeyMsg struct {
   436  	Type        string `sshtype:"17|25"`
   437  	P           *big.Int
   438  	Q           *big.Int
   439  	G           *big.Int
   440  	Y           *big.Int
   441  	X           *big.Int
   442  	Comments    string
   443  	Constraints []byte `ssh:"rest"`
   444  }
   445  
   446  type ecdsaKeyMsg struct {
   447  	Type        string `sshtype:"17|25"`
   448  	Curve       string
   449  	KeyBytes    []byte
   450  	D           *big.Int
   451  	Comments    string
   452  	Constraints []byte `ssh:"rest"`
   453  }
   454  
   455  type ed25519KeyMsg struct {
   456  	Type        string `sshtype:"17|25"`
   457  	Pub         []byte
   458  	Priv        []byte
   459  	Comments    string
   460  	Constraints []byte `ssh:"rest"`
   461  }
   462  
   463  // Insert adds a private key to the agent.
   464  func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
   465  	var req []byte
   466  	switch k := s.(type) {
   467  	case *rsa.PrivateKey:
   468  		if len(k.Primes) != 2 {
   469  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
   470  		}
   471  		k.Precompute()
   472  		req = ssh.Marshal(rsaKeyMsg{
   473  			Type:        ssh.KeyAlgoRSA,
   474  			N:           k.N,
   475  			E:           big.NewInt(int64(k.E)),
   476  			D:           k.D,
   477  			Iqmp:        k.Precomputed.Qinv,
   478  			P:           k.Primes[0],
   479  			Q:           k.Primes[1],
   480  			Comments:    comment,
   481  			Constraints: constraints,
   482  		})
   483  	case *dsa.PrivateKey:
   484  		req = ssh.Marshal(dsaKeyMsg{
   485  			Type:        ssh.KeyAlgoDSA,
   486  			P:           k.P,
   487  			Q:           k.Q,
   488  			G:           k.G,
   489  			Y:           k.Y,
   490  			X:           k.X,
   491  			Comments:    comment,
   492  			Constraints: constraints,
   493  		})
   494  	case *ecdsa.PrivateKey:
   495  		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
   496  		req = ssh.Marshal(ecdsaKeyMsg{
   497  			Type:        "ecdsa-sha2-" + nistID,
   498  			Curve:       nistID,
   499  			KeyBytes:    elliptic.Marshal(k.Curve, k.X, k.Y),
   500  			D:           k.D,
   501  			Comments:    comment,
   502  			Constraints: constraints,
   503  		})
   504  	case *ed25519.PrivateKey:
   505  		req = ssh.Marshal(ed25519KeyMsg{
   506  			Type:        ssh.KeyAlgoED25519,
   507  			Pub:         []byte(*k)[32:],
   508  			Priv:        []byte(*k),
   509  			Comments:    comment,
   510  			Constraints: constraints,
   511  		})
   512  	default:
   513  		return fmt.Errorf("agent: unsupported key type %T", s)
   514  	}
   515  
   516  	// if constraints are present then the message type needs to be changed.
   517  	if len(constraints) != 0 {
   518  		req[0] = agentAddIdConstrained
   519  	}
   520  
   521  	resp, err := c.call(req)
   522  	if err != nil {
   523  		return err
   524  	}
   525  	if _, ok := resp.(*successAgentMsg); ok {
   526  		return nil
   527  	}
   528  	return errors.New("agent: failure")
   529  }
   530  
   531  type rsaCertMsg struct {
   532  	Type        string `sshtype:"17|25"`
   533  	CertBytes   []byte
   534  	D           *big.Int
   535  	Iqmp        *big.Int // IQMP = Inverse Q Mod P
   536  	P           *big.Int
   537  	Q           *big.Int
   538  	Comments    string
   539  	Constraints []byte `ssh:"rest"`
   540  }
   541  
   542  type dsaCertMsg struct {
   543  	Type        string `sshtype:"17|25"`
   544  	CertBytes   []byte
   545  	X           *big.Int
   546  	Comments    string
   547  	Constraints []byte `ssh:"rest"`
   548  }
   549  
   550  type ecdsaCertMsg struct {
   551  	Type        string `sshtype:"17|25"`
   552  	CertBytes   []byte
   553  	D           *big.Int
   554  	Comments    string
   555  	Constraints []byte `ssh:"rest"`
   556  }
   557  
   558  type ed25519CertMsg struct {
   559  	Type        string `sshtype:"17|25"`
   560  	CertBytes   []byte
   561  	Pub         []byte
   562  	Priv        []byte
   563  	Comments    string
   564  	Constraints []byte `ssh:"rest"`
   565  }
   566  
   567  // Add adds a private key to the agent. If a certificate is given,
   568  // that certificate is added instead as public key.
   569  func (c *client) Add(key AddedKey) error {
   570  	var constraints []byte
   571  
   572  	if secs := key.LifetimeSecs; secs != 0 {
   573  		constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...)
   574  	}
   575  
   576  	if key.ConfirmBeforeUse {
   577  		constraints = append(constraints, agentConstrainConfirm)
   578  	}
   579  
   580  	if cert := key.Certificate; cert == nil {
   581  		return c.insertKey(key.PrivateKey, key.Comment, constraints)
   582  	} else {
   583  		return c.insertCert(key.PrivateKey, cert, key.Comment, constraints)
   584  	}
   585  }
   586  
   587  func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error {
   588  	var req []byte
   589  	switch k := s.(type) {
   590  	case *rsa.PrivateKey:
   591  		if len(k.Primes) != 2 {
   592  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
   593  		}
   594  		k.Precompute()
   595  		req = ssh.Marshal(rsaCertMsg{
   596  			Type:        cert.Type(),
   597  			CertBytes:   cert.Marshal(),
   598  			D:           k.D,
   599  			Iqmp:        k.Precomputed.Qinv,
   600  			P:           k.Primes[0],
   601  			Q:           k.Primes[1],
   602  			Comments:    comment,
   603  			Constraints: constraints,
   604  		})
   605  	case *dsa.PrivateKey:
   606  		req = ssh.Marshal(dsaCertMsg{
   607  			Type:        cert.Type(),
   608  			CertBytes:   cert.Marshal(),
   609  			X:           k.X,
   610  			Comments:    comment,
   611  			Constraints: constraints,
   612  		})
   613  	case *ecdsa.PrivateKey:
   614  		req = ssh.Marshal(ecdsaCertMsg{
   615  			Type:        cert.Type(),
   616  			CertBytes:   cert.Marshal(),
   617  			D:           k.D,
   618  			Comments:    comment,
   619  			Constraints: constraints,
   620  		})
   621  	case *ed25519.PrivateKey:
   622  		req = ssh.Marshal(ed25519CertMsg{
   623  			Type:        cert.Type(),
   624  			CertBytes:   cert.Marshal(),
   625  			Pub:         []byte(*k)[32:],
   626  			Priv:        []byte(*k),
   627  			Comments:    comment,
   628  			Constraints: constraints,
   629  		})
   630  	default:
   631  		return fmt.Errorf("agent: unsupported key type %T", s)
   632  	}
   633  
   634  	// if constraints are present then the message type needs to be changed.
   635  	if len(constraints) != 0 {
   636  		req[0] = agentAddIdConstrained
   637  	}
   638  
   639  	signer, err := ssh.NewSignerFromKey(s)
   640  	if err != nil {
   641  		return err
   642  	}
   643  	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
   644  		return errors.New("agent: signer and cert have different public key")
   645  	}
   646  
   647  	resp, err := c.call(req)
   648  	if err != nil {
   649  		return err
   650  	}
   651  	if _, ok := resp.(*successAgentMsg); ok {
   652  		return nil
   653  	}
   654  	return errors.New("agent: failure")
   655  }
   656  
   657  // Signers provides a callback for client authentication.
   658  func (c *client) Signers() ([]ssh.Signer, error) {
   659  	keys, err := c.List()
   660  	if err != nil {
   661  		return nil, err
   662  	}
   663  
   664  	var result []ssh.Signer
   665  	for _, k := range keys {
   666  		result = append(result, &agentKeyringSigner{c, k})
   667  	}
   668  	return result, nil
   669  }
   670  
   671  type agentKeyringSigner struct {
   672  	agent *client
   673  	pub   ssh.PublicKey
   674  }
   675  
   676  func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
   677  	return s.pub
   678  }
   679  
   680  func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
   681  	// The agent has its own entropy source, so the rand argument is ignored.
   682  	return s.agent.Sign(s.pub, data)
   683  }