From 57a8dd75df4e1d716d60fc95bd0acaab45465d68 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 17 Jul 2018 14:50:07 +0200 Subject: gpg-interface: add new config to select how to sign a commit Add "gpg.format" where the user can specify which type of signature to use for commits. At the moment only "openpgp" is supported and the value is not even used. This commit prepares for a new types of signatures. Signed-off-by: Henning Schild Signed-off-by: Junio C Hamano --- gpg-interface.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gpg-interface.c') diff --git a/gpg-interface.c b/gpg-interface.c index 09ddfbc267..b39a27980b 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -7,6 +7,7 @@ #include "tempfile.h" static char *configured_signing_key; +static const char *gpg_format = "openpgp"; static const char *gpg_program = "gpg"; #define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----" @@ -138,6 +139,15 @@ int git_gpg_config(const char *var, const char *value, void *cb) return 0; } + if (!strcmp(var, "gpg.format")) { + if (!value) + return config_error_nonbool(var); + if (strcmp(value, "openpgp")) + return error("unsupported value for %s: %s", + var, value); + return git_config_string(&gpg_format, var, value); + } + if (!strcmp(var, "gpg.program")) { if (!value) return config_error_nonbool(var); -- cgit v1.3 From 58af57e1c886a7c9fed7fb35f2dd8dd14cc5e4e0 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 17 Jul 2018 14:50:09 +0200 Subject: gpg-interface: introduce an abstraction for multiple gpg formats Create a struct that holds the format details for the supported formats. At the moment that is still just "openpgp". This commit prepares for the introduction of more formats, that might use other programs and match other signatures. Signed-off-by: Henning Schild Signed-off-by: Junio C Hamano --- gpg-interface.c | 88 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 21 deletions(-) (limited to 'gpg-interface.c') diff --git a/gpg-interface.c b/gpg-interface.c index b39a27980b..a02db76580 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -7,11 +7,52 @@ #include "tempfile.h" static char *configured_signing_key; -static const char *gpg_format = "openpgp"; -static const char *gpg_program = "gpg"; +struct gpg_format { + const char *name; + const char *program; + const char **verify_args; + const char **sigs; +}; + +static const char *openpgp_verify_args[] = { + "--keyid-format=long", + NULL +}; +static const char *openpgp_sigs[] = { + "-----BEGIN PGP SIGNATURE-----", + "-----BEGIN PGP MESSAGE-----", + NULL +}; + +static struct gpg_format gpg_format[] = { + { .name = "openpgp", .program = "gpg", + .verify_args = openpgp_verify_args, + .sigs = openpgp_sigs + }, +}; + +static struct gpg_format *use_format = &gpg_format[0]; -#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----" -#define PGP_MESSAGE "-----BEGIN PGP MESSAGE-----" +static struct gpg_format *get_format_by_name(const char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(gpg_format); i++) + if (!strcmp(gpg_format[i].name, str)) + return gpg_format + i; + return NULL; +} + +static struct gpg_format *get_format_by_sig(const char *sig) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(gpg_format); i++) + for (j = 0; gpg_format[i].sigs[j]; j++) + if (starts_with(sig, gpg_format[i].sigs[j])) + return gpg_format + i; + return NULL; +} void signature_check_clear(struct signature_check *sigc) { @@ -102,12 +143,6 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags) fputs(output, stderr); } -static int is_gpg_start(const char *line) -{ - return starts_with(line, PGP_SIGNATURE) || - starts_with(line, PGP_MESSAGE); -} - size_t parse_signature(const char *buf, size_t size) { size_t len = 0; @@ -115,7 +150,7 @@ size_t parse_signature(const char *buf, size_t size) while (len < size) { const char *eol; - if (is_gpg_start(buf + len)) + if (get_format_by_sig(buf + len)) match = len; eol = memchr(buf + len, '\n', size - len); @@ -132,6 +167,9 @@ void set_signing_key(const char *key) int git_gpg_config(const char *var, const char *value, void *cb) { + struct gpg_format *fmt = NULL; + char *fmtname = NULL; + if (!strcmp(var, "user.signingkey")) { if (!value) return config_error_nonbool(var); @@ -142,17 +180,20 @@ int git_gpg_config(const char *var, const char *value, void *cb) if (!strcmp(var, "gpg.format")) { if (!value) return config_error_nonbool(var); - if (strcmp(value, "openpgp")) + fmt = get_format_by_name(value); + if (!fmt) return error("unsupported value for %s: %s", var, value); - return git_config_string(&gpg_format, var, value); + use_format = fmt; + return 0; } - if (!strcmp(var, "gpg.program")) { - if (!value) - return config_error_nonbool(var); - gpg_program = xstrdup(value); - return 0; + if (!strcmp(var, "gpg.program")) + fmtname = "openpgp"; + + if (fmtname) { + fmt = get_format_by_name(fmtname); + return git_config_string(&fmt->program, var, value); } return 0; @@ -173,7 +214,7 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig struct strbuf gpg_status = STRBUF_INIT; argv_array_pushl(&gpg.args, - gpg_program, + use_format->program, "--status-fd=2", "-bsau", signing_key, NULL); @@ -211,6 +252,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size, struct strbuf *gpg_output, struct strbuf *gpg_status) { struct child_process gpg = CHILD_PROCESS_INIT; + struct gpg_format *fmt; struct tempfile *temp; int ret; struct strbuf buf = STRBUF_INIT; @@ -226,10 +268,14 @@ int verify_signed_buffer(const char *payload, size_t payload_size, return -1; } + fmt = get_format_by_sig(signature); + if (!fmt) + BUG("bad signature '%s'", signature); + + argv_array_push(&gpg.args, fmt->program); + argv_array_pushv(&gpg.args, fmt->verify_args); argv_array_pushl(&gpg.args, - gpg_program, "--status-fd=1", - "--keyid-format=long", "--verify", temp->filename.buf, "-", NULL); -- cgit v1.3 From 42149d7f4b1424b29c0bae4f564d5f50a856bcea Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 17 Jul 2018 14:50:10 +0200 Subject: gpg-interface: do not hardcode the key string len anymore gnupg does print the keyid followed by a space and the signer comes next. The same pattern is also used in gpgsm, but there the key length would be 40 instead of 16. Instead of hardcoding the expected length, find the first space and calculate it. Input that does not match the expected format will be ignored now, before we jumped to found+17 which might have been behind the end of an unexpected string. Signed-off-by: Henning Schild Signed-off-by: Junio C Hamano --- gpg-interface.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gpg-interface.c') diff --git a/gpg-interface.c b/gpg-interface.c index a02db76580..51cad9081d 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -95,10 +95,11 @@ static void parse_gpg_output(struct signature_check *sigc) sigc->result = sigcheck_gpg_status[i].result; /* The trust messages are not followed by key/signer information */ if (sigc->result != 'U') { - sigc->key = xmemdupz(found, 16); + next = strchrnul(found, ' '); + sigc->key = xmemdupz(found, next - found); /* The ERRSIG message is not followed by signer information */ - if (sigc-> result != 'E') { - found += 17; + if (*next && sigc-> result != 'E') { + found = next + 1; next = strchrnul(found, '\n'); sigc->signer = xmemdupz(found, next - found); } -- cgit v1.3 From b02f51b196deec70867d9616872e533e2633473c Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 17 Jul 2018 14:50:11 +0200 Subject: gpg-interface: introduce new config to select per gpg format program Supporting multiple signing formats we will have the need to configure a custom program each. Add a new config value to cater for that. Signed-off-by: Henning Schild Signed-off-by: Junio C Hamano --- Documentation/config.txt | 5 +++++ gpg-interface.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gpg-interface.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index ac373e3f48..0e871346a7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1832,6 +1832,11 @@ gpg.format:: Specifies which key format to use when signing with `--gpg-sign`. Default is "openpgp", that is also the only supported value. +gpg..program:: + Use this to customize the program used for the signing format you + chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still + be used as a legacy synonym for `gpg.openpgp.program`. + gui.commitMsgWidth:: Defines how wide the commit message window is in the linkgit:git-gui[1]. "75" is the default. diff --git a/gpg-interface.c b/gpg-interface.c index 51cad9081d..a158f08c13 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -189,7 +189,7 @@ int git_gpg_config(const char *var, const char *value, void *cb) return 0; } - if (!strcmp(var, "gpg.program")) + if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program")) fmtname = "openpgp"; if (fmtname) { -- cgit v1.3 From 1e7adb97566bff7d3431ce64b8d0d854a6863ed5 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 17 Jul 2018 14:50:12 +0200 Subject: gpg-interface: introduce new signature format "x509" using gpgsm This commit allows git to create and check x509 type signatures using gpgsm. Signed-off-by: Henning Schild Signed-off-by: Junio C Hamano --- Documentation/config.txt | 5 +++-- gpg-interface.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'gpg-interface.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 0e871346a7..ff1d4a76ca 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1830,12 +1830,13 @@ gpg.program:: gpg.format:: Specifies which key format to use when signing with `--gpg-sign`. - Default is "openpgp", that is also the only supported value. + Default is "openpgp" and another possible value is "x509". gpg..program:: Use this to customize the program used for the signing format you chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still - be used as a legacy synonym for `gpg.openpgp.program`. + be used as a legacy synonym for `gpg.openpgp.program`. The default + value for `gpg.x509.program` is "gpgsm". gui.commitMsgWidth:: Defines how wide the commit message window is in the diff --git a/gpg-interface.c b/gpg-interface.c index a158f08c13..bb8ea668b3 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -24,11 +24,23 @@ static const char *openpgp_sigs[] = { NULL }; +static const char *x509_verify_args[] = { + NULL +}; +static const char *x509_sigs[] = { + "-----BEGIN SIGNED MESSAGE-----", + NULL +}; + static struct gpg_format gpg_format[] = { { .name = "openpgp", .program = "gpg", .verify_args = openpgp_verify_args, .sigs = openpgp_sigs }, + { .name = "x509", .program = "gpgsm", + .verify_args = x509_verify_args, + .sigs = x509_sigs + }, }; static struct gpg_format *use_format = &gpg_format[0]; @@ -192,6 +204,9 @@ int git_gpg_config(const char *var, const char *value, void *cb) if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program")) fmtname = "openpgp"; + if (!strcmp(var, "gpg.x509.program")) + fmtname = "x509"; + if (fmtname) { fmt = get_format_by_name(fmtname); return git_config_string(&fmt->program, var, value); -- cgit v1.3