[PATCH 2/2] engine: add "any" engine mechanism and make it the default

James Bottomley James.Bottomley at HansenPartnership.com
Fri Jan 31 02:24:02 AEDT 2020


If openssl cannot load the private key, chances are it's an engine key
(or a corrupt file), so try processing it via all the available
openssl engines first before concluding corruption.  The reason for
doing this is to make the -o <engine> specifier optional, which means
that gnome-keyring-daemon can treat engine based openssh keys in
exactly the same way as it does ordinary ones.  Not specifying the
engine does incur some overhead in finding exactly which engine
handles the key, but most installations only have a small number of
engines available, so it's not really noticeable.

Signed-off-by: James Bottomley <James.Bottomley at HansenPartnership.com>
---
 ssh-add.c    |  8 ++++++++
 ssh-engine.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/ssh-add.c b/ssh-add.c
index e988023a7..92c324740 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -259,6 +259,14 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
 	/* At first, try empty passphrase */
 	if ((r = sshkey_parse_private_fileblob(keyblob, "", &private,
 	    &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
+		int n_r = add_engine_key(agent_fd, filename, "any");
+		if (n_r == SSH_AGENT_SUCCESS) {
+			clear_pass();
+			sshbuf_free(keyblob);
+			return 0;
+		} else if (n_r != SSH_ERR_INTERNAL_ERROR) {
+			r = n_r;
+		}
 		fprintf(stderr, "Error loading key \"%s\": %s\n",
 		    filename, ssh_err(r));
 		goto fail_load;
diff --git a/ssh-engine.c b/ssh-engine.c
index 90150c543..b13f9e298 100644
--- a/ssh-engine.c
+++ b/ssh-engine.c
@@ -37,29 +37,23 @@ ui_read(UI *ui, UI_STRING *uis)
 	return d->ret;
 }
 
-int
-engine_process_add(char *engine, char *file, char *pin,
-		   struct sshkey **k)
+static int
+engine_process_add_internal(ENGINE *e, char *file, char *pin,
+			    struct sshkey **k)
 {
 	EVP_PKEY *pk;
-	ENGINE *e;
 	struct sshkey *key;
 	int ret;
 	UI_METHOD *ui;
 	EVP_PKEY_CTX *ctx;
 	char hash[SHA256_DIGEST_LENGTH], result[1024];
 	size_t siglen;
+	const char *engine = ENGINE_get_name(e);
 	struct ui_data d;
 
 	verbose("%s: add provider=%s, key=%s", __func__, engine, file);
 
 	ret = SSH_ERR_INTERNAL_ERROR;
-	e = ENGINE_by_id(engine);
-	if (!e) {
-		verbose("%s: failed to get engine %s", __func__, engine);
-		ERR_print_errors_fp(stderr);
-		return ret;
-	}
 
 	ui = UI_create_method("ssh-agent password writer");
 	if (!ui) {
@@ -152,3 +146,40 @@ engine_process_add(char *engine, char *file, char *pin,
 	verbose("%s: returning %d", __func__, ret);
 	return ret;
 }
+
+int
+engine_process_add(char *engine, char *file, char *pin,
+		   struct sshkey **k)
+{
+	ENGINE *e;
+
+	if (strcmp(engine, "any") != 0) {
+		int ret;
+
+		e = ENGINE_by_id(engine);
+		if (!e) {
+			verbose("%s: failed to get engine %s", __func__, engine);
+			ERR_print_errors_fp(stderr);
+			return SSH_ERR_INTERNAL_ERROR;
+		}
+		ret =  engine_process_add_internal(e, file, pin, k);
+		ENGINE_free(e);
+		return ret;
+	}
+
+	/* this is the any engine case */
+
+	for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) {
+		int ret;
+
+		if (!ENGINE_get_load_privkey_function(e))
+			continue;
+
+		ret = engine_process_add_internal(e, file, pin, k);
+
+		if (ret == 1 || ret == SSH_ERR_KEY_WRONG_PASSPHRASE)
+			return ret;
+	}
+
+	return SSH_ERR_INTERNAL_ERROR;
+}
-- 
2.16.4



More information about the openssh-unix-dev mailing list