Agent protocol changes related to U2F/FIDO2 keys

Ron Frederick ronf at timeheart.net
Sat Dec 7 18:59:03 AEDT 2019


I spent some time today implementing support for loading U2F keys into the SSH agent from my AsyncSSH library. I got it working, but along the way I ran into a few issues I wanted to report:

First, it looks like the value of SSH_AGENT_CONSTRAIN_EXTENSION has changed from the value 3 defined at https://tools.ietf.org/html/draft-miller-ssh-agent-02 <https://tools.ietf.org/html/draft-miller-ssh-agent-02> to the value 255 now, and somewhere along the way the constraint SSH_AGENT_CONSTRAIN_MAXSIGN was defined to use the value 3.

Second, https://raw.githubusercontent.com/openssh/openssh-portable/master/PROTOCOL.u2f <https://raw.githubusercontent.com/openssh/openssh-portable/master/PROTOCOL.u2f> documents the new extension for loading SK keys as:
	byte		SSH_AGENT_CONSTRAIN_EXTENSION
	string		sk at openssh.com
	string		middleware path
However, the current OpenSSH agent code actually expects to receive:
	byte		SSH_AGENT_CONSTRAIN_EXTENSION
	string		sk-provider at openssh.com
	string		middleware path
Also, this documentation doesn’t define the format of the key data sent to the agent for SK keys with certificates. Similar to plain ECDSA keys with certificates, the key data sent for ECDSA SK keys omits the curve_id and Q value of the ECDSA key that would normally be written out when serializing a local private key. So, the data sent to the agent for an ECDSA SK key with certificate looks like:
	string		"sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com"
	string		nonce
	string		curve name
	ec_point	Q
	string		application
	uint64		serial
	uint32		type
	string		key id
	string		valid principals
	uint64		valid after
	uint64		valid before
	string		critical options
	string		extensions
	string		reserved
	string		signature key
	string		signature
	string		application
	uint8		flags
	string		key_handle
	string		reserved
If the instant was to avoid duplicating what was already in the certificate, though, I’m not sure why “application” is sent twice. It seems like that should have been left out along with the curve_id and Q value, appending only the flags, key_handle, and reserved values from the private key at the end.

In the case of Ed25519 SK keys with certificates, nothing was removed. There, the format appears to currently be just the normal encoding of the certificate followed by the normal encoding of the private key, repeating the public key value and the application:
	string		"sk-ssh-ed25519-cert-v01 at openssh.com"
	string		nonce
	string		public key
	string		application
	uint64		serial
	uint32		type
	string		key id
	string		valid principals
	uint64		valid after
	uint64		valid before
	string		critical options
	string		extensions
	string		reserved
	string		signature key
	string		signature
	string		public key
	string		application
	uint8		flags
	string		key_handle
	string		reserved
I also noticed that https://raw.githubusercontent.com/openssh/openssh-portable/master/PROTOCOL.u2f <https://raw.githubusercontent.com/openssh/openssh-portable/master/PROTOCOL.u2f> incorrectly documents the flags value as being a uint32 in the Ed25519 SK private key encoding:
	string		"sk-ssh-ed25519 at openssh.com"
	string		public key
	string		application (user-specified, but typically "ssh:")
	uint32		flags
	string		key_handle
	string		reserved
This should be a uint8 for the flags, matching the ECDSA case.
-- 
Ron Frederick
ronf at timeheart.net





More information about the openssh-unix-dev mailing list