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

Dmitry Savintsev dsavints at
Fri Apr 24 19:57:19 AEST 2015

Thanks Damien for your response and explanations - I opened to improve the wording
the PROTOCOL.certkeys spec.

Currently reading that the format the critical options field is a sequence
of tuples:
>     string       name
>     string       data

I would expect both fields to have the same encoding since they have the
same type "string" (and also by analogy with multiple other string fields
in the specification).  Do you think it would be worth to give the second
field of the tuple some other type like "object" or "composite" or string[]
- especially since you say the intent is to support "data types other than
string, e.g. integers or arrays of string"?
uses the type string[] for the list of strings (as in: "    string[]
hostkeys") which makes it clear that the field has different semantics and
encoding than a "plain" string one.

I opened an issue for Go's crypto/ssh library:



On Fri, Apr 24, 2015 at 8:11 AM, Damien Miller <djm at> wrote:

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