Re: anyone using certificates with an empty principals section?

Ashutosh Ghosh via openssh-unix-dev <[email protected]>
Newsgroups gmane.network.openssh.devel
Message-ID <[email protected]>
Hi,

I'm very late to this party, sorry! I have been using host certificates with empty principals and today I got the first user with an OpenSSH 10.3 client report an issue (I think macOS 26.6 released a few days ago is bundling OpenSSH 10.3p1).

I think the way this patch is implemented makes it impossible to have a backwards compatible host certificate. If I set the principals to "*", then a pre-10.3 client will not accept it; if I don't set it to "*" for a wildcard certificate then a post-10.3 client will not accept it.

For my use case, the hostname and IP address are not stable so I don't have a way to express the set of valid hostnames in advance. 

Am I missing something? Is there a way to issue a certificate that is effectively a wildcard for both old and new clients?

A last resort that I don't want to do is issue every host 2 certificates - one with an empty principals and one with "*" principals.

Cheers,
Ashutosh

On 15/12/2025, 16:24, "Damien Miller" <djm mindrot ! org> wrote:

On Wed, 26 Nov 2025, Damien Miller wrote:

> Hi,
>
> Is anyone on here using certificates with an empty principals section?
> If so then I'd like to hear from you.
>
> These were originally documented as being wildcard, i.e. matching any
> principal, though this was supported only inconsistently and AFAIK
> only for host certificates and not user certificates.
>
> IMO this behaviour is a footgun and I'd like to remove it.
> Specifically this would mean making certificates without a principals
> section never usable for anything.
>
> To make it possible to do wildcard host certificates, I'd like to
> add the ability to do explicit wildcards using '*' characters in
> principals, e.g. "*.example.com".
>
> This would be a breaking change if you're depending on the existing
> behaviour.

Here's a diff to implement this:

commit 02bd6acbbf146b89e1d5f0a1ffb427d56df99024
Author: Damien Miller <[email protected]>
Date:   Thu Nov 20 10:52:29 2025 +1100

    ban empty principals, allow wildcard hostnames

diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index d264913..a26bfaa 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -210,8 +210,8 @@ hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
}
debug2_f("access allowed by auth_rhosts2");

- if (sshkey_is_cert(key) &&
-     sshkey_cert_check_authority_now(key, 1, 0, 0, lookup, &reason)) {
+ if (sshkey_is_cert(key) && sshkey_cert_check_host(key, lookup,
+      options.ca_sign_algorithms, &reason) != 0) {
if ((fp = sshkey_fingerprint(key->cert->signature_key,
    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint fail");
diff --git a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c
index b580b89..4a109e6 100644
--- a/auth2-pubkeyfile.c
+++ b/auth2-pubkeyfile.c
@@ -363,7 +363,7 @@ auth_check_authkey_line(struct passwd *pw, struct sshkey *key,
reason = "Certificate does not contain an authorized principal";
goto cert_fail_reason;
}
- if (sshkey_cert_check_authority_now(key, 0, 0, 0,
+ if (sshkey_cert_check_authority_now(key, 0, 1, 0,
    keyopts->cert_principals == NULL ? pw->pw_name : NULL,
    &reason) != 0)
goto cert_fail_reason;
diff --git a/ssh-agent.c b/ssh-agent.c
index ebb573b..500acd1 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -389,7 +389,7 @@ match_key_hop(const char *tag, const struct sshkey *key,
return -1; /* shouldn't happen */
if (!sshkey_equal(key->cert->signature_key, dch->keys[i]))
continue;
- if (sshkey_cert_check_host(key, hostname, 1,
+ if (sshkey_cert_check_host(key, hostname,
    SSH_ALLOWED_CA_SIGALGS, &reason) != 0) {
debug_f("cert %s / hostname %s rejected: %s",
    key->cert->key_id, hostname, reason);
diff --git a/sshconnect.c b/sshconnect.c
index bd1359a..3d133c7 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1054,7 +1054,7 @@ check_host_key(char *hostname, const struct ssh_conn_info *cinfo,
if (want_cert) {
if (sshkey_cert_check_host(host_key,
    options.host_key_alias == NULL ?
-     hostname : options.host_key_alias, 0,
+     hostname : options.host_key_alias,
    options.ca_sign_algorithms, &fail_reason) != 0) {
error("%s", fail_reason);
goto fail;
diff --git a/sshkey.c b/sshkey.c
index 08425ad..91ce2f4 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -2418,12 +2418,11 @@ sshkey_cert_check_authority_now(const struct sshkey *k,

int
sshkey_cert_check_host(const struct sshkey *key, const char *host,
-    int wildcard_principals, const char *ca_sign_algorithms,
-    const char **reason)
+    const char *ca_sign_algorithms, const char **reason)
{
int r;

- if ((r = sshkey_cert_check_authority_now(key, 1, 0, wildcard_principals,
+ if ((r = sshkey_cert_check_authority_now(key, 1, 1, 1,
    host, reason)) != 0)
return r;
if (sshbuf_len(key->cert->critical) != 0) {
diff --git a/sshkey.h b/sshkey.h
index a83ddfe..3a0a32b 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -217,7 +217,7 @@ int sshkey_cert_check_authority(const struct sshkey *, int, int, int,
int sshkey_cert_check_authority_now(const struct sshkey *, int, int, int,
     const char *, const char **);
int sshkey_cert_check_host(const struct sshkey *, const char *,
-    int , const char *, const char **);
+    const char *, const char **);
size_t sshkey_format_cert_validity(const struct sshkey_cert *,
     char *, size_t) __attribute__((__bounded__(__string__, 2, 3)));
int sshkey_check_cert_sigtype(const struct sshkey *, const char *);
_______________________________________________
openssh-unix-dev mailing list
[email protected]
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.