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.
19 "golang.org/x/crypto/ed25519"
20 "golang.org/x/crypto/ssh"
23 // Server wraps an Agent and uses it to implement the agent side of
24 // the SSH-agent, wire protocol.
29 func (s *server) processRequestBytes(reqData []byte) []byte {
30 rep, err := s.processRequest(reqData)
33 // TODO(hanwen): provide better logging interface?
34 log.Printf("agent %d: %v", reqData[0], err)
36 return []byte{agentFailure}
39 if err == nil && rep == nil {
40 return []byte{agentSuccess}
43 return ssh.Marshal(rep)
46 func marshalKey(k *Key) []byte {
51 record.Blob = k.Marshal()
52 record.Comment = k.Comment
54 return ssh.Marshal(&record)
57 // See [PROTOCOL.agent], section 2.5.1.
58 const agentV1IdentitiesAnswer = 2
60 type agentV1IdentityMsg struct {
61 Numkeys uint32 `sshtype:"2"`
64 type agentRemoveIdentityMsg struct {
65 KeyBlob []byte `sshtype:"18"`
68 type agentLockMsg struct {
69 Passphrase []byte `sshtype:"22"`
72 type agentUnlockMsg struct {
73 Passphrase []byte `sshtype:"23"`
76 func (s *server) processRequest(data []byte) (interface{}, error) {
78 case agentRequestV1Identities:
79 return &agentV1IdentityMsg{0}, nil
81 case agentRemoveAllV1Identities:
84 case agentRemoveIdentity:
85 var req agentRemoveIdentityMsg
86 if err := ssh.Unmarshal(data, &req); err != nil {
91 if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
95 return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob})
97 case agentRemoveAllIdentities:
98 return nil, s.agent.RemoveAll()
102 if err := ssh.Unmarshal(data, &req); err != nil {
106 return nil, s.agent.Lock(req.Passphrase)
110 if err := ssh.Unmarshal(data, &req); err != nil {
113 return nil, s.agent.Unlock(req.Passphrase)
115 case agentSignRequest:
116 var req signRequestAgentMsg
117 if err := ssh.Unmarshal(data, &req); err != nil {
122 if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
131 sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags.
135 return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil
137 case agentRequestIdentities:
138 keys, err := s.agent.List()
143 rep := identitiesAnswerAgentMsg{
144 NumKeys: uint32(len(keys)),
146 for _, k := range keys {
147 rep.Keys = append(rep.Keys, marshalKey(k)...)
151 case agentAddIdConstrained, agentAddIdentity:
152 return nil, s.insertIdentity(data)
155 return nil, fmt.Errorf("unknown opcode %d", data[0])
158 func parseRSAKey(req []byte) (*AddedKey, error) {
160 if err := ssh.Unmarshal(req, &k); err != nil {
163 if k.E.BitLen() > 30 {
164 return nil, errors.New("agent: RSA public exponent too large")
166 priv := &rsa.PrivateKey{
167 PublicKey: rsa.PublicKey{
172 Primes: []*big.Int{k.P, k.Q},
176 return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
179 func parseEd25519Key(req []byte) (*AddedKey, error) {
181 if err := ssh.Unmarshal(req, &k); err != nil {
184 priv := ed25519.PrivateKey(k.Priv)
185 return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil
188 func parseDSAKey(req []byte) (*AddedKey, error) {
190 if err := ssh.Unmarshal(req, &k); err != nil {
193 priv := &dsa.PrivateKey{
194 PublicKey: dsa.PublicKey{
195 Parameters: dsa.Parameters{
205 return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
208 func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) {
209 priv = &ecdsa.PrivateKey{
215 priv.Curve = elliptic.P256()
217 priv.Curve = elliptic.P384()
219 priv.Curve = elliptic.P521()
221 return nil, fmt.Errorf("agent: unknown curve %q", curveName)
224 priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes)
225 if priv.X == nil || priv.Y == nil {
226 return nil, errors.New("agent: point not on curve")
232 func parseEd25519Cert(req []byte) (*AddedKey, error) {
234 if err := ssh.Unmarshal(req, &k); err != nil {
237 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
241 priv := ed25519.PrivateKey(k.Priv)
242 cert, ok := pubKey.(*ssh.Certificate)
244 return nil, errors.New("agent: bad ED25519 certificate")
246 return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
249 func parseECDSAKey(req []byte) (*AddedKey, error) {
251 if err := ssh.Unmarshal(req, &k); err != nil {
255 priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D)
260 return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
263 func parseRSACert(req []byte) (*AddedKey, error) {
265 if err := ssh.Unmarshal(req, &k); err != nil {
269 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
274 cert, ok := pubKey.(*ssh.Certificate)
276 return nil, errors.New("agent: bad RSA certificate")
279 // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
285 if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil {
286 return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
289 if rsaPub.E.BitLen() > 30 {
290 return nil, errors.New("agent: RSA public exponent too large")
293 priv := rsa.PrivateKey{
294 PublicKey: rsa.PublicKey{
295 E: int(rsaPub.E.Int64()),
299 Primes: []*big.Int{k.Q, k.P},
303 return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
306 func parseDSACert(req []byte) (*AddedKey, error) {
308 if err := ssh.Unmarshal(req, &k); err != nil {
311 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
315 cert, ok := pubKey.(*ssh.Certificate)
317 return nil, errors.New("agent: bad DSA certificate")
320 // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
325 if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil {
326 return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
329 priv := &dsa.PrivateKey{
330 PublicKey: dsa.PublicKey{
331 Parameters: dsa.Parameters{
341 return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
344 func parseECDSACert(req []byte) (*AddedKey, error) {
346 if err := ssh.Unmarshal(req, &k); err != nil {
350 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
354 cert, ok := pubKey.(*ssh.Certificate)
356 return nil, errors.New("agent: bad ECDSA certificate")
359 // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
360 var ecdsaPub struct {
365 if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil {
369 priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D)
374 return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
377 func (s *server) insertIdentity(req []byte) error {
379 Type string `sshtype:"17|25"`
380 Rest []byte `ssh:"rest"`
383 if err := ssh.Unmarshal(req, &record); err != nil {
387 var addedKey *AddedKey
392 addedKey, err = parseRSAKey(req)
394 addedKey, err = parseDSAKey(req)
395 case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
396 addedKey, err = parseECDSAKey(req)
397 case ssh.KeyAlgoED25519:
398 addedKey, err = parseEd25519Key(req)
399 case ssh.CertAlgoRSAv01:
400 addedKey, err = parseRSACert(req)
401 case ssh.CertAlgoDSAv01:
402 addedKey, err = parseDSACert(req)
403 case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
404 addedKey, err = parseECDSACert(req)
405 case ssh.CertAlgoED25519v01:
406 addedKey, err = parseEd25519Cert(req)
408 return fmt.Errorf("agent: not implemented: %q", record.Type)
414 return s.agent.Add(*addedKey)
417 // ServeAgent serves the agent protocol on the given connection. It
418 // returns when an I/O error occurs.
419 func ServeAgent(agent Agent, c io.ReadWriter) error {
424 if _, err := io.ReadFull(c, length[:]); err != nil {
427 l := binary.BigEndian.Uint32(length[:])
428 if l > maxAgentResponseBytes {
429 // We also cap requests.
430 return fmt.Errorf("agent: request too large: %d", l)
433 req := make([]byte, l)
434 if _, err := io.ReadFull(c, req); err != nil {
438 repData := s.processRequestBytes(req)
439 if len(repData) > maxAgentResponseBytes {
440 return fmt.Errorf("agent: reply too large: %d bytes", len(repData))
443 binary.BigEndian.PutUint32(length[:], uint32(len(repData)))
444 if _, err := c.Write(length[:]); err != nil {
447 if _, err := c.Write(repData); err != nil {