New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Agent restrictions / host-bound public key signatures combined #5
Conversation
33f3759
to
a76187d
Compare
a76187d
to
23ba606
Compare
23ba606
to
947fdc0
Compare
4e7bf94
to
104c7e1
Compare
104c7e1
to
6948d0b
Compare
6948d0b
to
9f8709a
Compare
These will be used later for agent session ID / hostkey binding
send session ID, hostkey, signature and a flag indicating whether the agent connection is being forwarded to ssh agent each time a connection is opened via a new "session-bind@openssh.com" agent extension.
record session ID/hostkey/forwarding status for each active socket. Attempt to parse data-to-be-signed at signature request time and extract session ID from the blob if it is a pubkey userauth request.
Have ssh-add accept a list of "destination constraints" that allow restricting where keys may be used in conjunction with a ssh-agent/ssh that supports session ID/hostkey binding. Constraints are specified as either "[user@]host-pattern" or "host-pattern>[user@]host-pattern". The first form permits a key to be used to authenticate as the specified user to the specified host. The second form permits a key that has previously been permitted for use at a host to be available via a forwarded agent to an additional host. For example, constraining a key with "user1@host_a" and "host_a>host_b". Would permit authentication as "user1" at "host_a", and allow the key to be available on an agent forwarded to "host_a" only for authentication to "host_b". The key would not be visible on agent forwarded to other hosts or usable for authentication there. Internally, destination constraints use host keys to identify hosts. The host patterns are used to obtain lists of host keys for that destination that are communicated to the agent. The user/hostkeys are encoded using a new restrict-destination-v00@openssh.com key constraint. host keys are looked up in the default client user/system known_hosts files. It is possible to override this set on the command-line.
Gives ssh-agent the ability to parse restrict-destination-v00@openssh.com constraints and to apply them to keys. Check constraints against the hostkeys recorded for a SocketEntry when attempting a signature, adding, listing or deleting keys. Note that the "delete all keys" request will remove constrained keys regardless of location.
allow authentication methods to have one additional name beyond their primary name. allow lookup by this synonym Use primary name for authentication decisions, e.g. for PermitRootLogin=publickey Pass actual invoked name to the authmethods, so they can tell whether they were requested via the their primary name or synonym.
This is identical to the standard "publickey" method, but it also includes the initial server hostkey in the message signed by the client.
Add kex->flags member to enable the publickey-hostbound-v00@openssh.com authentication method. Use the new hostbound method in client if the kex->flags flag was set, and include the inital KEX hostkey in the userauth request. Note: nothing in kex.c actually sets the new flag yet
the EXT_INFO packet gets a new publickey-hostbound@openssh.com to advertise the hostbound public key method. Client side support to parse this feature flag and set the kex->flags indicator if the expected version is offered (currently "0").
Allow parse_userauth_request() to work with blobs from publickey-hostbound-v00@openssh.com userauth attempts. Extract hostkey from these blobs.
Require host-bound userauth requests for forwarded SSH connections. The hostkey parsed from the host-bound userauth request is now checked against the most recently bound session ID / hostkey on the agent socket and the signature refused if they do not match.
Allow control over which pubkey methods are used. Added out of concern that some hardware devices may have difficulty signing the longer pubkey authentication challenges. This provides a way for them to disable the extension. It's also handy for testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
....
tried to comment per commit....
| } | ||
| /* XXX logspam */ | ||
| debug_f("user=%s", user); | ||
| if (identity_permitted(id, e, user, &fwd_host, &dest_host) != 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fwd_host and dest_host are not used (printed?)
Right, it's enforced as empty when it is loaded in parse_dest_constraint(). The complete pretty-printing is probably vestigial from an earlier version of the patch :) |
good point; done |
Not at present. I'd like to use them in the askpass UI, but there is enough in this patchset already... |
done |
moved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok markus@
NB. This is a work in progress.
This tree combines the agent session ID binding and host-bound userauth signatures approaches to restricting agent forwarding.
Note also that these patches are for the OpenBSD version of OpenSSH. A version of the patches adapted for Portable OpenSSH is also available.
Overview
These changes implement a key permission model for
ssh-agentthat allows granular control over which keys are available to particular destinations and forwarding hops. Destination hosts specified in these permissions are cryptographically verifiable by the agent.Keys may be destination restricted when they added to the agent by
ssh-add. Destination restrictions take the form of one or more[user@]hostorhost1>[user@]host2strings, e.g.This would permit the key to be used to authenticate to any account on
example.com, to userdjmonexample.org, and toexample.netusing an agent forwarded throughexample.org.Internally, hosts are identified by their host keys.
ssh-addwill perform the name to key lookup using theknown_hostsfiles on the system where was ran.Connections forwarded across multiple hops must satisfy all restriction conditions for the keys to be usable at the destination. E.g. for the above set of restrictions (and assuming all hosts have independent host keys, the key is in
authorized_keys, etc)TODO decide whether this "hop by hop" permission model is better than requiring the user to explicitly specify full paths, e.g.
(allowing access to
host_cby the specified path, but also implicitly allowing the intermediate hosts too.)Goals
The goal of these changes is to allow control over selection and delegation of keys stored in SSH agent.
Delegation of key subsets
The primary motivation of this feature is providing the ability to delegate access to subsets of keys hosted in an agent. For example:
Running these commands would load four keys into a
ssh-agent, each with different delegation permissions:key_ahas no delegation restrictions. It will be available for use on all hosts to which the agent has been forwarded.key_bis permitted for authentication tohost_aand delegated for use athost_aonly for authentication tohost_b.key_cis permitted for authentication tohost_aand delegated for authentication from there to hostshost_borhost_ckey_dis permitted for authentication tohost_a, authentication fromhost_atohost_band use onhost_bto authenticate tohost_cAt each step, only the delegated keys should be visible. I.e.
ssh-add -lon the origin host orhost_ashould show all four keys whereas running the same command onhost_bwill display only the unrestrictedkey_aand the delegatedkey_d.Selection of keys
It is already possible to select particular keys to be offered to specific destination hosts using the
IdentityFileandIdentiesOnlydirectives inssh_config.These changes offer an alternative that may be more friendly, at least for one-off or ad-hoc use cases As an example,
May be easier than the equivalent configuration:
Implementation
This assumes familiarity with the SSH agent protocol draft-miller-ssh-agent-04, the SSH public key authentication subprotocol and how they are used in practice.
Key permissions are built on a pair of agent protocol extensions: a trivial
restrict-destination-v00@openssh.comkey constraint that is used to encode the permissions attached to keys being added to the agent and and a newsession-bind@openssh.comextension request that is used to cryptographically bind hostkeys to agent connections.An additional modification is made to the public key authentication request to include the host key signature in the data signed by the client.
Session / hostkey binding
The session binding mechanism depends on a number of SSH protocol features across the client, server and agent to establish a cryptographically provable binding between a session ID and a SSH host key.
When a SSH connection is established, a key exchange process is performed between the client and server (e.g. using ECDH). One of the outputs of this process is a session ID that is signed by the server to prove ownership of a host key. This same session ID is subsequently used to included in public key authentication requests that are signed and sent by the client and verified by the server. The session ID is included in the to-be-signed data to bind them to the connection instance, preventing replay of authentication attempts across connections.
The session ID is therefore cryptographically traceable to a host key and included in public key authentication requests. The
session-bind@openssh.comextension takes advantage of these two properties. It allows a SSH client to communicate the to the agent the host key used in the initial key exchange, the session ID derived for the connection and the server's signature (over the session ID) proving the binding between them.When the agent receives this binding on a connected socket, it verifies the signature and records the host key and session ID as bound to that socket. When publickey authentication requests subsequently arrive on that socket, the agent may check the bound session ID against the session ID included in the authentication request to be signed, and the associated hostkey against the constraints associated with the key that will perform the signing. If one of these fails to match the signing request will be denied.
If a SSH agent is forwarded across multiple "hops" of SSH clients, each client will issue a
session-bind@openssh.comrequest when it attempts to use or forward the agent. The agent connection will therefore accrue a list of{session ID, hostkey}that it may use to match against destination restrictions that it has set on loaded keys. This implementation requires hostkeys gathered on a chained connection be permitted by a destination restriction.Certificate matching is slightly more complex than plain hostkey matching. As per above, certificates are represented in destination restrictions by their CA key and a hostname wildcard pattern that is matched against the host certificate principals. This allows for common patterns of CA use such as whole domain
*.example.comtrust and individual hostname trust.Destination restriction key restrictions
Destination restrictions are an array of permission tuples that may be attached to a key when it is added to
ssh-agent. Each entry in the array identifies a single forwarding step that a key is allowed for. A forwarding step is identified by its source host keys and destination user and host keys.A special case is the initial authentication / forwarding step, from the host that is running
ssh-agentlocally. The step is distinguished by having no source host keys specified. All other steps must have both source and destination hostkeys present.Restrictions are applied by
ssh-agentwhen it receives a request to use a key (e.g. to sign a challenge). The agent will walk the array of bound session IDs hostkeys for the connection on which the request was received and try to match each hop to a permission tuple. All entries in the bound session array must match a corresponding permission for the request to be permitted. Additionally, for signature requests, the agent will require that the session ID present in the to-be-signed challenge matches the most-recently bound session ID.Restrictions are communicated to
ssh-agentwhen keys are added using a key constraint extension described below.Modification to public key authentication subprotocol
Given the session binding modification above, the data signed by a SSH client (or by
ssh-agenton a client's behalf) is only indirectly linked to the host key used to authenticate the connection, by way of the binding between session ID and hostkey. This situation allows a malicious host that has access to a trusted hostkey to forge bindings and potentially circumvent destination restrictions.Consider a user on hostA who has authorised a key for authentication to hostB and for forwarding through hostB for authentication to hostC. Assume that an attacker has access to the user's agent socket on hostB and has use of hostC's hostkey. The attacker could establish a connection to some unauthorised host (say hostX) and issue a
session-bind@request to the agent, offering the session ID for the connection to hostX but including a copy of hostC's hostkey and a valid signature. At this point the agent would permit signature requests made over that socket as authorised.To avoid this situation, we introduce a slightly-modified
publickey-hostbound-v00@openssh.comauthentication request that extends the data signed by the client to include the server's host key. This effectively makes the host key available to the agent at the time of signing and allows the agent to ensure that it matches the most recently-bound session ID and hostkey.To enable use of this new public key request, both the client and server must support it. This uses the
SSH2_MSG_EXT_INFOextension mechanism to allow the server to inform the client of its availability, via apublickey-hostbound@openssh.comadvertisment string. A client with support for the modified method that sees this extension offered by the server may use it.Protocol extension message formats
Session binding
Session bindings are communicated using an agent extension request:
Where
is_forwardingis a hint from the client as to whether this connection is intended solely for user authentication (false) or is a forwarding channel for arbitrary future requests (true).Destination restriction key constraint
Destination restrictions are encoded using a key constraint extension that may be attached to
SSH2_AGENTC_ADD_IDENTITYandSSH_AGENTC_ADD_SMARTCARD_KEYrequests.where each
permissionis the encoded tuple:The
reservedstring must be empty at this time. The source and desination hops are encoded as:A zero-length
usernamerepresents any user. The username in the source hop specification must be empty.key_specsis an array of:If the
ca_flagis set, then the correponding hostkey is assumed to be a trusted CA key for host names matching thehostnamewildcard pattern. Otherwise, the hostkey directly specifies the expected host key for the destination and thehostnamefield is not used for permission checking (though it may still be used for display).Host-bound public key authentication
The
publickey-hostbound-v00@openssh.comauthentication method modifies the data signed during public key authentication.The request packet is unmodified except for the method name:
The signed data is modified to include the server's initial host key after the user key attempting authentication:
Negotiation of host-bound public key authentication
The host-bound public key authentication method is offered via the ext-info mechanism via a
SSH2_MSG_EXT_INFOnotification. The format of the notification is just the extension name and version number:Testing
A corresponding regression test is at djmdjm/openssh-regress-wip#1
Threat model
This feature is intended to protect forwarded agents. We assume the local host (i.e. the host running the agent) to be trustworthy.
We assume a remote attacker to be an attacker with root-equivalent access on a host that has had a restricted agent forwarded to it. They are expected to have full access to the forwarded agent socket, are able to attempt arbitrary requests over it and be able to make use of the forwarded-to host's host-key. For this design to be successful, such an attacker must have no more access to keys stored in
ssh-agentthan what was delegated to the remote host.Potential attacks/vulnerabilities include:
ssh-addcommand-line interface causes user misunderstanding resulting in unintentional use-of-key exposure.Future work
The underlying infrastructure implemented here has the potential to offer additional capabilities beyond what has been implemented.
Wildcard forwarding
It would be relatively simple to allow true wildcard hosts in the forwarding
specification. E.g.
At present, wildcard host names are expanded to the set of host keys matching the wildcard in the local
known_hostsfiles, which isn't really optimal.Limitation of agent requests
This change only meaningfully restricts visibility and use of keys. It would be possible however, to use the path information made available by the
session-bind@openssh.comextension to control access to other agent features.In particular, it would be possible to restrict a forwarded agent's ability to add or remove keys, or to load a PKCS#11 token into a running agent.
The caveat here is that, unlike signature requests, there is no binding of these other to a host key. As such, the forwarding path only really trustworthy for the first hop.
Addition of restrictions by hop
Similarly, it would be possible to use path information to modify existing key restrictions. For example, it would be possible to require per-signature confirmation (using the existing askpass mechanism) for keys forwarded to/beyond a particular host.
Forwarded access to FIDO tokens
Currently,
ssh-agentrefuses to sign data using FIDO tokens that does not parse as a SSH messages (e.g. a public key userauth request). This check exists to prevent a forwarded agent from granting access to sign web authentication challenges remotely.But, sometimes you want to sign web authentication challenges via a forwarded agent. An example might be a command-line too that needs to authenticate to a web server.
It would be possible to use the forwarding path information to selectively relax this restriction, though the above caveat about trustworthiness of the path beyond the first hop apply.
Selective relaxation of host-bound signature requirement
These
ssh-agentchanges require user authentication signature requests be host-bound for forwarded agents. This has the consequence of requiring upgraded SSH servers for all destinations that the user wished to authenticate to with a forwarded key.It would similarly be possible to relax this requirement, at the cost of reintroducing the hostkey collusion signing attack that motivated host-bound signatures initially. This relaxation could be done on a per-hop basis.
Credits
Thanks to Markus Friedl and Jann Horn for providing invaluable feedback on the design and implementation. Jann also identified the hostkey re-signing attack with embarrassing speed.