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)
109 var req agentUnlockMsg
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 parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) {
159 for len(constraints) != 0 {
160 switch constraints[0] {
161 case agentConstrainLifetime:
162 lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5])
163 constraints = constraints[5:]
164 case agentConstrainConfirm:
165 confirmBeforeUse = true
166 constraints = constraints[1:]
167 case agentConstrainExtension:
168 var msg constrainExtensionAgentMsg
169 if err = ssh.Unmarshal(constraints, &msg); err != nil {
170 return 0, false, nil, err
172 extensions = append(extensions, ConstraintExtension{
173 ExtensionName: msg.ExtensionName,
174 ExtensionDetails: msg.ExtensionDetails,
176 constraints = msg.Rest
178 return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0])
184 func setConstraints(key *AddedKey, constraintBytes []byte) error {
185 lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes)
190 key.LifetimeSecs = lifetimeSecs
191 key.ConfirmBeforeUse = confirmBeforeUse
192 key.ConstraintExtensions = constraintExtensions
196 func parseRSAKey(req []byte) (*AddedKey, error) {
198 if err := ssh.Unmarshal(req, &k); err != nil {
201 if k.E.BitLen() > 30 {
202 return nil, errors.New("agent: RSA public exponent too large")
204 priv := &rsa.PrivateKey{
205 PublicKey: rsa.PublicKey{
210 Primes: []*big.Int{k.P, k.Q},
214 addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
215 if err := setConstraints(addedKey, k.Constraints); err != nil {
221 func parseEd25519Key(req []byte) (*AddedKey, error) {
223 if err := ssh.Unmarshal(req, &k); err != nil {
226 priv := ed25519.PrivateKey(k.Priv)
228 addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments}
229 if err := setConstraints(addedKey, k.Constraints); err != nil {
235 func parseDSAKey(req []byte) (*AddedKey, error) {
237 if err := ssh.Unmarshal(req, &k); err != nil {
240 priv := &dsa.PrivateKey{
241 PublicKey: dsa.PublicKey{
242 Parameters: dsa.Parameters{
252 addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
253 if err := setConstraints(addedKey, k.Constraints); err != nil {
259 func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) {
260 priv = &ecdsa.PrivateKey{
266 priv.Curve = elliptic.P256()
268 priv.Curve = elliptic.P384()
270 priv.Curve = elliptic.P521()
272 return nil, fmt.Errorf("agent: unknown curve %q", curveName)
275 priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes)
276 if priv.X == nil || priv.Y == nil {
277 return nil, errors.New("agent: point not on curve")
283 func parseEd25519Cert(req []byte) (*AddedKey, error) {
285 if err := ssh.Unmarshal(req, &k); err != nil {
288 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
292 priv := ed25519.PrivateKey(k.Priv)
293 cert, ok := pubKey.(*ssh.Certificate)
295 return nil, errors.New("agent: bad ED25519 certificate")
298 addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}
299 if err := setConstraints(addedKey, k.Constraints); err != nil {
305 func parseECDSAKey(req []byte) (*AddedKey, error) {
307 if err := ssh.Unmarshal(req, &k); err != nil {
311 priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D)
316 addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
317 if err := setConstraints(addedKey, k.Constraints); err != nil {
323 func parseRSACert(req []byte) (*AddedKey, error) {
325 if err := ssh.Unmarshal(req, &k); err != nil {
329 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
334 cert, ok := pubKey.(*ssh.Certificate)
336 return nil, errors.New("agent: bad RSA certificate")
339 // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
345 if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil {
346 return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
349 if rsaPub.E.BitLen() > 30 {
350 return nil, errors.New("agent: RSA public exponent too large")
353 priv := rsa.PrivateKey{
354 PublicKey: rsa.PublicKey{
355 E: int(rsaPub.E.Int64()),
359 Primes: []*big.Int{k.Q, k.P},
363 addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}
364 if err := setConstraints(addedKey, k.Constraints); err != nil {
370 func parseDSACert(req []byte) (*AddedKey, error) {
372 if err := ssh.Unmarshal(req, &k); err != nil {
375 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
379 cert, ok := pubKey.(*ssh.Certificate)
381 return nil, errors.New("agent: bad DSA certificate")
384 // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
389 if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil {
390 return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
393 priv := &dsa.PrivateKey{
394 PublicKey: dsa.PublicKey{
395 Parameters: dsa.Parameters{
405 addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}
406 if err := setConstraints(addedKey, k.Constraints); err != nil {
412 func parseECDSACert(req []byte) (*AddedKey, error) {
414 if err := ssh.Unmarshal(req, &k); err != nil {
418 pubKey, err := ssh.ParsePublicKey(k.CertBytes)
422 cert, ok := pubKey.(*ssh.Certificate)
424 return nil, errors.New("agent: bad ECDSA certificate")
427 // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
428 var ecdsaPub struct {
433 if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil {
437 priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D)
442 addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}
443 if err := setConstraints(addedKey, k.Constraints); err != nil {
449 func (s *server) insertIdentity(req []byte) error {
451 Type string `sshtype:"17|25"`
452 Rest []byte `ssh:"rest"`
455 if err := ssh.Unmarshal(req, &record); err != nil {
459 var addedKey *AddedKey
464 addedKey, err = parseRSAKey(req)
466 addedKey, err = parseDSAKey(req)
467 case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
468 addedKey, err = parseECDSAKey(req)
469 case ssh.KeyAlgoED25519:
470 addedKey, err = parseEd25519Key(req)
471 case ssh.CertAlgoRSAv01:
472 addedKey, err = parseRSACert(req)
473 case ssh.CertAlgoDSAv01:
474 addedKey, err = parseDSACert(req)
475 case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
476 addedKey, err = parseECDSACert(req)
477 case ssh.CertAlgoED25519v01:
478 addedKey, err = parseEd25519Cert(req)
480 return fmt.Errorf("agent: not implemented: %q", record.Type)
486 return s.agent.Add(*addedKey)
489 // ServeAgent serves the agent protocol on the given connection. It
490 // returns when an I/O error occurs.
491 func ServeAgent(agent Agent, c io.ReadWriter) error {
496 if _, err := io.ReadFull(c, length[:]); err != nil {
499 l := binary.BigEndian.Uint32(length[:])
500 if l > maxAgentResponseBytes {
501 // We also cap requests.
502 return fmt.Errorf("agent: request too large: %d", l)
505 req := make([]byte, l)
506 if _, err := io.ReadFull(c, req); err != nil {
510 repData := s.processRequestBytes(req)
511 if len(repData) > maxAgentResponseBytes {
512 return fmt.Errorf("agent: reply too large: %d bytes", len(repData))
515 binary.BigEndian.PutUint32(length[:], uint32(len(repData)))
516 if _, err := c.Write(length[:]); err != nil {
519 if _, err := c.Write(repData); err != nil {