ssh: support SSH agent signature flags and custom extensions
This commit implements two new features. To preserve backwards compatibility the new methods are added to an `ExtendedAgent` interface which extends `Agent`. The client code implements `ExtendedAgent` (which extends Agent) so you can call these additional methods against SSH agents such as the OpenSSH agent. The ServeAgent method still accepts Agent but will attempt to upcast the agent to `ExtendedAgent` as needed, so if you supply an ExtendedAgent implementation you can implement these additional methods (which keyring does). The first feature is supporting the standard flags that can be passed to SSH Sign requests, requesting that RSA signatures use SHA-256 or SHA-512. See section 4.5.1 of the SSH agent protocol draft: https://tools.ietf.org/html/draft-miller-ssh-agent-02 The second feature is supporting calling custom extensions from clients and implementing custom extensions from servers. See section 4.7 of the SSH agent protocol draft: https://tools.ietf.org/html/draft-miller-ssh-agent-02 Change-Id: I0f74feb893762c27e921ec37604d3a46434ee6ef GitHub-Last-Rev: 2e23fd01c0e95b664e8507682f0bd5bd61d4c146 GitHub-Pull-Request: golang/crypto#53 Reviewed-on: https://go-review.googlesource.com/c/123955 Reviewed-by: Han-Wen Nienhuys <hanwen@google.com> Run-TryBot: Han-Wen Nienhuys <hanwen@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
committed by
Han-Wen Nienhuys
parent
45a5f77698
commit
dab2b1051b
+45
-1
@@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) {
|
||||
Blob: req.KeyBlob,
|
||||
}
|
||||
|
||||
sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags.
|
||||
var sig *ssh.Signature
|
||||
var err error
|
||||
if extendedAgent, ok := s.agent.(ExtendedAgent); ok {
|
||||
sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags))
|
||||
} else {
|
||||
sig, err = s.agent.Sign(k, req.Data)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) {
|
||||
|
||||
case agentAddIDConstrained, agentAddIdentity:
|
||||
return nil, s.insertIdentity(data)
|
||||
|
||||
case agentExtension:
|
||||
// Return a stub object where the whole contents of the response gets marshaled.
|
||||
var responseStub struct {
|
||||
Rest []byte `ssh:"rest"`
|
||||
}
|
||||
|
||||
if extendedAgent, ok := s.agent.(ExtendedAgent); !ok {
|
||||
// If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7
|
||||
// requires that we return a standard SSH_AGENT_FAILURE message.
|
||||
responseStub.Rest = []byte{agentFailure}
|
||||
} else {
|
||||
var req extensionAgentMsg
|
||||
if err := ssh.Unmarshal(data, &req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := extendedAgent.Extension(req.ExtensionType, req.Contents)
|
||||
if err != nil {
|
||||
// If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE
|
||||
// message as required by [PROTOCOL.agent] section 4.7.
|
||||
if err == ErrExtensionUnsupported {
|
||||
responseStub.Rest = []byte{agentFailure}
|
||||
} else {
|
||||
// As the result of any other error processing an extension request,
|
||||
// [PROTOCOL.agent] section 4.7 requires that we return a
|
||||
// SSH_AGENT_EXTENSION_FAILURE code.
|
||||
responseStub.Rest = []byte{agentExtensionFailure}
|
||||
}
|
||||
} else {
|
||||
if len(res) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
responseStub.Rest = res
|
||||
}
|
||||
}
|
||||
|
||||
return responseStub, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown opcode %d", data[0])
|
||||
|
||||
Reference in New Issue
Block a user