ssh signing: provide a textual signing_key_id

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>

Fabian Stelzer committed Sep 10, 2021 at 20:07 UTC 4838f62c8caffbfe5d7d39cad4e8aeb2a2d57da8
3 files changed +66 -4
gpg-interface.c
+56
@@ -24,6 +24,7 @@ struct gpg_format {
24 int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
25 const char *signing_key);
26 const char *(*get_default_key)(void);
27 + const char *(*get_key_id)(void);
28 };
29
30 static const char *openpgp_verify_args[] = {
@@ -61,6 +62,8 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
62
63 static const char *get_default_ssh_signing_key(void);
64
65 +static const char *get_ssh_key_id(void);
66 +
67 static struct gpg_format gpg_format[] = {
68 {
69 .name = "openpgp",
@@ -70,6 +73,7 @@ static struct gpg_format gpg_format[] = {
73 .verify_signed_buffer = verify_gpg_signed_buffer,
74 .sign_buffer = sign_buffer_gpg,
75 .get_default_key = NULL,
76 + .get_key_id = NULL,
77 },
78 {
79 .name = "x509",
@@ -79,6 +83,7 @@ static struct gpg_format gpg_format[] = {
83 .verify_signed_buffer = verify_gpg_signed_buffer,
84 .sign_buffer = sign_buffer_gpg,
85 .get_default_key = NULL,
86 + .get_key_id = NULL,
87 },
88 {
89 .name = "ssh",
@@ -88,6 +93,7 @@ static struct gpg_format gpg_format[] = {
93 .verify_signed_buffer = NULL, /* TODO */
94 .sign_buffer = sign_buffer_ssh,
95 .get_default_key = get_default_ssh_signing_key,
96 + .get_key_id = get_ssh_key_id,
97 },
98 };
99
@@ -484,6 +490,41 @@ int git_gpg_config(const char *var, const char *value, void *cb)
490 return 0;
491 }
492
493 +static char *get_ssh_key_fingerprint(const char *signing_key)
494 +{
495 + struct child_process ssh_keygen = CHILD_PROCESS_INIT;
496 + int ret = -1;
497 + struct strbuf fingerprint_stdout = STRBUF_INIT;
498 + struct strbuf **fingerprint;
499 +
500 + /*
501 + * With SSH Signing this can contain a filename or a public key
502 + * For textual representation we usually want a fingerprint
503 + */
504 + if (starts_with(signing_key, "ssh-")) {
505 + strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf", "-", NULL);
506 + ret = pipe_command(&ssh_keygen, signing_key,
507 + strlen(signing_key), &fingerprint_stdout, 0,
508 + NULL, 0);
509 + } else {
510 + strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf",
511 + configured_signing_key, NULL);
512 + ret = pipe_command(&ssh_keygen, NULL, 0, &fingerprint_stdout, 0,
513 + NULL, 0);
514 + }
515 +
516 + if (!!ret)
517 + die_errno(_("failed to get the ssh fingerprint for key '%s'"),
518 + signing_key);
519 +
520 + fingerprint = strbuf_split_max(&fingerprint_stdout, ' ', 3);
521 + if (!fingerprint[1])
522 + die_errno(_("failed to get the ssh fingerprint for key '%s'"),
523 + signing_key);
524 +
525 + return strbuf_detach(fingerprint[1], NULL);
526 +}
527 +
528 /* Returns the first public key from an ssh-agent to use for signing */
529 static const char *get_default_ssh_signing_key(void)
530 {
@@ -532,6 +573,21 @@ static const char *get_default_ssh_signing_key(void)
573 return default_key;
574 }
575
576 +static const char *get_ssh_key_id(void) {
577 + return get_ssh_key_fingerprint(get_signing_key());
578 +}
579 +
580 +/* Returns a textual but unique representation of the signing key */
581 +const char *get_signing_key_id(void)
582 +{
583 + if (use_format->get_key_id) {
584 + return use_format->get_key_id();
585 + }
586 +
587 + /* GPG/GPGSM only store a key id on this variable */
588 + return get_signing_key();
589 +}
590 +
591 const char *get_signing_key(void)
592 {
593 if (configured_signing_key)
gpg-interface.h
+6
@@ -64,6 +64,12 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
64 int git_gpg_config(const char *, const char *, void *);
65 void set_signing_key(const char *);
66 const char *get_signing_key(void);
67 +
68 +/*
69 + * Returns a textual unique representation of the signing key in use
70 + * Either a GPG KeyID or a SSH Key Fingerprint
71 + */
72 +const char *get_signing_key_id(void);
73 int check_signature(const char *payload, size_t plen,
74 const char *signature, size_t slen,
75 struct signature_check *sigc);
send-pack.c
+4 -4
@@ -341,13 +341,13 @@ static int generate_push_cert(struct strbuf *req_buf,
341 {
342 const struct ref *ref;
343 struct string_list_item *item;
344 - char *signing_key = xstrdup(get_signing_key());
344 + char *signing_key_id = xstrdup(get_signing_key_id());
345 const char *cp, *np;
346 struct strbuf cert = STRBUF_INIT;
347 int update_seen = 0;
348
349 strbuf_addstr(&cert, "certificate version 0.1\n");
350 - strbuf_addf(&cert, "pusher %s ", signing_key);
350 + strbuf_addf(&cert, "pusher %s ", signing_key_id);
351 datestamp(&cert);
352 strbuf_addch(&cert, '\n');
353 if (args->url && *args->url) {
@@ -374,7 +374,7 @@ static int generate_push_cert(struct strbuf *req_buf,
374 if (!update_seen)
375 goto free_return;
376
377 - if (sign_buffer(&cert, &cert, signing_key))
377 + if (sign_buffer(&cert, &cert, get_signing_key()))
378 die(_("failed to sign the push certificate"));
379
380 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,
386 packet_buf_write(req_buf, "push-cert-end\n");
387
388 free_return:
389 - free(signing_key);
389 + free(signing_key_id);
390 strbuf_release(&cert);
391 return update_seen;
392 }