-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split GPG interface into its own helper library
This mostly moves existing code from builtin/tag.c (for signing) and builtin/verify-tag.c (for verifying) to a new gpg-interface.c file to provide a more generic library interface. - sign_buffer() takes a payload strbuf, a signature strbuf, and a signing key, runs "gpg" to produce a detached signature for the payload, and appends it to the signature strbuf. The contents of a signed tag that concatenates the payload and the detached signature can be produced by giving the same strbuf as payload and signature strbuf. - verify_signed_buffer() takes a payload and a detached signature as <ptr, len> pairs, and runs "gpg --verify" to see if the payload matches the signature. It can optionally capture the output from GPG to allow the callers to pretty-print it in a way more suitable for their contexts. "verify-tag" (aka "tag -v") used to save the whole tag contents as if it is a detached signature, and fed gpg the payload part of the tag. It relied on gpg to fail when the given tag is not signed but just is annotated. The updated run_gpg_verify() function detects the lack of detached signature in the input, and errors out without bothering "gpg". Signed-off-by: Junio C Hamano <gitster@pobox.com>
- Loading branch information
Junio C Hamano
committed
Nov 5, 2011
1 parent
3dfbe68
commit 2f47eae
Showing
6 changed files
with
166 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#include "cache.h" | ||
#include "run-command.h" | ||
#include "strbuf.h" | ||
#include "gpg-interface.h" | ||
#include "sigchain.h" | ||
|
||
static char *configured_signing_key; | ||
|
||
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")) { | ||
if (!value) | ||
return config_error_nonbool(var); | ||
set_signing_key(value); | ||
} | ||
return 0; | ||
} | ||
|
||
const char *get_signing_key(void) | ||
{ | ||
if (configured_signing_key) | ||
return configured_signing_key; | ||
return git_committer_info(IDENT_ERROR_ON_NO_NAME|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"; | ||
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_to tells where the output from "gpg" should go: | ||
* < 0: /dev/null | ||
* = 0: standard error of the calling process | ||
* > 0: the specified file descriptor | ||
*/ | ||
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[] = {"gpg", "--verify", "FILE", "-", NULL}; | ||
char path[PATH_MAX]; | ||
int fd, ret; | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef GPG_INTERFACE_H | ||
#define GPG_INTERFACE_H | ||
|
||
extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key); | ||
extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output); | ||
extern int git_gpg_config(const char *, const char *, void *); | ||
extern void set_signing_key(const char *); | ||
extern const char *get_signing_key(void); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters