OSDN Git Service

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