]> git.ipfire.org Git - thirdparty/git.git/commitdiff
ssh signing: provide a textual signing_key_id
authorFabian Stelzer <fs@gigacodes.de>
Fri, 10 Sep 2021 20:07:38 +0000 (20:07 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Sep 2021 21:15:52 +0000 (14:15 -0700)
For ssh the user.signingkey can be a filename/path or even a literal ssh pubkey.
In push certs and textual output we prefer the ssh fingerprint instead.

Signed-off-by: Fabian Stelzer <fs@gigacodes.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
gpg-interface.c
gpg-interface.h
send-pack.c

index 3a0cca1b1d21093406efdb0153b20dc87e7f27d2..0f1c6a02e53257b09042178effbd7bd7ce14909b 100644 (file)
@@ -24,6 +24,7 @@ struct gpg_format {
        int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
                           const char *signing_key);
        const char *(*get_default_key)(void);
+       const char *(*get_key_id)(void);
 };
 
 static const char *openpgp_verify_args[] = {
@@ -61,6 +62,8 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
 
 static const char *get_default_ssh_signing_key(void);
 
+static const char *get_ssh_key_id(void);
+
 static struct gpg_format gpg_format[] = {
        {
                .name = "openpgp",
@@ -70,6 +73,7 @@ static struct gpg_format gpg_format[] = {
                .verify_signed_buffer = verify_gpg_signed_buffer,
                .sign_buffer = sign_buffer_gpg,
                .get_default_key = NULL,
+               .get_key_id = NULL,
        },
        {
                .name = "x509",
@@ -79,6 +83,7 @@ static struct gpg_format gpg_format[] = {
                .verify_signed_buffer = verify_gpg_signed_buffer,
                .sign_buffer = sign_buffer_gpg,
                .get_default_key = NULL,
+               .get_key_id = NULL,
        },
        {
                .name = "ssh",
@@ -88,6 +93,7 @@ static struct gpg_format gpg_format[] = {
                .verify_signed_buffer = NULL, /* TODO */
                .sign_buffer = sign_buffer_ssh,
                .get_default_key = get_default_ssh_signing_key,
+               .get_key_id = get_ssh_key_id,
        },
 };
 
@@ -484,6 +490,41 @@ int git_gpg_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
+static char *get_ssh_key_fingerprint(const char *signing_key)
+{
+       struct child_process ssh_keygen = CHILD_PROCESS_INIT;
+       int ret = -1;
+       struct strbuf fingerprint_stdout = STRBUF_INIT;
+       struct strbuf **fingerprint;
+
+       /*
+        * With SSH Signing this can contain a filename or a public key
+        * For textual representation we usually want a fingerprint
+        */
+       if (starts_with(signing_key, "ssh-")) {
+               strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf", "-", NULL);
+               ret = pipe_command(&ssh_keygen, signing_key,
+                                  strlen(signing_key), &fingerprint_stdout, 0,
+                                  NULL, 0);
+       } else {
+               strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf",
+                            configured_signing_key, NULL);
+               ret = pipe_command(&ssh_keygen, NULL, 0, &fingerprint_stdout, 0,
+                                  NULL, 0);
+       }
+
+       if (!!ret)
+               die_errno(_("failed to get the ssh fingerprint for key '%s'"),
+                         signing_key);
+
+       fingerprint = strbuf_split_max(&fingerprint_stdout, ' ', 3);
+       if (!fingerprint[1])
+               die_errno(_("failed to get the ssh fingerprint for key '%s'"),
+                         signing_key);
+
+       return strbuf_detach(fingerprint[1], NULL);
+}
+
 /* Returns the first public key from an ssh-agent to use for signing */
 static const char *get_default_ssh_signing_key(void)
 {
@@ -532,6 +573,21 @@ static const char *get_default_ssh_signing_key(void)
        return default_key;
 }
 
+static const char *get_ssh_key_id(void) {
+       return get_ssh_key_fingerprint(get_signing_key());
+}
+
+/* Returns a textual but unique representation of the signing key */
+const char *get_signing_key_id(void)
+{
+       if (use_format->get_key_id) {
+               return use_format->get_key_id();
+       }
+
+       /* GPG/GPGSM only store a key id on this variable */
+       return get_signing_key();
+}
+
 const char *get_signing_key(void)
 {
        if (configured_signing_key)
index feac4decf8b79f81435a87aba502b1d42e0cee6a..beefacbb1e9025b8d65a83aea74c6ce3913535cd 100644 (file)
@@ -64,6 +64,12 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
 int git_gpg_config(const char *, const char *, void *);
 void set_signing_key(const char *);
 const char *get_signing_key(void);
+
+/*
+ * Returns a textual unique representation of the signing key in use
+ * Either a GPG KeyID or a SSH Key Fingerprint
+ */
+const char *get_signing_key_id(void);
 int check_signature(const char *payload, size_t plen,
                    const char *signature, size_t slen,
                    struct signature_check *sigc);
index 5a79e0e711031907bcec04acc18a64c2b9d40adc..50cca7e439b34b78b9d26fc845de967cbf20bad5 100644 (file)
@@ -341,13 +341,13 @@ static int generate_push_cert(struct strbuf *req_buf,
 {
        const struct ref *ref;
        struct string_list_item *item;
-       char *signing_key = xstrdup(get_signing_key());
+       char *signing_key_id = xstrdup(get_signing_key_id());
        const char *cp, *np;
        struct strbuf cert = STRBUF_INIT;
        int update_seen = 0;
 
        strbuf_addstr(&cert, "certificate version 0.1\n");
-       strbuf_addf(&cert, "pusher %s ", signing_key);
+       strbuf_addf(&cert, "pusher %s ", signing_key_id);
        datestamp(&cert);
        strbuf_addch(&cert, '\n');
        if (args->url && *args->url) {
@@ -374,7 +374,7 @@ static int generate_push_cert(struct strbuf *req_buf,
        if (!update_seen)
                goto free_return;
 
-       if (sign_buffer(&cert, &cert, signing_key))
+       if (sign_buffer(&cert, &cert, get_signing_key()))
                die(_("failed to sign the push certificate"));
 
        packet_buf_write(req_buf, "push-cert%c%s", 0, cap_string);
@@ -386,7 +386,7 @@ static int generate_push_cert(struct strbuf *req_buf,
        packet_buf_write(req_buf, "push-cert-end\n");
 
 free_return:
-       free(signing_key);
+       free(signing_key_id);
        strbuf_release(&cert);
        return update_seen;
 }