]>
Commit | Line | Data |
---|---|---|
2f47eae2 | 1 | #include "cache.h" |
9b27b492 | 2 | #include "commit.h" |
b2141fc1 | 3 | #include "config.h" |
2f47eae2 JH |
4 | #include "run-command.h" |
5 | #include "strbuf.h" | |
6 | #include "gpg-interface.h" | |
7 | #include "sigchain.h" | |
4322353b | 8 | #include "tempfile.h" |
2f47eae2 JH |
9 | |
10 | static char *configured_signing_key; | |
54887b46 HJI |
11 | static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED; |
12 | ||
58af57e1 HS |
13 | struct gpg_format { |
14 | const char *name; | |
15 | const char *program; | |
16 | const char **verify_args; | |
17 | const char **sigs; | |
b5726a5d FS |
18 | int (*verify_signed_buffer)(struct signature_check *sigc, |
19 | struct gpg_format *fmt, const char *payload, | |
20 | size_t payload_size, const char *signature, | |
21 | size_t signature_size); | |
22 | int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature, | |
23 | const char *signing_key); | |
58af57e1 HS |
24 | }; |
25 | ||
26 | static const char *openpgp_verify_args[] = { | |
27 | "--keyid-format=long", | |
28 | NULL | |
29 | }; | |
30 | static const char *openpgp_sigs[] = { | |
31 | "-----BEGIN PGP SIGNATURE-----", | |
32 | "-----BEGIN PGP MESSAGE-----", | |
33 | NULL | |
34 | }; | |
35 | ||
1e7adb97 HS |
36 | static const char *x509_verify_args[] = { |
37 | NULL | |
38 | }; | |
39 | static const char *x509_sigs[] = { | |
40 | "-----BEGIN SIGNED MESSAGE-----", | |
41 | NULL | |
42 | }; | |
43 | ||
b5726a5d FS |
44 | static int verify_gpg_signed_buffer(struct signature_check *sigc, |
45 | struct gpg_format *fmt, const char *payload, | |
46 | size_t payload_size, const char *signature, | |
47 | size_t signature_size); | |
48 | static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature, | |
49 | const char *signing_key); | |
50 | ||
58af57e1 | 51 | static struct gpg_format gpg_format[] = { |
b5726a5d FS |
52 | { |
53 | .name = "openpgp", | |
54 | .program = "gpg", | |
55 | .verify_args = openpgp_verify_args, | |
56 | .sigs = openpgp_sigs, | |
57 | .verify_signed_buffer = verify_gpg_signed_buffer, | |
58 | .sign_buffer = sign_buffer_gpg, | |
58af57e1 | 59 | }, |
b5726a5d FS |
60 | { |
61 | .name = "x509", | |
62 | .program = "gpgsm", | |
63 | .verify_args = x509_verify_args, | |
64 | .sigs = x509_sigs, | |
65 | .verify_signed_buffer = verify_gpg_signed_buffer, | |
66 | .sign_buffer = sign_buffer_gpg, | |
1e7adb97 | 67 | }, |
58af57e1 HS |
68 | }; |
69 | ||
70 | static struct gpg_format *use_format = &gpg_format[0]; | |
2f47eae2 | 71 | |
58af57e1 HS |
72 | static struct gpg_format *get_format_by_name(const char *str) |
73 | { | |
74 | int i; | |
75 | ||
76 | for (i = 0; i < ARRAY_SIZE(gpg_format); i++) | |
77 | if (!strcmp(gpg_format[i].name, str)) | |
78 | return gpg_format + i; | |
79 | return NULL; | |
80 | } | |
81 | ||
82 | static struct gpg_format *get_format_by_sig(const char *sig) | |
83 | { | |
84 | int i, j; | |
85 | ||
86 | for (i = 0; i < ARRAY_SIZE(gpg_format); i++) | |
87 | for (j = 0; gpg_format[i].sigs[j]; j++) | |
88 | if (starts_with(sig, gpg_format[i].sigs[j])) | |
89 | return gpg_format + i; | |
90 | return NULL; | |
91 | } | |
d7c67668 | 92 | |
01e57b5d MG |
93 | void signature_check_clear(struct signature_check *sigc) |
94 | { | |
88ce3ef6 | 95 | FREE_AND_NULL(sigc->payload); |
b5726a5d | 96 | FREE_AND_NULL(sigc->output); |
88ce3ef6 ÆAB |
97 | FREE_AND_NULL(sigc->gpg_status); |
98 | FREE_AND_NULL(sigc->signer); | |
99 | FREE_AND_NULL(sigc->key); | |
3daaaabe | 100 | FREE_AND_NULL(sigc->fingerprint); |
4de9394d | 101 | FREE_AND_NULL(sigc->primary_key_fingerprint); |
01e57b5d MG |
102 | } |
103 | ||
da6cf1b3 MG |
104 | /* An exclusive status -- only one of them can appear in output */ |
105 | #define GPG_STATUS_EXCLUSIVE (1<<0) | |
0b11a84e MG |
106 | /* The status includes key identifier */ |
107 | #define GPG_STATUS_KEYID (1<<1) | |
108 | /* The status includes user identifier */ | |
109 | #define GPG_STATUS_UID (1<<2) | |
3daaaabe MG |
110 | /* The status includes key fingerprints */ |
111 | #define GPG_STATUS_FINGERPRINT (1<<3) | |
54887b46 HJI |
112 | /* The status includes trust level */ |
113 | #define GPG_STATUS_TRUST_LEVEL (1<<4) | |
0b11a84e MG |
114 | |
115 | /* Short-hand for standard exclusive *SIG status with keyid & UID */ | |
116 | #define GPG_STATUS_STDSIG (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID) | |
da6cf1b3 | 117 | |
a50e7ca3 JH |
118 | static struct { |
119 | char result; | |
120 | const char *check; | |
da6cf1b3 | 121 | unsigned int flags; |
a50e7ca3 | 122 | } sigcheck_gpg_status[] = { |
0b11a84e MG |
123 | { 'G', "GOODSIG ", GPG_STATUS_STDSIG }, |
124 | { 'B', "BADSIG ", GPG_STATUS_STDSIG }, | |
0b11a84e MG |
125 | { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID }, |
126 | { 'X', "EXPSIG ", GPG_STATUS_STDSIG }, | |
127 | { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG }, | |
128 | { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG }, | |
3daaaabe | 129 | { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT }, |
54887b46 HJI |
130 | { 0, "TRUST_", GPG_STATUS_TRUST_LEVEL }, |
131 | }; | |
132 | ||
133 | static struct { | |
134 | const char *key; | |
135 | enum signature_trust_level value; | |
136 | } sigcheck_gpg_trust_level[] = { | |
137 | { "UNDEFINED", TRUST_UNDEFINED }, | |
138 | { "NEVER", TRUST_NEVER }, | |
139 | { "MARGINAL", TRUST_MARGINAL }, | |
140 | { "FULLY", TRUST_FULLY }, | |
141 | { "ULTIMATE", TRUST_ULTIMATE }, | |
a50e7ca3 JH |
142 | }; |
143 | ||
392b862e HJI |
144 | static void replace_cstring(char **field, const char *line, const char *next) |
145 | { | |
146 | free(*field); | |
147 | ||
148 | if (line && next) | |
149 | *field = xmemdupz(line, next - line); | |
150 | else | |
151 | *field = NULL; | |
152 | } | |
153 | ||
54887b46 HJI |
154 | static int parse_gpg_trust_level(const char *level, |
155 | enum signature_trust_level *res) | |
156 | { | |
157 | size_t i; | |
158 | ||
159 | for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_trust_level); i++) { | |
160 | if (!strcmp(sigcheck_gpg_trust_level[i].key, level)) { | |
161 | *res = sigcheck_gpg_trust_level[i].value; | |
162 | return 0; | |
163 | } | |
164 | } | |
165 | return 1; | |
166 | } | |
167 | ||
fbd0f166 | 168 | static void parse_gpg_output(struct signature_check *sigc) |
a50e7ca3 JH |
169 | { |
170 | const char *buf = sigc->gpg_status; | |
da6cf1b3 | 171 | const char *line, *next; |
4de9394d | 172 | int i, j; |
da6cf1b3 MG |
173 | int seen_exclusive_status = 0; |
174 | ||
175 | /* Iterate over all lines */ | |
176 | for (line = buf; *line; line = strchrnul(line+1, '\n')) { | |
177 | while (*line == '\n') | |
178 | line++; | |
64c45dc7 SR |
179 | if (!*line) |
180 | break; | |
181 | ||
da6cf1b3 MG |
182 | /* Skip lines that don't start with GNUPG status */ |
183 | if (!skip_prefix(line, "[GNUPG:] ", &line)) | |
184 | continue; | |
185 | ||
186 | /* Iterate over all search strings */ | |
187 | for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { | |
188 | if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) { | |
54887b46 HJI |
189 | /* |
190 | * GOODSIG, BADSIG etc. can occur only once for | |
191 | * each signature. Therefore, if we had more | |
192 | * than one then we're dealing with multiple | |
193 | * signatures. We don't support them | |
194 | * currently, and they're rather hard to | |
195 | * create, so something is likely fishy and we | |
196 | * should reject them altogether. | |
197 | */ | |
da6cf1b3 | 198 | if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) { |
02561896 | 199 | if (seen_exclusive_status++) |
54887b46 | 200 | goto error; |
da6cf1b3 MG |
201 | } |
202 | ||
3daaaabe MG |
203 | if (sigcheck_gpg_status[i].result) |
204 | sigc->result = sigcheck_gpg_status[i].result; | |
0b11a84e MG |
205 | /* Do we have key information? */ |
206 | if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) { | |
da6cf1b3 | 207 | next = strchrnul(line, ' '); |
392b862e | 208 | replace_cstring(&sigc->key, line, next); |
0b11a84e MG |
209 | /* Do we have signer information? */ |
210 | if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) { | |
da6cf1b3 MG |
211 | line = next + 1; |
212 | next = strchrnul(line, '\n'); | |
392b862e | 213 | replace_cstring(&sigc->signer, line, next); |
da6cf1b3 MG |
214 | } |
215 | } | |
54887b46 HJI |
216 | |
217 | /* Do we have trust level? */ | |
218 | if (sigcheck_gpg_status[i].flags & GPG_STATUS_TRUST_LEVEL) { | |
219 | /* | |
220 | * GPG v1 and v2 differs in how the | |
221 | * TRUST_ lines are written. Some | |
222 | * trust lines contain no additional | |
223 | * space-separated information for v1. | |
224 | */ | |
225 | size_t trust_size = strcspn(line, " \n"); | |
226 | char *trust = xmemdupz(line, trust_size); | |
227 | ||
228 | if (parse_gpg_trust_level(trust, &sigc->trust_level)) { | |
229 | free(trust); | |
230 | goto error; | |
231 | } | |
232 | free(trust); | |
233 | } | |
234 | ||
3daaaabe MG |
235 | /* Do we have fingerprint? */ |
236 | if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) { | |
67a6ea63 HJI |
237 | const char *limit; |
238 | char **field; | |
239 | ||
3daaaabe | 240 | next = strchrnul(line, ' '); |
392b862e | 241 | replace_cstring(&sigc->fingerprint, line, next); |
4de9394d | 242 | |
67a6ea63 HJI |
243 | /* |
244 | * Skip interim fields. The search is | |
245 | * limited to the same line since only | |
246 | * OpenPGP signatures has a field with | |
247 | * the primary fingerprint. | |
248 | */ | |
249 | limit = strchrnul(line, '\n'); | |
4de9394d | 250 | for (j = 9; j > 0; j--) { |
67a6ea63 | 251 | if (!*next || limit <= next) |
4de9394d MG |
252 | break; |
253 | line = next + 1; | |
254 | next = strchrnul(line, ' '); | |
255 | } | |
256 | ||
67a6ea63 HJI |
257 | field = &sigc->primary_key_fingerprint; |
258 | if (!j) { | |
259 | next = strchrnul(line, '\n'); | |
260 | replace_cstring(field, line, next); | |
261 | } else { | |
262 | replace_cstring(field, NULL, NULL); | |
263 | } | |
3daaaabe | 264 | } |
da6cf1b3 MG |
265 | |
266 | break; | |
661a1806 | 267 | } |
a50e7ca3 JH |
268 | } |
269 | } | |
da6cf1b3 MG |
270 | return; |
271 | ||
54887b46 | 272 | error: |
da6cf1b3 MG |
273 | sigc->result = 'E'; |
274 | /* Clear partial data to avoid confusion */ | |
4de9394d | 275 | FREE_AND_NULL(sigc->primary_key_fingerprint); |
3daaaabe | 276 | FREE_AND_NULL(sigc->fingerprint); |
da6cf1b3 MG |
277 | FREE_AND_NULL(sigc->signer); |
278 | FREE_AND_NULL(sigc->key); | |
a50e7ca3 JH |
279 | } |
280 | ||
b5726a5d FS |
281 | static int verify_gpg_signed_buffer(struct signature_check *sigc, |
282 | struct gpg_format *fmt, const char *payload, | |
283 | size_t payload_size, const char *signature, | |
284 | size_t signature_size) | |
67948981 HJI |
285 | { |
286 | struct child_process gpg = CHILD_PROCESS_INIT; | |
67948981 HJI |
287 | struct tempfile *temp; |
288 | int ret; | |
b5726a5d FS |
289 | struct strbuf gpg_stdout = STRBUF_INIT; |
290 | struct strbuf gpg_stderr = STRBUF_INIT; | |
67948981 HJI |
291 | |
292 | temp = mks_tempfile_t(".git_vtag_tmpXXXXXX"); | |
293 | if (!temp) | |
294 | return error_errno(_("could not create temporary file")); | |
295 | if (write_in_full(temp->fd, signature, signature_size) < 0 || | |
296 | close_tempfile_gently(temp) < 0) { | |
297 | error_errno(_("failed writing detached signature to '%s'"), | |
298 | temp->filename.buf); | |
299 | delete_tempfile(&temp); | |
300 | return -1; | |
301 | } | |
302 | ||
ef8d7ac4 JK |
303 | strvec_push(&gpg.args, fmt->program); |
304 | strvec_pushv(&gpg.args, fmt->verify_args); | |
305 | strvec_pushl(&gpg.args, | |
f6d8942b JK |
306 | "--status-fd=1", |
307 | "--verify", temp->filename.buf, "-", | |
308 | NULL); | |
67948981 | 309 | |
67948981 | 310 | sigchain_push(SIGPIPE, SIG_IGN); |
b5726a5d FS |
311 | ret = pipe_command(&gpg, payload, payload_size, &gpg_stdout, 0, |
312 | &gpg_stderr, 0); | |
67948981 HJI |
313 | sigchain_pop(SIGPIPE); |
314 | ||
315 | delete_tempfile(&temp); | |
316 | ||
b5726a5d FS |
317 | ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG "); |
318 | sigc->payload = xmemdupz(payload, payload_size); | |
319 | sigc->output = strbuf_detach(&gpg_stderr, NULL); | |
320 | sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL); | |
321 | ||
322 | parse_gpg_output(sigc); | |
323 | ||
324 | strbuf_release(&gpg_stdout); | |
325 | strbuf_release(&gpg_stderr); | |
67948981 HJI |
326 | |
327 | return ret; | |
328 | } | |
329 | ||
434060ec | 330 | int check_signature(const char *payload, size_t plen, const char *signature, |
a4cc18f2 | 331 | size_t slen, struct signature_check *sigc) |
332 | { | |
b5726a5d | 333 | struct gpg_format *fmt; |
a4cc18f2 | 334 | int status; |
335 | ||
336 | sigc->result = 'N'; | |
54887b46 | 337 | sigc->trust_level = -1; |
a4cc18f2 | 338 | |
b5726a5d FS |
339 | fmt = get_format_by_sig(signature); |
340 | if (!fmt) | |
341 | die(_("bad/incompatible signature '%s'"), signature); | |
342 | ||
343 | status = fmt->verify_signed_buffer(sigc, fmt, payload, plen, signature, | |
344 | slen); | |
345 | ||
346 | if (status && !sigc->output) | |
347 | return !!status; | |
348 | ||
54887b46 HJI |
349 | status |= sigc->result != 'G'; |
350 | status |= sigc->trust_level < configured_min_trust_level; | |
a4cc18f2 | 351 | |
4e5dc9ca | 352 | return !!status; |
a4cc18f2 | 353 | } |
354 | ||
ca194d50 | 355 | void print_signature_buffer(const struct signature_check *sigc, unsigned flags) |
356 | { | |
b5726a5d FS |
357 | const char *output = flags & GPG_VERIFY_RAW ? sigc->gpg_status : |
358 | sigc->output; | |
aeff29dd | 359 | |
ca194d50 | 360 | if (flags & GPG_VERIFY_VERBOSE && sigc->payload) |
361 | fputs(sigc->payload, stdout); | |
362 | ||
aeff29dd | 363 | if (output) |
364 | fputs(output, stderr); | |
ca194d50 | 365 | } |
366 | ||
482c1191 | 367 | size_t parse_signed_buffer(const char *buf, size_t size) |
d7c67668 | 368 | { |
d7c67668 | 369 | size_t len = 0; |
8b44b2be JK |
370 | size_t match = size; |
371 | while (len < size) { | |
372 | const char *eol; | |
373 | ||
58af57e1 | 374 | if (get_format_by_sig(buf + len)) |
8b44b2be JK |
375 | match = len; |
376 | ||
377 | eol = memchr(buf + len, '\n', size - len); | |
d7c67668 JH |
378 | len += eol ? eol - (buf + len) + 1 : size - len; |
379 | } | |
8b44b2be | 380 | return match; |
d7c67668 JH |
381 | } |
382 | ||
482c1191 | 383 | int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature) |
384 | { | |
385 | size_t match = parse_signed_buffer(buf, size); | |
386 | if (match != size) { | |
387 | strbuf_add(payload, buf, match); | |
9b27b492 | 388 | remove_signature(payload); |
482c1191 | 389 | strbuf_add(signature, buf + match, size - match); |
390 | return 1; | |
391 | } | |
392 | return 0; | |
393 | } | |
394 | ||
2f47eae2 JH |
395 | void set_signing_key(const char *key) |
396 | { | |
397 | free(configured_signing_key); | |
398 | configured_signing_key = xstrdup(key); | |
399 | } | |
400 | ||
401 | int git_gpg_config(const char *var, const char *value, void *cb) | |
402 | { | |
58af57e1 HS |
403 | struct gpg_format *fmt = NULL; |
404 | char *fmtname = NULL; | |
54887b46 HJI |
405 | char *trust; |
406 | int ret; | |
58af57e1 | 407 | |
2f47eae2 | 408 | if (!strcmp(var, "user.signingkey")) { |
1b0eeec3 JK |
409 | if (!value) |
410 | return config_error_nonbool(var); | |
0c5e70f0 | 411 | set_signing_key(value); |
1b0eeec3 | 412 | return 0; |
0c5e70f0 | 413 | } |
1b0eeec3 | 414 | |
57a8dd75 HS |
415 | if (!strcmp(var, "gpg.format")) { |
416 | if (!value) | |
417 | return config_error_nonbool(var); | |
58af57e1 HS |
418 | fmt = get_format_by_name(value); |
419 | if (!fmt) | |
57a8dd75 HS |
420 | return error("unsupported value for %s: %s", |
421 | var, value); | |
58af57e1 HS |
422 | use_format = fmt; |
423 | return 0; | |
57a8dd75 HS |
424 | } |
425 | ||
54887b46 HJI |
426 | if (!strcmp(var, "gpg.mintrustlevel")) { |
427 | if (!value) | |
428 | return config_error_nonbool(var); | |
429 | ||
430 | trust = xstrdup_toupper(value); | |
431 | ret = parse_gpg_trust_level(trust, &configured_min_trust_level); | |
432 | free(trust); | |
433 | ||
434 | if (ret) | |
435 | return error("unsupported value for %s: %s", var, | |
436 | value); | |
437 | return 0; | |
438 | } | |
439 | ||
b02f51b1 | 440 | if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program")) |
58af57e1 HS |
441 | fmtname = "openpgp"; |
442 | ||
1e7adb97 HS |
443 | if (!strcmp(var, "gpg.x509.program")) |
444 | fmtname = "x509"; | |
445 | ||
58af57e1 HS |
446 | if (fmtname) { |
447 | fmt = get_format_by_name(fmtname); | |
448 | return git_config_string(&fmt->program, var, value); | |
2f47eae2 | 449 | } |
1b0eeec3 | 450 | |
2f47eae2 JH |
451 | return 0; |
452 | } | |
453 | ||
454 | const char *get_signing_key(void) | |
455 | { | |
456 | if (configured_signing_key) | |
457 | return configured_signing_key; | |
f9bc573f | 458 | return git_committer_info(IDENT_STRICT|IDENT_NO_DATE); |
2f47eae2 JH |
459 | } |
460 | ||
2f47eae2 | 461 | int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key) |
b5726a5d FS |
462 | { |
463 | return use_format->sign_buffer(buffer, signature, signing_key); | |
464 | } | |
465 | ||
466 | static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature, | |
467 | const char *signing_key) | |
2f47eae2 | 468 | { |
d3180279 | 469 | struct child_process gpg = CHILD_PROCESS_INIT; |
0581b546 | 470 | int ret; |
2f47eae2 | 471 | size_t i, j, bottom; |
efee9553 | 472 | struct strbuf gpg_status = STRBUF_INIT; |
2f47eae2 | 473 | |
ef8d7ac4 | 474 | strvec_pushl(&gpg.args, |
f6d8942b JK |
475 | use_format->program, |
476 | "--status-fd=2", | |
477 | "-bsau", signing_key, | |
478 | NULL); | |
2f47eae2 | 479 | |
0581b546 | 480 | bottom = signature->len; |
2f47eae2 JH |
481 | |
482 | /* | |
483 | * When the username signingkey is bad, program could be terminated | |
484 | * because gpg exits without reading and then write gets SIGPIPE. | |
485 | */ | |
486 | sigchain_push(SIGPIPE, SIG_IGN); | |
0581b546 | 487 | ret = pipe_command(&gpg, buffer->buf, buffer->len, |
efee9553 | 488 | signature, 1024, &gpg_status, 0); |
2f47eae2 JH |
489 | sigchain_pop(SIGPIPE); |
490 | ||
efee9553 MG |
491 | ret |= !strstr(gpg_status.buf, "\n[GNUPG:] SIG_CREATED "); |
492 | strbuf_release(&gpg_status); | |
493 | if (ret) | |
2f47eae2 JH |
494 | return error(_("gpg failed to sign the data")); |
495 | ||
496 | /* Strip CR from the line endings, in case we are on Windows. */ | |
497 | for (i = j = bottom; i < signature->len; i++) | |
498 | if (signature->buf[i] != '\r') { | |
499 | if (i != j) | |
500 | signature->buf[j] = signature->buf[i]; | |
501 | j++; | |
502 | } | |
503 | strbuf_setlen(signature, j); | |
504 | ||
505 | return 0; | |
506 | } |