ssh-add: add no-pin flag

Damien Miller <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
Hi,

Some FIDO and PKCS#11 tokens have alternate ways of entering PINs or
performing PIN-equivalent authentication, such as biometrics and on-
device PIN entry hardware.

To better support these, this adds a ssh-add -P flag to make PIN entry
optional.

ok?

commit 36b8ed7e63a3ad340f590ad846354b2f8bb1b1f1
Author: Damien Miller <[email protected]>
Date:   Mon Nov 20 14:31:22 2023 +1100

    Add -P flag to suppress requesting FIDO/p11 PIN

diff --git a/ssh-add.1 b/ssh-add.1
index af5f8f7..e761d21 100644
--- a/ssh-add.1
+++ b/ssh-add.1
@@ -43,7 +43,7 @@
 .Nd adds private key identities to the OpenSSH authentication agent
 .Sh SYNOPSIS
 .Nm ssh-add
-.Op Fl CcDdKkLlNqvXx
+.Op Fl CcDdKkLlNPqvXx
 .Op Fl E Ar fingerprint_hash
 .Op Fl H Ar hostkey_file
 .Op Fl h Ar destination_constraint
@@ -235,6 +235,11 @@ certificates added to an agent.
 .It Fl Q
 Query the agent for the list of protocol extensions it supports.
 Note: not all agents support this query.
+.It Fl P
+When loading PKCS#11 or FIDO keys from a token, do not request a PIN.
+This will cause the operation to fail if the token requires additional
+authentication and has no other way to obtain it, such as a keypad or
+biometric reader.
 .It Fl q
 Be quiet after a successful operation.
 .It Fl S Ar provider
diff --git a/ssh-add.c b/ssh-add.c
index 2788f7e..2fead57 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -452,7 +452,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only,
 }
 
 static int
-update_card(int agent_fd, int add, const char *id, int qflag,
+update_card(int agent_fd, int add, const char *id, int qflag, int no_pin,
     int key_only, int cert_only,
     struct dest_constraint **dest_constraints, size_t ndest_constraints,
     struct sshkey **certs, size_t ncerts)
@@ -463,7 +463,7 @@ update_card(int agent_fd, int add, const char *id, int qflag,
 	if (key_only)
 		ncerts = 0;
 
-	if (add) {
+	if (add && !no_pin) {
 		if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
 		    RP_ALLOW_STDIN)) == NULL)
 			return -1;
@@ -589,20 +589,24 @@ lock_agent(int agent_fd, int lock)
 }
 
 static int
-load_resident_keys(int agent_fd, const char *skprovider, int qflag,
+load_resident_keys(int agent_fd, const char *skprovider, int qflag, int no_pin,
     struct dest_constraint **dest_constraints, size_t ndest_constraints)
 {
 	struct sshsk_resident_key **srks;
 	size_t nsrks, i;
 	struct sshkey *key;
-	int r, ok = 0;
-	char *fp;
+	int r, ret = -1;
+	char *fp, *pin = NULL;
 
-	pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
-	if ((r = sshsk_load_resident(skprovider, NULL, pass, 0,
-	    &srks, &nsrks)) != 0) {
+	if (!no_pin) {
+		pin = read_passphrase("Enter PIN for authenticator: ",
+		    RP_ALLOW_STDIN);
+	}
+	if ((r = sshsk_load_resident(skprovider, NULL, pin = NULL ? "" : pin,
+	    0, &srks, &nsrks)) != 0) {
 		error_r(r, "Unable to load resident keys");
-		return r;
+		ret = r;
+		goto out;
 	}
 	for (i = 0; i < nsrks; i++) {
 		key = srks[i]->key;
@@ -615,11 +619,9 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag,
 			error("Unable to add key %s %s",
 			    sshkey_type(key), fp);
 			free(fp);
-			ok = r;
+			ret = r;
 			continue;
 		}
-		if (ok == 0)
-			ok = 1;
 		if (!qflag) {
 			fprintf(stderr, "Resident identity added: %s %s\n",
 			    sshkey_type(key), fp);
@@ -633,11 +635,17 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag,
 			}
 		}
 		free(fp);
+		if (ret == -1)
+			ret = 0;
 	}
 	sshsk_free_resident_keys(srks, nsrks);
-	if (nsrks == 0)
-		return SSH_ERR_KEY_NOT_FOUND;
-	return ok == 1 ? 0 : ok;
+	if (nsrks == 0) {
+		fprintf(stderr, "No keys loaded from authenticator\n");
+		ret = SSH_ERR_KEY_NOT_FOUND;
+	}
+ out:
+	free(pin);
+	return ret;
 }
 
 static int
@@ -811,7 +819,7 @@ main(int argc, char **argv)
 	char **dest_constraint_strings = NULL, **hostkey_files = NULL;
 	int r, i, ch, deleting = 0, ret = 0, key_only = 0, cert_only = 0;
 	int do_download = 0, xflag = 0, lflag = 0, Dflag = 0;
-	int Qflag = 0, qflag = 0, Tflag = 0, Nflag = 0;
+	int Qflag = 0, qflag = 0, Tflag = 0, Nflag = 0, no_pin = 0;
 	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
 	LogLevel log_level = SYSLOG_LEVEL_INFO;
 	struct sshkey *k, **certs = NULL;
@@ -840,7 +848,7 @@ main(int argc, char **argv)
 
 	skprovider = getenv("SSH_SK_PROVIDER");
 
-	while ((ch = getopt(argc, argv, "vkKlLNCcdDTxXE:e:h:H:M:m:Qqs:S:t:")) != -1) {
+	while ((ch = getopt(argc, argv, "vkKlLNPCcdDTxXE:e:h:H:M:m:Qqs:S:t:")) != -1) {
 		switch (ch) {
 		case 'v':
 			if (log_level == SYSLOG_LEVEL_INFO)
@@ -893,6 +901,9 @@ main(int argc, char **argv)
 		case 'd':
 			deleting = 1;
 			break;
+		case 'P':
+			no_pin = 1;
+			break;
 		case 'D':
 			Dflag = 1;
 			break;
@@ -988,7 +999,7 @@ main(int argc, char **argv)
 		}
 		debug2_f("loaded %zu certificates", ncerts);
 		if (update_card(agent_fd, !deleting, pkcs11provider,
-		    qflag, key_only, cert_only,
+		    qflag, no_pin, key_only, cert_only,
 		    dest_constraints, ndest_constraints,
 		    certs, ncerts) == -1)
 			ret = 1;
@@ -1000,7 +1011,7 @@ main(int argc, char **argv)
 	if (do_download) {
 		if (skprovider == NULL)
 			fatal("Cannot download keys without provider");
-		if (load_resident_keys(agent_fd, skprovider, qflag,
+		if (load_resident_keys(agent_fd, skprovider, qflag, no_pin,
 		    dest_constraints, ndest_constraints) != 0)
 			ret = 1;
 		goto done;
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.