anyone using certificates with an empty principals section?

Damien Miller djm at mindrot.org
Tue Dec 16 11:24:14 AEDT 2025


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 <djm at mindrot.org>
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 *);


More information about the openssh-unix-dev mailing list