Subject: [PATCH v2 5/6] gpg-interface: extract SSH key type from signature status output

From: Christian Couder <[email-masked]>
Date: Mon, 26 May 2025 12:33:13 +0200

A previous commit extracted the hash algorithm from GPG/GPGSM signature
status output and stored it in a new 'sig_algo' member of 'struct
signature_check'.

For SSH signatures, it's more interesting and easier to extract the key
type (like "RSA", "ECDSA", "Ed25519", ...) rather than the hash
algorithm which often depends on the key type. For example "Ed25519"
has SHA-512 integrated into its design, and "ECDSA" and "RSA" are
typically used with SHA-256.

Let's improve the `gpg-interface` parsing logic to capture the SSH key
type when parsing the SSH signature status output.

Similarly as the hash algorithm for GPG/GPGSM signatures, this
information can be useful for Git commands or external tools that
process signature information. For example, it could be used when
displaying signature verification results to users or when working with
various signature formats in tools like fast-export and fast-import.

As they share a common usage, we also store the SSH key type in the new
'sig_algo' member of 'struct signature_check'.

Signed-off-by: Christian Couder <[email-masked]>
---
 gpg-interface.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/gpg-interface.c b/gpg-interface.c
index 15687ede43..182e579769 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -456,11 +456,27 @@ static int verify_gpg_signed_buffer(struct signature_check *sigc,
 	return ret;
 }
 
+static char *extract_ssh_key_type(const char *type_start, const char *type_end)
+{
+	if (!type_end || type_end <= type_start)
+		return NULL;
+
+	/* Back up over any spaces before " key " */
+	while (type_end > type_start && *(type_end - 1) == ' ')
+		type_end--;
+
+	if (type_end <= type_start)
+		return NULL;
+
+	return xmemdupz(type_start, type_end - type_start);
+}
+
 static void parse_ssh_output(struct signature_check *sigc)
 {
 	const char *line, *principal, *search;
 	char *to_free;
 	char *key = NULL;
+	const char *after_last_with = NULL;
 
 	/*
 	 * ssh-keygen output should be:
@@ -485,8 +501,10 @@ static void parse_ssh_output(struct signature_check *sigc)
 		principal = line;
 		do {
 			search = strstr(line, " with ");
-			if (search)
+			if (search) {
 				line = search + 1;
+				after_last_with = search + 6;
+			}
 		} while (search != NULL);
 		if (line == principal)
 			goto cleanup;
@@ -499,6 +517,7 @@ static void parse_ssh_output(struct signature_check *sigc)
 		/* Valid signature, but key unknown */
 		sigc->result = 'G';
 		sigc->trust_level = TRUST_UNDEFINED;
+		after_last_with = line;
 	} else {
 		goto cleanup;
 	}
@@ -507,6 +526,9 @@ static void parse_ssh_output(struct signature_check *sigc)
 	if (key) {
 		sigc->fingerprint = xstrdup(key + 4);
 		sigc->key = xstrdup(sigc->fingerprint);
+
+		if (after_last_with)
+			sigc->sig_algo = extract_ssh_key_type(after_last_with, key);
 	} else {
 		/*
 		 * Output did not match what we expected
-- 
2.49.0.609.g63c55177e5