]>
Commit | Line | Data |
---|---|---|
2f47eae2 JH |
1 | #include "cache.h" |
2 | #include "run-command.h" | |
3 | #include "strbuf.h" | |
4 | #include "gpg-interface.h" | |
5 | #include "sigchain.h" | |
6 | ||
7 | static char *configured_signing_key; | |
8 | ||
9 | void set_signing_key(const char *key) | |
10 | { | |
11 | free(configured_signing_key); | |
12 | configured_signing_key = xstrdup(key); | |
13 | } | |
14 | ||
15 | int 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 | ||
25 | const 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 | */ | |
38 | int 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 | */ | |
99 | int 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 | } |