Mailing List Archive

Agent protocol changes related to U2F/FIDO2 keys
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@openssh.com
string middleware path
However, the current OpenSSH agent code actually expects to receive:
byte SSH_AGENT_CONSTRAIN_EXTENSION
string sk-provider@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@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@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@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@timeheart.net



_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Agent protocol changes related to U2F/FIDO2 keys [ In reply to ]
On Fri, 6 Dec 2019, Ron Frederick wrote:

> 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 to the value 255
> now, and somewhere along the way the constraint
> SSH_AGENT_CONSTRAIN_MAXSIGN was defined to use the value 3.

Yes, I had already updated the I-D back in July to fix this collision:
https://tools.ietf.org/html/draft-miller-ssh-agent-03

> Second, 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@openssh.com
> string middleware path
> However, the current OpenSSH agent code actually expects to receive:
> byte SSH_AGENT_CONSTRAIN_EXTENSION
> string sk-provider@openssh.com
> string middleware path

oops, I'll fix.

> 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@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

I don't think that's quite right as it has the pubkey/cert expanded rather
than encoded in a string - for all certificates, including sk-* the wire
format for private keys should be:

string key type
string public key (including certificate data)
... private key fields

E.g.

string "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
string pubkey
string application
uint8 flags
string key_handle
string reserved

You're correct that this is not documented in PROTOCOL.u2f. I'll update
that now.

> 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.

Yeah, application is accidentally repeated. I don't think that I'll touch
it for now, unless there is some other change that requires changing the
serialisation format.

> I also noticed that
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:

yes, that's a mistake too. I'll fix that now.

Thanks for the detailed feedback!

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Agent protocol changes related to U2F/FIDO2 keys [ In reply to ]
On Dec 10, 2019, at 3:36 PM, Damien Miller <djm@mindrot.org> wrote:
> On Fri, 6 Dec 2019, Ron Frederick wrote:
>
>> 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 to the value 255
>> now, and somewhere along the way the constraint
>> SSH_AGENT_CONSTRAIN_MAXSIGN was defined to use the value 3.
>
> Yes, I had already updated the I-D back in July to fix this collision:
> https://tools.ietf.org/html/draft-miller-ssh-agent-03 <https://tools.ietf.org/html/draft-miller-ssh-agent-03>

Ah, thanks. Is the MAXSIGN constraint defined anywhere?

>> 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:
>>
>> <snip>
>
> I don't think that's quite right as it has the pubkey/cert expanded rather
> than encoded in a string - for all certificates, including sk-* the wire
> format for private keys should be:
>
> string key type
> string public key (including certificate data)
> ... private key fields
>
> E.g.
>
> string "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
> string pubkey
> string application
> uint8 flags
> string key_handle
> string reserved

You’re right - I was focusing on what the additional fields were when I wrote that (which aren’t wrapped in a string), but missed the fact that the prior public key or cert data is.


> You're correct that this is not documented in PROTOCOL.u2f. I'll update
> that now.

Thanks!


>> 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.
>
> Yeah, application is accidentally repeated. I don't think that I'll touch
> it for now, unless there is some other change that requires changing the
> serialisation format.

I’m fine either way on this, but it isn’t just the application. In the Ed25519 case, it’s both the public key and application fields that end up being repeated. It would be nice if both of these cases could be made consistent, with the appended data being only the flags, key_handle, and reserved values from the private key, skipping over the fields present in the public key in both cases. Right now, you skip over the curve name and Q values in the ECDSA case, but not the application, and you don’t skip over any of the values from the public key in the Ed25519 case.
--
Ron Frederick
ronf@timeheart.net



_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev