gpg-interface.con commit Merge branch 'jl/submodule-status-failure-report' (91c23f7)
   1#include "cache.h"
   2#include "run-command.h"
   3#include "strbuf.h"
   4#include "gpg-interface.h"
   5#include "sigchain.h"
   6
   7static char *configured_signing_key;
   8
   9void set_signing_key(const char *key)
  10{
  11        free(configured_signing_key);
  12        configured_signing_key = xstrdup(key);
  13}
  14
  15int git_gpg_config(const char *var, const char *value, void *cb)
  16{
  17        if (!strcmp(var, "user.signingkey")) {
  18                if (!value)
  19                        return config_error_nonbool(var);
  20                set_signing_key(value);
  21        }
  22        return 0;
  23}
  24
  25const char *get_signing_key(void)
  26{
  27        if (configured_signing_key)
  28                return configured_signing_key;
  29        return git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE);
  30}
  31
  32/*
  33 * Create a detached signature for the contents of "buffer" and append
  34 * it after "signature"; "buffer" and "signature" can be the same
  35 * strbuf instance, which would cause the detached signature appended
  36 * at the end.
  37 */
  38int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
  39{
  40        struct child_process gpg;
  41        const char *args[4];
  42        ssize_t len;
  43        size_t i, j, bottom;
  44
  45        memset(&gpg, 0, sizeof(gpg));
  46        gpg.argv = args;
  47        gpg.in = -1;
  48        gpg.out = -1;
  49        args[0] = "gpg";
  50        args[1] = "-bsau";
  51        args[2] = signing_key;
  52        args[3] = NULL;
  53
  54        if (start_command(&gpg))
  55                return error(_("could not run gpg."));
  56
  57        /*
  58         * When the username signingkey is bad, program could be terminated
  59         * because gpg exits without reading and then write gets SIGPIPE.
  60         */
  61        sigchain_push(SIGPIPE, SIG_IGN);
  62
  63        if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
  64                close(gpg.in);
  65                close(gpg.out);
  66                finish_command(&gpg);
  67                return error(_("gpg did not accept the data"));
  68        }
  69        close(gpg.in);
  70
  71        bottom = signature->len;
  72        len = strbuf_read(signature, gpg.out, 1024);
  73        close(gpg.out);
  74
  75        sigchain_pop(SIGPIPE);
  76
  77        if (finish_command(&gpg) || !len || len < 0)
  78                return error(_("gpg failed to sign the data"));
  79
  80        /* Strip CR from the line endings, in case we are on Windows. */
  81        for (i = j = bottom; i < signature->len; i++)
  82                if (signature->buf[i] != '\r') {
  83                        if (i != j)
  84                                signature->buf[j] = signature->buf[i];
  85                        j++;
  86                }
  87        strbuf_setlen(signature, j);
  88
  89        return 0;
  90}
  91
  92/*
  93 * Run "gpg" to see if the payload matches the detached signature.
  94 * gpg_output_to tells where the output from "gpg" should go:
  95 *   < 0: /dev/null
  96 *   = 0: standard error of the calling process
  97 *   > 0: the specified file descriptor
  98 */
  99int verify_signed_buffer(const char *payload, size_t payload_size,
 100                         const char *signature, size_t signature_size,
 101                         struct strbuf *gpg_output)
 102{
 103        struct child_process gpg;
 104        const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
 105        char path[PATH_MAX];
 106        int fd, ret;
 107
 108        fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
 109        if (fd < 0)
 110                return error("could not create temporary file '%s': %s",
 111                             path, strerror(errno));
 112        if (write_in_full(fd, signature, signature_size) < 0)
 113                return error("failed writing detached signature to '%s': %s",
 114                             path, strerror(errno));
 115        close(fd);
 116
 117        memset(&gpg, 0, sizeof(gpg));
 118        gpg.argv = args_gpg;
 119        gpg.in = -1;
 120        if (gpg_output)
 121                gpg.err = -1;
 122        args_gpg[2] = path;
 123        if (start_command(&gpg)) {
 124                unlink(path);
 125                return error("could not run gpg.");
 126        }
 127
 128        write_in_full(gpg.in, payload, payload_size);
 129        close(gpg.in);
 130
 131        if (gpg_output)
 132                strbuf_read(gpg_output, gpg.err, 0);
 133        ret = finish_command(&gpg);
 134
 135        unlink_or_warn(path);
 136
 137        return ret;
 138}