Skip to content

hiba-ca.sh: certificate extensions not in lexical order, breaks Go SSH client parsing #69

@nkrishk

Description

@nkrishk

Summary

hiba-ca.sh generates user certificates with extensions that are not in lexical order, violating the OpenSSH PROTOCOL.certkeys specification. This causes Go's x/crypto/ssh library to reject the certificate during parsing.

OpenSSH Spec Requirement

The OpenSSH PROTOCOL.certkeys spec mandates that certificate extensions must be lexically ordered:

Critical options section:
Options must be lexically ordered by "name" if they appear in the sequence. Each named option may only appear once in a certificate.

Extensions section:
The encoding and ordering of extensions in this field is identical to that of the critical options, as is the requirement that each name appear only once.

Problem

When hiba-ca.sh signs a user certificate, ssh-keygen embeds the following default extensions:

  1. permit-agent-forwarding
  2. permit-port-forwarding
  3. permit-pty
  4. permit-user-rc
  5. permit-X11-forwarding

The HIBA extension (extension:grant@hibassh.dev=...) is then appended via the -O flag. The resulting certificate contains extensions in this order:

permit-agent-forwarding <-- default
permit-port-forwarding <-- default
permit-pty <-- default
permit-user-rc <-- default
permit-X11-forwarding <-- default
grant@hibassh.dev[...] <-- added by hiba-ca.sh

While extension:grant@hibassh.dev lexically precedes all permit-* extensions, ssh-keygen does not guarantee the final ordering when mixing built-in defaults with custom extensions added via -O. The resulting certificate may have extensions out of lexical order.

Impact

Go's x/crypto/ssh library (v0.50.0, used in featureprofiles go.mod) strictly enforces the lexical ordering in parseTuples():

// according to [PROTOCOL.certkeys], the names must be in
// lexical order.
if haveLastKey && keyStr <= lastKey {
    return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
}

When parsing the certificate, the Go SSH client fails with:

ssh: certificate options are not in lexical order

This error propagates up through ssh.ParseAuthorizedKey() as:

illegal base64 data at input byte 8

Note: OpenSSH's own ssh client is more lenient and does not enforce lexical ordering during parsing, so the same certificate works fine with the ssh CLI but fails with Go-based SSH clients.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions