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
    Commented May 31, 2019 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.
    – user163495
    Commented May 31, 2019 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
    Commented May 31, 2019 at 11:22
  • Another fair comment from @MechMK1, as I was reading more the spirit of the question rather than the actual question.
    – user53693
    Commented May 31, 2019 at 12:00

2 Answers 2


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
    Commented May 31, 2019 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.
    – user163495
    Commented May 31, 2019 at 13:17
  • 1
    Agreed, never thought to sudo ssh -i <host key location>, but it works.
    – PAihGKy0W
    Commented May 31, 2019 at 13:30
  • @PAihGKy0W You should open a bug report.
    – user163495
    Commented May 31, 2019 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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .