Multiple allowed signer files in `ssh-keygen -Y verify`

Damien Miller djm at mindrot.org
Tue Apr 29 12:58:53 AEST 2025


On Wed, 23 Apr 2025, Wiktor Kwapisiewicz via openssh-unix-dev wrote:

> Hello,
> 
> I'm currently evaluating using `ssh-keygen -Y verify` to check OS artifacts
> (e.g. packages) and I noticed that the `-f allowed_signers_file` option can be
> passed only once. A side remark: technically it can be passed multiple times
> without a warning but the last invocation overrides all previous ones. Tested
> using:
> 
> $ ssh-keygen -Y verify -f allowed_signers -f /dev/null -n file -s
> statement.txt.sig -I wiktor at metacode.biz < statement.txt
> Could not verify signature.
> 
> While this works (note the order of -f's):
> 
> $ ssh-keygen -Y verify -f /dev/null -f allowed_signers -n file -s
> statement.txt.sig -I wiktor at metacode.biz < statement.txt
> Good "file" signature for wiktor at metacode.biz with RSA key
> SHA256:xb+QgBmoSdveobEdwKqUb3BCk9SLJVxq3Ltu2o/FK7U
> 
> This is a little bit limiting since it doesn't allow splitting the signers
> file into multiple locations that may be managed independently. For example: a
> distro's keys file would be managed by a system package while additional
> user/local keys could be in a separate one, managed by the system
> administrator / end user.
> 
> Of course, this could be workarounded by careful concatenation of files before
> passing them to "verify" (inserting newlines between files etc.).
> 
> Just for comparison the Stateless OpenPGP CLI spec allows passing multiple
> CERTS files [0] directly in the command-line.
> 
> A similar problem appears in the "File Hierarchy for the Verification of OS
> Artifacts (VOA)" draft specification [1] which suggests putting each key in a
> separate file (CC'ing David, who is leading this).
> 
> In my opinion allowing multiple "-f" files would cleanly solve all these
> issues but I'd like to hear what you think about it and if there are any
> (potentially better) alternatives?

I think it's reasonable to allow multiple allowed signers files. These
patches implement this.

Please take a look to see if I've missed any test cases.

-d

-------------- next part --------------
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 9aac967..0b0587d 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -91,6 +91,10 @@ static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
 static char identity_file[PATH_MAX];
 static int have_identity = 0;
 
+/* Some operations accept multiple files */
+static char **identity_files;
+static size_t nidentity_files;
+
 /* This is set to the passphrase if given on the command line. */
 static char *identity_passphrase = NULL;
 
@@ -2803,16 +2807,17 @@ done:
 
 static int
 sig_verify(const char *signature, const char *sig_namespace,
-    const char *principal, const char *allowed_keys, const char *revoked_keys,
-    char * const *opts, size_t nopts)
+    const char *principal, char **allowed_keys, size_t nallowed_keys,
+    const char *revoked_keys, char * const *opts, size_t nopts)
 {
-	int r, ret = -1;
+	int r, ret = -1, matched = 0;
 	int print_pubkey = 0;
 	struct sshbuf *sigbuf = NULL, *abuf = NULL;
 	struct sshkey *sign_key = NULL;
 	char *fp = NULL;
 	struct sshkey_sig_details *sig_details = NULL;
 	uint64_t verify_time = 0;
+	size_t i;
 
 	if (sig_process_opts(opts, nopts, NULL, &verify_time,
 	    &print_pubkey) != 0)
@@ -2850,9 +2855,23 @@ sig_verify(const char *signature, const char *sig_namespace,
 		}
 	}
 
-	if (allowed_keys != NULL && (r = sshsig_check_allowed_keys(allowed_keys,
-	    sign_key, principal, sig_namespace, verify_time)) != 0) {
-		debug3_fr(r, "sshsig_check_allowed_keys");
+	for (i = 0; i < nallowed_keys; i++) {
+		if ((r = sshsig_check_allowed_keys(allowed_keys[i], sign_key,
+		    principal, sig_namespace, verify_time)) != 0) {
+			/* don't attempt other files on hard errors */
+			if (r != SSH_ERR_KEY_NOT_FOUND) {
+				error_fr(r, "check allowed keys in %s",
+				    allowed_keys[i]);
+				goto done;
+			}
+			debug3_fr(r, "sshsig_check_allowed_keys in %s",
+			    allowed_keys[i]);
+			continue;
+		}
+		matched = 1;
+	}
+	if (!matched && nallowed_keys != 0) {
+		error_f("No key matched in allowed signers file(s)");
 		goto done;
 	}
 	/* success */
@@ -2894,14 +2913,15 @@ done:
 }
 
 static int
-sig_find_principals(const char *signature, const char *allowed_keys,
-    char * const *opts, size_t nopts)
+sig_find_principals(const char *signature, char **allowed_keys_files,
+    size_t nallowed_keys_files, char * const *opts, size_t nopts)
 {
 	int r, ret = -1;
 	struct sshbuf *sigbuf = NULL, *abuf = NULL;
 	struct sshkey *sign_key = NULL;
-	char *principals = NULL, *cp, *tmp;
+	char *principals = NULL, *output = NULL, *cp, *tmp;
 	uint64_t verify_time = 0;
+	size_t i;
 
 	if (sig_process_opts(opts, nopts, NULL, &verify_time, NULL) != 0)
 		goto done; /* error already logged */
@@ -2918,53 +2938,76 @@ sig_find_principals(const char *signature, const char *allowed_keys,
 		error_fr(r, "sshsig_get_pubkey");
 		goto done;
 	}
-	if ((r = sshsig_find_principals(allowed_keys, sign_key,
-	    verify_time, &principals)) != 0) {
-		if (r != SSH_ERR_KEY_NOT_FOUND)
-			error_fr(r, "sshsig_find_principal");
-		goto done;
-	}
-	ret = 0;
-done:
-	if (ret == 0 ) {
-		/* Emit matching principals one per line */
+
+	for (i = 0; i < nallowed_keys_files; i++) {
+		if ((r = sshsig_find_principals(allowed_keys_files[i], sign_key,
+		    verify_time, &principals)) != 0) {
+			/* don't attempt other files on hard errors */
+			if (r != SSH_ERR_KEY_NOT_FOUND) {
+				error_fr(r, "find principals in %s",
+				    allowed_keys_files[i]);
+				goto done;
+			}
+			debug_fr(r, "find principals in %s",
+			    allowed_keys_files[i]);
+			continue;
+		}
+		/* Record matching principals one per line */
 		tmp = principals;
 		while ((cp = strsep(&tmp, ",")) != NULL && *cp != '\0')
-			puts(cp);
-	} else {
-		fprintf(stderr, "No principal matched.\n");
+			xextendf(&output, "\n", "%s", cp);
+		free(principals);
 	}
+	if (output != NULL) {
+		printf("%s\n", output);
+		ret = 0;
+	} else
+		fprintf(stderr, "No principal matched.\n");
+done:
 	sshbuf_free(sigbuf);
 	sshbuf_free(abuf);
 	sshkey_free(sign_key);
-	free(principals);
+	free(output);
 	return ret;
 }
 
 static int
-sig_match_principals(const char *allowed_keys, char *principal,
-	char * const *opts, size_t nopts)
+sig_match_principals(char **allowed_keys, size_t nallowed_keys,
+    char *principal, char * const *opts, size_t nopts)
 {
-	int r;
-	char **principals = NULL;
-	size_t i, nprincipals = 0;
+	int r, ret = -1;
+	char **principals = NULL, *output = NULL;
+	size_t i, j, nprincipals = 0;
 
 	if ((r = sig_process_opts(opts, nopts, NULL, NULL, NULL)) != 0)
 		return r; /* error already logged */
 
-	if ((r = sshsig_match_principals(allowed_keys, principal,
-	    &principals, &nprincipals)) != 0) {
-		debug_f("match: %s", ssh_err(r));
+	for (i = 0; i < nallowed_keys; i++) {
+		if ((r = sshsig_match_principals(allowed_keys[i], principal,
+		    &principals, &nprincipals)) != 0) {
+			/* don't attempt other files on hard errors */
+			if (r != SSH_ERR_KEY_NOT_FOUND) {
+				error_fr(r, "match principals in %s",
+				    allowed_keys[i]);
+				goto done;
+			}
+			debug_fr(r, "match in %s", allowed_keys[i]);
+			continue;
+		}
+		for (j = 0; j < nprincipals; j++) {
+			xextendf(&output, "\n", "%s", principals[j]);
+			free(principals[j]);
+		}
+		free(principals);
+	}
+	if (output != NULL) {
+		printf("%s\n", output);
+		ret = 0;
+	} else
 		fprintf(stderr, "No principal matched.\n");
-		return r;
-	}
-	for (i = 0; i < nprincipals; i++) {
-		printf("%s\n", principals[i]);
-		free(principals[i]);
-	}
-	free(principals);
-
-	return 0;
+ done:
+	free(output);
+	return ret;
 }
 
 static void
@@ -3478,6 +3521,11 @@ main(int argc, char **argv)
 			    sizeof(identity_file)) >= sizeof(identity_file))
 				fatal("Identity filename too long");
 			have_identity = 1;
+			/* Some operations accept multiple filenames */
+			identity_files = xrecallocarray(identity_files,
+			    nidentity_files, nidentity_files + 1,
+			    sizeof(*identity_files));
+			identity_files[nidentity_files++] = xstrdup(optarg);
 			break;
 		case 'g':
 			print_generic = 1;
@@ -3608,17 +3656,17 @@ main(int argc, char **argv)
 	if (sign_op != NULL) {
 		if (strncmp(sign_op, "find-principals", 15) == 0) {
 			if (ca_key_path == NULL) {
-				error("Too few arguments for find-principals:"
+				fatal("Too few arguments for find-principals:"
 				    "missing signature file");
 				exit(1);
 			}
 			if (!have_identity) {
-				error("Too few arguments for find-principals:"
+				fatal("Too few arguments for find-principals:"
 				    "missing allowed keys file");
 				exit(1);
 			}
-			return sig_find_principals(ca_key_path, identity_file,
-			    opts, nopts);
+			return sig_find_principals(ca_key_path, identity_files,
+			    nidentity_files, opts, nopts);
 		} else if (strncmp(sign_op, "match-principals", 16) == 0) {
 			if (!have_identity) {
 				error("Too few arguments for match-principals:"
@@ -3630,8 +3678,8 @@ main(int argc, char **argv)
 				    "missing principal ID");
 				exit(1);
 			}
-			return sig_match_principals(identity_file, cert_key_id,
-			    opts, nopts);
+			return sig_match_principals(identity_files,
+			    nidentity_files, cert_key_id, opts, nopts);
 		} else if (strncmp(sign_op, "sign", 4) == 0) {
 			/* NB. cert_principals is actually namespace, via -n */
 			if (cert_principals == NULL ||
@@ -3645,6 +3693,10 @@ main(int argc, char **argv)
 				    "missing key");
 				exit(1);
 			}
+			if (nidentity_files > 1) {
+				error("Too many keys specified for sign");
+				exit(1);
+			}
 			return sig_sign(identity_file, cert_principals,
 			    prefer_agent, argc, argv, opts, nopts);
 		} else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
@@ -3660,8 +3712,13 @@ main(int argc, char **argv)
 				    "missing signature file");
 				exit(1);
 			}
+			if (nidentity_files > 0) {
+				error("Too many keys specified "
+				    "for check-novalidate");
+				exit(1);
+			}
 			return sig_verify(ca_key_path, cert_principals,
-			    NULL, NULL, NULL, opts, nopts);
+			    NULL, NULL, 0, NULL, opts, nopts);
 		} else if (strncmp(sign_op, "verify", 6) == 0) {
 			/* NB. cert_principals is actually namespace, via -n */
 			if (cert_principals == NULL ||
@@ -3676,7 +3733,7 @@ main(int argc, char **argv)
 				exit(1);
 			}
 			if (!have_identity) {
-				error("Too few arguments for sign: "
+				error("Too few arguments for verify: "
 				    "missing allowed keys file");
 				exit(1);
 			}
@@ -3686,14 +3743,19 @@ main(int argc, char **argv)
 				exit(1);
 			}
 			return sig_verify(ca_key_path, cert_principals,
-			    cert_key_id, identity_file, rr_hostname,
-			    opts, nopts);
+			    cert_key_id, identity_files, nidentity_files,
+			    rr_hostname, opts, nopts);
 		}
 		error("Unsupported operation for -Y: \"%s\"", sign_op);
 		usage();
 		/* NOTREACHED */
 	}
 
+	/* All other operations accept only a single keyfile */
+	if (nidentity_files > 1) {
+		error("Too many keys specified on commandline");
+		exit(1);
+	}
 	if (ca_key_path != NULL) {
 		if (argc < 1 && !gen_krl) {
 			error("Too few arguments.");
-------------- next part --------------
diff --git a/sshsig.sh b/sshsig.sh
index dae0370..1a31ac7 100644
--- a/sshsig.sh
+++ b/sshsig.sh
@@ -6,7 +6,7 @@ tid="sshsig"
 DATA2=$OBJ/${DATANAME}.2
 cat ${DATA} ${DATA} > ${DATA2}
 
-rm -f $OBJ/sshsig-*.sig $OBJ/wrong-key* $OBJ/sigca-key*
+rm -f $OBJ/sshsig-*.sig $OBJ/wrong-key* $OBJ/sigca-key* $OBJ/allowed_signers*
 
 sig_namespace="test-$$"
 sig_principal="user-$$@example.com"
@@ -66,11 +66,22 @@ for t in $SIGNKEYS; do
 		    $hashalg_arg < $DATA > $sigfile 2>/dev/null || \
 			fail "sign using $t / $h failed"
 		(printf "$sig_principal " ; cat $pubkey) > $OBJ/allowed_signers
+		echo "" > $OBJ/allowed_signers.empty
 		trace "$tid: key type $t verify with hash $h"
 		${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
 		    -I $sig_principal -f $OBJ/allowed_signers \
 		    < $DATA >/dev/null 2>&1 || \
 			fail "failed signature for $t / $h key"
+		# Multiple allowed_signers files
+		${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		    -I $sig_principal -f $OBJ/allowed_signers.empty \
+		    -f $OBJ/allowed_signers < $DATA >/dev/null 2>&1 || \
+			fail "failed signature for $t / $h key (multifile)"
+		# Opposite order
+		${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		    -I $sig_principal -f $OBJ/allowed_signers \
+		    -f $OBJ/allowed_signers.empty < $DATA >/dev/null 2>&1 || \
+			fail "failed signature for $t / $h key (multifile2)"
 	done
 
 	trace "$tid: key type $t verify with limited namespace"
@@ -104,10 +115,29 @@ for t in $SIGNKEYS; do
 	# Wrong key trusted.
 	trace "$tid: key type $t verify with wrong key"
 	(printf "$sig_principal " ; cat $WRONG) > $OBJ/allowed_signers
+	(printf "$sig_principal " ; cat $WRONG) > $OBJ/allowed_signers.2
 	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
 		-I $sig_principal -f $OBJ/allowed_signers \
 		< $DATA >/dev/null 2>&1 && \
 		fail "accepted signature for $t key with wrong key trusted"
+	# Multiple files.
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 < $DATA >/dev/null 2>&1 && \
+		fail "accepted signature for $t key with wrong key trusted2"
+
+	# Wrong key in one file shouldn't stop correct key in other working.
+	trace "$tid: key type $t verify with right and wrong keys"
+	(printf "$sig_principal " ; cat $WRONG) > $OBJ/allowed_signers
+	(printf "$sig_principal " ; cat $pubkey) > $OBJ/allowed_signers.2
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 < $DATA >/dev/null 2>&1 || \
+		fail "failed signature for $t key with right+wrong key trusted"
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 < $DATA >/dev/null 2>&1 || \
+		fail "failed signature for $t key with right+wrong key trusted2"
 
 	# incorrect data
 	trace "$tid: key type $t verify with wrong data"
@@ -120,10 +150,37 @@ for t in $SIGNKEYS; do
 	# wrong principal in signers
 	trace "$tid: key type $t verify with wrong principal"
 	(printf "josef.k at example.com " ; cat $pubkey) > $OBJ/allowed_signers
+	(printf "gregor.s at example.com " ; cat $pubkey) > $OBJ/allowed_signers.2
 	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
 		-I $sig_principal -f $OBJ/allowed_signers \
 		< $DATA >/dev/null 2>&1 && \
 		fail "accepted signature for $t key with wrong principal"
+	# Multiple files.
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 < $DATA >/dev/null 2>&1 && \
+		fail "accepted signature for $t key with wrong principal2"
+
+	# Right and wrong principals in same file.
+	trace "$tid: key type $t verify with right and wrong principal"
+	(printf "josef.k at example.com " ; cat $pubkey) > $OBJ/allowed_signers
+	(printf "$sig_principal " ; cat $pubkey) >> $OBJ/allowed_signers
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		< $DATA >/dev/null 2>&1 || \
+		fail "failed signature for $t key with right/wrong principal"
+	# Same but across different files.
+	(printf "josef.k at example.com " ; cat $pubkey) > $OBJ/allowed_signers
+	(printf "$sig_principal " ; cat $pubkey) > $OBJ/allowed_signers.2
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 < $DATA >/dev/null 2>&1 || \
+		fail "failed signature for $t key with right/wrong principal2"
+	# Opposite ordering.
+	${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+		-I $sig_principal -f $OBJ/allowed_signers.2 \
+		-f $OBJ/allowed_signers < $DATA >/dev/null 2>&1 || \
+		fail "failed signature for $t key with right/wrong principal3"
 
 	# wrong namespace
 	trace "$tid: key type $t verify with wrong namespace"
@@ -174,19 +231,46 @@ for t in $SIGNKEYS; do
 		< $DATA >/dev/null 2>&1 && \
 		fail "failed signature for $t with expired key"
 
-	# key lifespan valid
+	( printf "$sig_principal " ;
+	  printf "valid-after=\"19800101\",valid-before=\"19900101\" " ;
+	  cat $pubkey) > $OBJ/allowed_signers
+	echo "" > $OBJ/allowed_signers.2
+	( printf "$sig_principal " ;
+	  printf "valid-after=\"20000101\",valid-before=\"20100101\" " ;
+	  cat $pubkey) > $OBJ/allowed_signers.3
+
+	# find-principals: principal not found
+	trace "$tid: key type $t find-principals missing"
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19990101" \
+		-f $OBJ/allowed_signers.2 >/dev/null 2>&1 && \
+		fail "passed find-principals for $t missing"
+
+	# find-principals: key lifespan valid
 	trace "$tid: key type $t find-principals with valid lifespan"
 	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
 		-Overify-time="19850101" \
 		-f $OBJ/allowed_signers >/dev/null 2>&1 || \
-		fail "failed find-principals for $t key with valid expiry interval"
-	# key not yet valid
+		fail "failed find-principals for $t key valid expiry interval"
+	# same but multiple files.
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19850101" -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 >/dev/null 2>&1 || \
+		fail "failed find-principals for $t key valid expiry interval2"
+	# opposite order.
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19850101" -f $OBJ/allowed_signers.2 \
+		-f $OBJ/allowed_signers >/dev/null 2>&1 || \
+		fail "failed find-principals for $t key valid expiry interval2"
+
+	# find-principals: key not yet valid
 	trace "$tid: key type $t find principals with not-yet-valid lifespan"
 	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
 		-Overify-time="19790101" \
 		-f $OBJ/allowed_signers >/dev/null 2>&1 && \
 		fail "failed find-principals for $t not-yet-valid key"
-	# key expired
+
+	# find-principals: key expired
 	trace "$tid: key type $t find-principals with expired lifespan"
 	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
 		-Overify-time="19990101" \
@@ -197,6 +281,33 @@ for t in $SIGNKEYS; do
 	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
 		-f $OBJ/allowed_signers >/dev/null 2>&1 && \
 		fail "failed find-principals for $t with expired key"
+	# Multiple files
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19990101" -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.2 >/dev/null 2>&1 && \
+		fail "failed find-principals for $t with expired key2"
+	# opposite order.
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19990101" -f $OBJ/allowed_signers.2 \
+		-f $OBJ/allowed_signers >/dev/null 2>&1 && \
+		fail "failed find-principals for $t with expired key3"
+
+	# find-principals: key expired in one file but not the other
+	trace "$tid: key type $t find-principals with expired lifespan"
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="19990101" -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.3 >/dev/null 2>&1 && \
+		fail "failed find-principals for $t with expired key (multi)"
+	# Valid date
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="20050101" -f $OBJ/allowed_signers \
+		-f $OBJ/allowed_signers.3 >/dev/null 2>&1 || \
+		fail "failed find-principals for $t with expired key (multi2)"
+	# Opposite order.
+	${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \
+		-Overify-time="20050101" -f $OBJ/allowed_signers.3 \
+		-f $OBJ/allowed_signers >/dev/null 2>&1 || \
+		fail "failed find-principals for $t with expired key (multi2)"
 
 	# public key in revoked keys file
 	trace "$tid: key type $t verify with revoked key"
@@ -513,11 +624,22 @@ done
 	printf "princi* " ; cat $pubkey;
 	printf "unique " ; cat $pubkey;
 ) > $OBJ/allowed_signers
+echo > $OBJ/allowed_signers.2
 
 verbose "$tid: match principals"
 ${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers -I "unique" | \
     fgrep "unique" >/dev/null || \
 	fail "failed to match static principal"
+# Multiple files
+${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers \
+    -f $OBJ/allowed_signers.2 -I "unique" | \
+    fgrep "unique" >/dev/null || \
+	fail "failed to match static principal (multi)"
+# Opposite order
+${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers.2 \
+    -f $OBJ/allowed_signers -I "unique" | \
+    fgrep "unique" >/dev/null || \
+	fail "failed to match static principal (multi2)"
 
 trace "$tid: match principals wildcard"
 ${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers -I "princip" | \


More information about the openssh-unix-dev mailing list