Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tag: v1.8.1-rc1
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 141 lines (119 sloc) 3.398 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
#include "cache.h"
#include "run-command.h"
#include "strbuf.h"
#include "gpg-interface.h"
#include "sigchain.h"

static char *configured_signing_key;
static const char *gpg_program = "gpg";

void set_signing_key(const char *key)
{
free(configured_signing_key);
configured_signing_key = xstrdup(key);
}

int git_gpg_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "user.signingkey")) {
set_signing_key(value);
}
if (!strcmp(var, "gpg.program")) {
if (!value)
return config_error_nonbool(var);
gpg_program = xstrdup(value);
}
return 0;
}

const char *get_signing_key(void)
{
if (configured_signing_key)
return configured_signing_key;
return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
}

/*
* Create a detached signature for the contents of "buffer" and append
* it after "signature"; "buffer" and "signature" can be the same
* strbuf instance, which would cause the detached signature appended
* at the end.
*/
int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
{
struct child_process gpg;
const char *args[4];
ssize_t len;
size_t i, j, bottom;

memset(&gpg, 0, sizeof(gpg));
gpg.argv = args;
gpg.in = -1;
gpg.out = -1;
args[0] = gpg_program;
args[1] = "-bsau";
args[2] = signing_key;
args[3] = NULL;

if (start_command(&gpg))
return error(_("could not run gpg."));

/*
* When the username signingkey is bad, program could be terminated
* because gpg exits without reading and then write gets SIGPIPE.
*/
sigchain_push(SIGPIPE, SIG_IGN);

if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
close(gpg.in);
close(gpg.out);
finish_command(&gpg);
return error(_("gpg did not accept the data"));
}
close(gpg.in);

bottom = signature->len;
len = strbuf_read(signature, gpg.out, 1024);
close(gpg.out);

sigchain_pop(SIGPIPE);

if (finish_command(&gpg) || !len || len < 0)
return error(_("gpg failed to sign the data"));

/* Strip CR from the line endings, in case we are on Windows. */
for (i = j = bottom; i < signature->len; i++)
if (signature->buf[i] != '\r') {
if (i != j)
signature->buf[j] = signature->buf[i];
j++;
}
strbuf_setlen(signature, j);

return 0;
}

/*
* Run "gpg" to see if the payload matches the detached signature.
* gpg_output, when set, receives the diagnostic output from GPG.
*/
int verify_signed_buffer(const char *payload, size_t payload_size,
const char *signature, size_t signature_size,
struct strbuf *gpg_output)
{
struct child_process gpg;
const char *args_gpg[] = {NULL, "--verify", "FILE", "-", NULL};
char path[PATH_MAX];
int fd, ret;

args_gpg[0] = gpg_program;
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
if (fd < 0)
return error("could not create temporary file '%s': %s",
path, strerror(errno));
if (write_in_full(fd, signature, signature_size) < 0)
return error("failed writing detached signature to '%s': %s",
path, strerror(errno));
close(fd);

memset(&gpg, 0, sizeof(gpg));
gpg.argv = args_gpg;
gpg.in = -1;
if (gpg_output)
gpg.err = -1;
args_gpg[2] = path;
if (start_command(&gpg)) {
unlink(path);
return error("could not run gpg.");
}

write_in_full(gpg.in, payload, payload_size);
close(gpg.in);

if (gpg_output)
strbuf_read(gpg_output, gpg.err, 0);
ret = finish_command(&gpg);

unlink_or_warn(path);

return ret;
}
Something went wrong with that request. Please try again.