Having read the ssh-keygen man page, i saw the '-h' flag and the following:

ssh-keygen supports two types of certificates: user and host. User certificates authenticate users to servers, whereas host certificates authenticate server hosts to users

I understand the server/client usage, the different storage locations and the certificates are unique, but is there a fundamentally difference?

I.e. If I don't use the '-h' flag during host key generation, have I made an error that could cause issues?

  • 1
  • Had put together an answer, then saw @gowenfawr 's comment. I'd say that it is a duplicate and the link they posted holds the answer for the OP.
    – user53693
    May 31 '19 at 11:17
  • I'd say it's not exactly a duplicate, as the linked question asks what the difference between both files is, while this question asks if you can use them interchangably.
    – MechMK1
    May 31 '19 at 11:19
  • 1
    Retracting my close vote because @MechMK1 came up with an answer that succinctly, differently, and validly answers this question as opposed to the possible dupe. Kudos :)
    – gowenfawr
    May 31 '19 at 11:22
  • Another fair comment from @MechMK1, as I was reading more the spirit of the question rather than the actual question.
    – user53693
    May 31 '19 at 12:00

According to the source code of openssh-portable, the -h flag modifies the certificate type and selects permitted options to None.

Here is the relevant source code:

/* Key type when certifying */
static u_int cert_key_type = SSH2_CERT_TYPE_USER; // L105

/* If -h is set, set certificate type to Host and set cert flags to none. */
case 'h': // L2573
    cert_key_type = SSH2_CERT_TYPE_HOST;
    certflags_flags = 0;

/* Set the certificate type to whatever value was set before */
public->cert->type = cert_key_type; // L1744

As you can see, that's all the magic. If you used the wrong certificate type, then the verifying end will refuse to accept the certificate, as it was not signed for that purpose. You can't use a client certificate to identify as server, and you can't use a server certificate to authenticate as client. You can however use the same key to create both a client and a server certificate.

As it turns out, you can indeed use a client certificate for purposes of host identification, and vice versa. This seems to me like a bug.

  • I've looked deeper based on your info and did some testing, the certs are interchangeable but host certs disable some functions such as port forwarding (L118 & L1583). My 1st post, so don't want to cause trouble editing your answer with a slightly different answer that you may not agree with.
    – PAihGKy0W
    May 31 '19 at 13:15
  • @PAihGKy0W No no, feel free to edit or downvote if it is wrong. I'm glad I could send you into the right direction, even if my conclusion was wrong. It just seems...odd that openssh would allow a client certificate being used as a host certificate. Seems like a bug to me.
    – MechMK1
    May 31 '19 at 13:17
  • 1
    Agreed, never thought to sudo ssh -i <host key location>, but it works.
    – PAihGKy0W
    May 31 '19 at 13:30
  • @PAihGKy0W You should open a bug report.
    – MechMK1
    May 31 '19 at 15:51

Thanks for the hint @MechMK1. It looks like the certificates as interchangeable from my testing, but client certificates have more functionality.

It seems to control the following areas:

/* Certificate options */
#define CERTOPT_X_FWD   (1) // L118
#define CERTOPT_AGENT_FWD   (1<<1)
#define CERTOPT_PORT_FWD    (1<<2)
#define CERTOPT_PTY     (1<<3)
#define CERTOPT_USER_RC (1<<4)
static u_int32_t certflags_flags = CERTOPT_DEFAULT;

if ((which & OPTIONS_EXTENSIONS) != 0 && // L1583
    (certflags_flags & CERTOPT_X_FWD) != 0)
    add_flag_option(c, "permit-X11-forwarding");
if ((which & OPTIONS_EXTENSIONS) != 0 &&
    (certflags_flags & CERTOPT_AGENT_FWD) != 0)
    add_flag_option(c, "permit-agent-forwarding");
if ((which & OPTIONS_EXTENSIONS) != 0 &&
    (certflags_flags & CERTOPT_PORT_FWD) != 0)
    add_flag_option(c, "permit-port-forwarding");
if ((which & OPTIONS_EXTENSIONS) != 0 &&
    (certflags_flags & CERTOPT_PTY) != 0)
    add_flag_option(c, "permit-pty");
if ((which & OPTIONS_EXTENSIONS) != 0 &&
    (certflags_flags & CERTOPT_USER_RC) != 0)
    add_flag_option(c, "permit-user-rc");

A host certificate would disable the above options, limiting those functions to user certificates only.

This is a bit deep for me, but that's how I currently see it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.