gpg-interface.c: use flags to determine key/signer info presence
[git] / gpg-interface.c
1 #include "cache.h"
2 #include "config.h"
3 #include "run-command.h"
4 #include "strbuf.h"
5 #include "gpg-interface.h"
6 #include "sigchain.h"
7 #include "tempfile.h"
8
9 static char *configured_signing_key;
10 struct gpg_format {
11         const char *name;
12         const char *program;
13         const char **verify_args;
14         const char **sigs;
15 };
16
17 static const char *openpgp_verify_args[] = {
18         "--keyid-format=long",
19         NULL
20 };
21 static const char *openpgp_sigs[] = {
22         "-----BEGIN PGP SIGNATURE-----",
23         "-----BEGIN PGP MESSAGE-----",
24         NULL
25 };
26
27 static const char *x509_verify_args[] = {
28         NULL
29 };
30 static const char *x509_sigs[] = {
31         "-----BEGIN SIGNED MESSAGE-----",
32         NULL
33 };
34
35 static struct gpg_format gpg_format[] = {
36         { .name = "openpgp", .program = "gpg",
37           .verify_args = openpgp_verify_args,
38           .sigs = openpgp_sigs
39         },
40         { .name = "x509", .program = "gpgsm",
41           .verify_args = x509_verify_args,
42           .sigs = x509_sigs
43         },
44 };
45
46 static struct gpg_format *use_format = &gpg_format[0];
47
48 static struct gpg_format *get_format_by_name(const char *str)
49 {
50         int i;
51
52         for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
53                 if (!strcmp(gpg_format[i].name, str))
54                         return gpg_format + i;
55         return NULL;
56 }
57
58 static struct gpg_format *get_format_by_sig(const char *sig)
59 {
60         int i, j;
61
62         for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
63                 for (j = 0; gpg_format[i].sigs[j]; j++)
64                         if (starts_with(sig, gpg_format[i].sigs[j]))
65                                 return gpg_format + i;
66         return NULL;
67 }
68
69 void signature_check_clear(struct signature_check *sigc)
70 {
71         FREE_AND_NULL(sigc->payload);
72         FREE_AND_NULL(sigc->gpg_output);
73         FREE_AND_NULL(sigc->gpg_status);
74         FREE_AND_NULL(sigc->signer);
75         FREE_AND_NULL(sigc->key);
76 }
77
78 /* An exclusive status -- only one of them can appear in output */
79 #define GPG_STATUS_EXCLUSIVE    (1<<0)
80 /* The status includes key identifier */
81 #define GPG_STATUS_KEYID        (1<<1)
82 /* The status includes user identifier */
83 #define GPG_STATUS_UID          (1<<2)
84
85 /* Short-hand for standard exclusive *SIG status with keyid & UID */
86 #define GPG_STATUS_STDSIG       (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
87
88 static struct {
89         char result;
90         const char *check;
91         unsigned int flags;
92 } sigcheck_gpg_status[] = {
93         { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
94         { 'B', "BADSIG ", GPG_STATUS_STDSIG },
95         { 'U', "TRUST_NEVER", 0 },
96         { 'U', "TRUST_UNDEFINED", 0 },
97         { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
98         { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
99         { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
100         { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
101 };
102
103 static void parse_gpg_output(struct signature_check *sigc)
104 {
105         const char *buf = sigc->gpg_status;
106         const char *line, *next;
107         int i;
108         int seen_exclusive_status = 0;
109
110         /* Iterate over all lines */
111         for (line = buf; *line; line = strchrnul(line+1, '\n')) {
112                 while (*line == '\n')
113                         line++;
114                 /* Skip lines that don't start with GNUPG status */
115                 if (!skip_prefix(line, "[GNUPG:] ", &line))
116                         continue;
117
118                 /* Iterate over all search strings */
119                 for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
120                         if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) {
121                                 if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) {
122                                         if (++seen_exclusive_status > 1)
123                                                 goto found_duplicate_status;
124                                 }
125
126                                 sigc->result = sigcheck_gpg_status[i].result;
127                                 /* Do we have key information? */
128                                 if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) {
129                                         next = strchrnul(line, ' ');
130                                         free(sigc->key);
131                                         sigc->key = xmemdupz(line, next - line);
132                                         /* Do we have signer information? */
133                                         if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
134                                                 line = next + 1;
135                                                 next = strchrnul(line, '\n');
136                                                 free(sigc->signer);
137                                                 sigc->signer = xmemdupz(line, next - line);
138                                         }
139                                 }
140
141                                 break;
142                         }
143                 }
144         }
145         return;
146
147 found_duplicate_status:
148         /*
149          * GOODSIG, BADSIG etc. can occur only once for each signature.
150          * Therefore, if we had more than one then we're dealing with multiple
151          * signatures.  We don't support them currently, and they're rather
152          * hard to create, so something is likely fishy and we should reject
153          * them altogether.
154          */
155         sigc->result = 'E';
156         /* Clear partial data to avoid confusion */
157         FREE_AND_NULL(sigc->signer);
158         FREE_AND_NULL(sigc->key);
159 }
160
161 int check_signature(const char *payload, size_t plen, const char *signature,
162         size_t slen, struct signature_check *sigc)
163 {
164         struct strbuf gpg_output = STRBUF_INIT;
165         struct strbuf gpg_status = STRBUF_INIT;
166         int status;
167
168         sigc->result = 'N';
169
170         status = verify_signed_buffer(payload, plen, signature, slen,
171                                       &gpg_output, &gpg_status);
172         if (status && !gpg_output.len)
173                 goto out;
174         sigc->payload = xmemdupz(payload, plen);
175         sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
176         sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
177         parse_gpg_output(sigc);
178         status |= sigc->result != 'G' && sigc->result != 'U';
179
180  out:
181         strbuf_release(&gpg_status);
182         strbuf_release(&gpg_output);
183
184         return !!status;
185 }
186
187 void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
188 {
189         const char *output = flags & GPG_VERIFY_RAW ?
190                 sigc->gpg_status : sigc->gpg_output;
191
192         if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
193                 fputs(sigc->payload, stdout);
194
195         if (output)
196                 fputs(output, stderr);
197 }
198
199 size_t parse_signature(const char *buf, size_t size)
200 {
201         size_t len = 0;
202         size_t match = size;
203         while (len < size) {
204                 const char *eol;
205
206                 if (get_format_by_sig(buf + len))
207                         match = len;
208
209                 eol = memchr(buf + len, '\n', size - len);
210                 len += eol ? eol - (buf + len) + 1 : size - len;
211         }
212         return match;
213 }
214
215 void set_signing_key(const char *key)
216 {
217         free(configured_signing_key);
218         configured_signing_key = xstrdup(key);
219 }
220
221 int git_gpg_config(const char *var, const char *value, void *cb)
222 {
223         struct gpg_format *fmt = NULL;
224         char *fmtname = NULL;
225
226         if (!strcmp(var, "user.signingkey")) {
227                 if (!value)
228                         return config_error_nonbool(var);
229                 set_signing_key(value);
230                 return 0;
231         }
232
233         if (!strcmp(var, "gpg.format")) {
234                 if (!value)
235                         return config_error_nonbool(var);
236                 fmt = get_format_by_name(value);
237                 if (!fmt)
238                         return error("unsupported value for %s: %s",
239                                      var, value);
240                 use_format = fmt;
241                 return 0;
242         }
243
244         if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
245                 fmtname = "openpgp";
246
247         if (!strcmp(var, "gpg.x509.program"))
248                 fmtname = "x509";
249
250         if (fmtname) {
251                 fmt = get_format_by_name(fmtname);
252                 return git_config_string(&fmt->program, var, value);
253         }
254
255         return 0;
256 }
257
258 const char *get_signing_key(void)
259 {
260         if (configured_signing_key)
261                 return configured_signing_key;
262         return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
263 }
264
265 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
266 {
267         struct child_process gpg = CHILD_PROCESS_INIT;
268         int ret;
269         size_t i, j, bottom;
270         struct strbuf gpg_status = STRBUF_INIT;
271
272         argv_array_pushl(&gpg.args,
273                          use_format->program,
274                          "--status-fd=2",
275                          "-bsau", signing_key,
276                          NULL);
277
278         bottom = signature->len;
279
280         /*
281          * When the username signingkey is bad, program could be terminated
282          * because gpg exits without reading and then write gets SIGPIPE.
283          */
284         sigchain_push(SIGPIPE, SIG_IGN);
285         ret = pipe_command(&gpg, buffer->buf, buffer->len,
286                            signature, 1024, &gpg_status, 0);
287         sigchain_pop(SIGPIPE);
288
289         ret |= !strstr(gpg_status.buf, "\n[GNUPG:] SIG_CREATED ");
290         strbuf_release(&gpg_status);
291         if (ret)
292                 return error(_("gpg failed to sign the data"));
293
294         /* Strip CR from the line endings, in case we are on Windows. */
295         for (i = j = bottom; i < signature->len; i++)
296                 if (signature->buf[i] != '\r') {
297                         if (i != j)
298                                 signature->buf[j] = signature->buf[i];
299                         j++;
300                 }
301         strbuf_setlen(signature, j);
302
303         return 0;
304 }
305
306 int verify_signed_buffer(const char *payload, size_t payload_size,
307                          const char *signature, size_t signature_size,
308                          struct strbuf *gpg_output, struct strbuf *gpg_status)
309 {
310         struct child_process gpg = CHILD_PROCESS_INIT;
311         struct gpg_format *fmt;
312         struct tempfile *temp;
313         int ret;
314         struct strbuf buf = STRBUF_INIT;
315
316         temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
317         if (!temp)
318                 return error_errno(_("could not create temporary file"));
319         if (write_in_full(temp->fd, signature, signature_size) < 0 ||
320             close_tempfile_gently(temp) < 0) {
321                 error_errno(_("failed writing detached signature to '%s'"),
322                             temp->filename.buf);
323                 delete_tempfile(&temp);
324                 return -1;
325         }
326
327         fmt = get_format_by_sig(signature);
328         if (!fmt)
329                 BUG("bad signature '%s'", signature);
330
331         argv_array_push(&gpg.args, fmt->program);
332         argv_array_pushv(&gpg.args, fmt->verify_args);
333         argv_array_pushl(&gpg.args,
334                          "--status-fd=1",
335                          "--verify", temp->filename.buf, "-",
336                          NULL);
337
338         if (!gpg_status)
339                 gpg_status = &buf;
340
341         sigchain_push(SIGPIPE, SIG_IGN);
342         ret = pipe_command(&gpg, payload, payload_size,
343                            gpg_status, 0, gpg_output, 0);
344         sigchain_pop(SIGPIPE);
345
346         delete_tempfile(&temp);
347
348         ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
349         strbuf_release(&buf); /* no matter it was used or not */
350
351         return ret;
352 }