From f5daf40e6bcb932a72665c7df03ab4b5e4950e3b Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 2 Apr 2026 07:48:13 +0000 Subject: sshd(8): fix inappropriate matching of authorized_keys principals When matching an authorized_keys principals="" option against a list of principals in a certificate, an incorrect algorithm was used that could allow inappropriate matching in cases where a principal name in the certificate contains a comma character. Exploitation of the condition requires an authorized_keys principals="" option that lists more than one principal *and* a CA that will issue a certificate that encodes more than one of these principal names separated by a comma (typical CAs strongly constrain which principal names they will place in a certificate). This condition only applies to user- trusted CA keys in authorized_keys, the main certificate authentication path (TrustedUserCAKeys/AuthorizedPrincipalsFile) is not affected. Reported by Vladimir Tokarev. OpenBSD-Commit-ID: c790e2687c35989ae34a00e709be935c55b16a86 [cjwatson: Committed upstream together with apparently-unrelated changes for CVE-2026-35387. I've split them into separate patches for clarity.] Upstream: https://salsa.debian.org/ssh-team/openssh/-/blob/bookworm/debian/patches/CVE-2026-35414.patch Upstream: https://anongit.mindrot.org/openssh.git/commit/?id=fd1c7e131f331942d20f42f31e79912d570081fa CVE: CVE-2026-35414 Signed-off-by: Thomas Perale --- auth2-pubkeyfile.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c index 0cfacac35..6b757e55b 100644 --- a/auth2-pubkeyfile.c +++ b/auth2-pubkeyfile.c @@ -50,6 +50,7 @@ #include "authfile.h" #include "match.h" #include "ssherr.h" +#include "xmalloc.h" int auth_authorise_keyopts(struct passwd *pw, struct sshauthopt *opts, @@ -146,20 +147,23 @@ auth_authorise_keyopts(struct passwd *pw, struct sshauthopt *opts, static int match_principals_option(const char *principal_list, struct sshkey_cert *cert) { - char *result; + char *list, *olist, *entry; u_int i; - /* XXX percent_expand() sequences for authorized_principals? */ - - for (i = 0; i < cert->nprincipals; i++) { - if ((result = match_list(cert->principals[i], - principal_list, NULL)) != NULL) { - debug3("matched principal from key options \"%.100s\"", - result); - free(result); - return 1; + olist = list = xstrdup(principal_list); + for (;;) { + if ((entry = strsep(&list, ",")) == NULL || *entry == '\0') + break; + for (i = 0; i < cert->nprincipals; i++) { + if (strcmp(entry, cert->principals[i]) == 0) { + debug3("matched principal from key i" + "options \"%.100s\"", entry); + free(olist); + return 1; + } } } + free(olist); return 0; }