double length prefix in ssh-keygen certificates (values of critical options)

Damien Miller djm at mindrot.org
Fri Apr 24 16:11:49 AEST 2015


On Thu, 23 Apr 2015, Dmitry Savintsev wrote:

> Hi,
> 
> I have a question regarding the binary format of the certificates generated
> with ssh-keygen, in particular when the critical options of source-address
> or force-command are present and the correspondence to the certificate
> format specifications such as
> http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
> .
> 
> It appears that the string values of the source-address and force-command
> are prepended with *two* length offsets - 4-byte offset with the integer
> value of len(string)+4 followed by the 4-byte offset with the proper
> length, and then the string.  Is it a correct behavior?

Yes, as per PROTOCOL.certkeys:

> The critical options section of the certificate specifies zero or more
> options on the certificates validity. The format of this field
> is a sequence of zero or more tuples:
> 
>     string       name
>     string       data

So that's the first header for the data. You then have to look at the
table to determine the format of data's contents. E.g.

> force-command           string        Specifies a command that is executed
...

So, for name=force-command, the contents of the data buffer are a string.
That's the second header.

The intent is to support options/extensions with data types other
than string, e.g. integers or arrays of string.

> This apparent deviation (unless I misread the spec, of course!) creates
> problems in terms of interoperability with other tools.  Go ssh library (
> https://godoc.org/golang.org/x/crypto/ssh), for example, does not do the
> "double-wrapping", and as a result, you cannot read the certificates
> generated with Go using ssh-keygen -L -f <filename>.  ssh-keygen tries to
> read the first 4 bytes of the string value as the second length offset and
> of course things quickly go south. Here's a hexdump of the certificate
> generated with Go around the critical options section.

Go's implementation is incorrect here.

Maybe the wording of PROTOCOL.certkeys could be improved to avoid
the confusion, but I'm surprised the Go SSH developers didn't check
against what OpenSSH actually generates (or ask if in doubt).

-d


More information about the openssh-unix-dev mailing list