ssh signing: add ssh key format and signing code
[git/debian.git] / gpg-interface.c
blob7ca682ac6d68495a01bd1d76ed49bcc1adab2245
1 #include "cache.h"
2 #include "commit.h"
3 #include "config.h"
4 #include "run-command.h"
5 #include "strbuf.h"
6 #include "gpg-interface.h"
7 #include "sigchain.h"
8 #include "tempfile.h"
10 static char *configured_signing_key;
11 static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
13 struct gpg_format {
14 const char *name;
15 const char *program;
16 const char **verify_args;
17 const char **sigs;
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);
26 static const char *openpgp_verify_args[] = {
27 "--keyid-format=long",
28 NULL
30 static const char *openpgp_sigs[] = {
31 "-----BEGIN PGP SIGNATURE-----",
32 "-----BEGIN PGP MESSAGE-----",
33 NULL
36 static const char *x509_verify_args[] = {
37 NULL
39 static const char *x509_sigs[] = {
40 "-----BEGIN SIGNED MESSAGE-----",
41 NULL
44 static const char *ssh_verify_args[] = { NULL };
45 static const char *ssh_sigs[] = {
46 "-----BEGIN SSH SIGNATURE-----",
47 NULL
50 static int verify_gpg_signed_buffer(struct signature_check *sigc,
51 struct gpg_format *fmt, const char *payload,
52 size_t payload_size, const char *signature,
53 size_t signature_size);
54 static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
55 const char *signing_key);
56 static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
57 const char *signing_key);
59 static struct gpg_format gpg_format[] = {
61 .name = "openpgp",
62 .program = "gpg",
63 .verify_args = openpgp_verify_args,
64 .sigs = openpgp_sigs,
65 .verify_signed_buffer = verify_gpg_signed_buffer,
66 .sign_buffer = sign_buffer_gpg,
69 .name = "x509",
70 .program = "gpgsm",
71 .verify_args = x509_verify_args,
72 .sigs = x509_sigs,
73 .verify_signed_buffer = verify_gpg_signed_buffer,
74 .sign_buffer = sign_buffer_gpg,
77 .name = "ssh",
78 .program = "ssh-keygen",
79 .verify_args = ssh_verify_args,
80 .sigs = ssh_sigs,
81 .verify_signed_buffer = NULL, /* TODO */
82 .sign_buffer = sign_buffer_ssh
86 static struct gpg_format *use_format = &gpg_format[0];
88 static struct gpg_format *get_format_by_name(const char *str)
90 int i;
92 for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
93 if (!strcmp(gpg_format[i].name, str))
94 return gpg_format + i;
95 return NULL;
98 static struct gpg_format *get_format_by_sig(const char *sig)
100 int i, j;
102 for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
103 for (j = 0; gpg_format[i].sigs[j]; j++)
104 if (starts_with(sig, gpg_format[i].sigs[j]))
105 return gpg_format + i;
106 return NULL;
109 void signature_check_clear(struct signature_check *sigc)
111 FREE_AND_NULL(sigc->payload);
112 FREE_AND_NULL(sigc->output);
113 FREE_AND_NULL(sigc->gpg_status);
114 FREE_AND_NULL(sigc->signer);
115 FREE_AND_NULL(sigc->key);
116 FREE_AND_NULL(sigc->fingerprint);
117 FREE_AND_NULL(sigc->primary_key_fingerprint);
120 /* An exclusive status -- only one of them can appear in output */
121 #define GPG_STATUS_EXCLUSIVE (1<<0)
122 /* The status includes key identifier */
123 #define GPG_STATUS_KEYID (1<<1)
124 /* The status includes user identifier */
125 #define GPG_STATUS_UID (1<<2)
126 /* The status includes key fingerprints */
127 #define GPG_STATUS_FINGERPRINT (1<<3)
128 /* The status includes trust level */
129 #define GPG_STATUS_TRUST_LEVEL (1<<4)
131 /* Short-hand for standard exclusive *SIG status with keyid & UID */
132 #define GPG_STATUS_STDSIG (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
134 static struct {
135 char result;
136 const char *check;
137 unsigned int flags;
138 } sigcheck_gpg_status[] = {
139 { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
140 { 'B', "BADSIG ", GPG_STATUS_STDSIG },
141 { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
142 { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
143 { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
144 { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
145 { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
146 { 0, "TRUST_", GPG_STATUS_TRUST_LEVEL },
149 static struct {
150 const char *key;
151 enum signature_trust_level value;
152 } sigcheck_gpg_trust_level[] = {
153 { "UNDEFINED", TRUST_UNDEFINED },
154 { "NEVER", TRUST_NEVER },
155 { "MARGINAL", TRUST_MARGINAL },
156 { "FULLY", TRUST_FULLY },
157 { "ULTIMATE", TRUST_ULTIMATE },
160 static void replace_cstring(char **field, const char *line, const char *next)
162 free(*field);
164 if (line && next)
165 *field = xmemdupz(line, next - line);
166 else
167 *field = NULL;
170 static int parse_gpg_trust_level(const char *level,
171 enum signature_trust_level *res)
173 size_t i;
175 for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_trust_level); i++) {
176 if (!strcmp(sigcheck_gpg_trust_level[i].key, level)) {
177 *res = sigcheck_gpg_trust_level[i].value;
178 return 0;
181 return 1;
184 static void parse_gpg_output(struct signature_check *sigc)
186 const char *buf = sigc->gpg_status;
187 const char *line, *next;
188 int i, j;
189 int seen_exclusive_status = 0;
191 /* Iterate over all lines */
192 for (line = buf; *line; line = strchrnul(line+1, '\n')) {
193 while (*line == '\n')
194 line++;
195 if (!*line)
196 break;
198 /* Skip lines that don't start with GNUPG status */
199 if (!skip_prefix(line, "[GNUPG:] ", &line))
200 continue;
202 /* Iterate over all search strings */
203 for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
204 if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) {
206 * GOODSIG, BADSIG etc. can occur only once for
207 * each signature. Therefore, if we had more
208 * than one then we're dealing with multiple
209 * signatures. We don't support them
210 * currently, and they're rather hard to
211 * create, so something is likely fishy and we
212 * should reject them altogether.
214 if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) {
215 if (seen_exclusive_status++)
216 goto error;
219 if (sigcheck_gpg_status[i].result)
220 sigc->result = sigcheck_gpg_status[i].result;
221 /* Do we have key information? */
222 if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) {
223 next = strchrnul(line, ' ');
224 replace_cstring(&sigc->key, line, next);
225 /* Do we have signer information? */
226 if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
227 line = next + 1;
228 next = strchrnul(line, '\n');
229 replace_cstring(&sigc->signer, line, next);
233 /* Do we have trust level? */
234 if (sigcheck_gpg_status[i].flags & GPG_STATUS_TRUST_LEVEL) {
236 * GPG v1 and v2 differs in how the
237 * TRUST_ lines are written. Some
238 * trust lines contain no additional
239 * space-separated information for v1.
241 size_t trust_size = strcspn(line, " \n");
242 char *trust = xmemdupz(line, trust_size);
244 if (parse_gpg_trust_level(trust, &sigc->trust_level)) {
245 free(trust);
246 goto error;
248 free(trust);
251 /* Do we have fingerprint? */
252 if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) {
253 const char *limit;
254 char **field;
256 next = strchrnul(line, ' ');
257 replace_cstring(&sigc->fingerprint, line, next);
260 * Skip interim fields. The search is
261 * limited to the same line since only
262 * OpenPGP signatures has a field with
263 * the primary fingerprint.
265 limit = strchrnul(line, '\n');
266 for (j = 9; j > 0; j--) {
267 if (!*next || limit <= next)
268 break;
269 line = next + 1;
270 next = strchrnul(line, ' ');
273 field = &sigc->primary_key_fingerprint;
274 if (!j) {
275 next = strchrnul(line, '\n');
276 replace_cstring(field, line, next);
277 } else {
278 replace_cstring(field, NULL, NULL);
282 break;
286 return;
288 error:
289 sigc->result = 'E';
290 /* Clear partial data to avoid confusion */
291 FREE_AND_NULL(sigc->primary_key_fingerprint);
292 FREE_AND_NULL(sigc->fingerprint);
293 FREE_AND_NULL(sigc->signer);
294 FREE_AND_NULL(sigc->key);
297 static int verify_gpg_signed_buffer(struct signature_check *sigc,
298 struct gpg_format *fmt, const char *payload,
299 size_t payload_size, const char *signature,
300 size_t signature_size)
302 struct child_process gpg = CHILD_PROCESS_INIT;
303 struct tempfile *temp;
304 int ret;
305 struct strbuf gpg_stdout = STRBUF_INIT;
306 struct strbuf gpg_stderr = STRBUF_INIT;
308 temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
309 if (!temp)
310 return error_errno(_("could not create temporary file"));
311 if (write_in_full(temp->fd, signature, signature_size) < 0 ||
312 close_tempfile_gently(temp) < 0) {
313 error_errno(_("failed writing detached signature to '%s'"),
314 temp->filename.buf);
315 delete_tempfile(&temp);
316 return -1;
319 strvec_push(&gpg.args, fmt->program);
320 strvec_pushv(&gpg.args, fmt->verify_args);
321 strvec_pushl(&gpg.args,
322 "--status-fd=1",
323 "--verify", temp->filename.buf, "-",
324 NULL);
326 sigchain_push(SIGPIPE, SIG_IGN);
327 ret = pipe_command(&gpg, payload, payload_size, &gpg_stdout, 0,
328 &gpg_stderr, 0);
329 sigchain_pop(SIGPIPE);
331 delete_tempfile(&temp);
333 ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG ");
334 sigc->payload = xmemdupz(payload, payload_size);
335 sigc->output = strbuf_detach(&gpg_stderr, NULL);
336 sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
338 parse_gpg_output(sigc);
340 strbuf_release(&gpg_stdout);
341 strbuf_release(&gpg_stderr);
343 return ret;
346 int check_signature(const char *payload, size_t plen, const char *signature,
347 size_t slen, struct signature_check *sigc)
349 struct gpg_format *fmt;
350 int status;
352 sigc->result = 'N';
353 sigc->trust_level = -1;
355 fmt = get_format_by_sig(signature);
356 if (!fmt)
357 die(_("bad/incompatible signature '%s'"), signature);
359 status = fmt->verify_signed_buffer(sigc, fmt, payload, plen, signature,
360 slen);
362 if (status && !sigc->output)
363 return !!status;
365 status |= sigc->result != 'G';
366 status |= sigc->trust_level < configured_min_trust_level;
368 return !!status;
371 void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
373 const char *output = flags & GPG_VERIFY_RAW ? sigc->gpg_status :
374 sigc->output;
376 if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
377 fputs(sigc->payload, stdout);
379 if (output)
380 fputs(output, stderr);
383 size_t parse_signed_buffer(const char *buf, size_t size)
385 size_t len = 0;
386 size_t match = size;
387 while (len < size) {
388 const char *eol;
390 if (get_format_by_sig(buf + len))
391 match = len;
393 eol = memchr(buf + len, '\n', size - len);
394 len += eol ? eol - (buf + len) + 1 : size - len;
396 return match;
399 int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
401 size_t match = parse_signed_buffer(buf, size);
402 if (match != size) {
403 strbuf_add(payload, buf, match);
404 remove_signature(payload);
405 strbuf_add(signature, buf + match, size - match);
406 return 1;
408 return 0;
411 void set_signing_key(const char *key)
413 free(configured_signing_key);
414 configured_signing_key = xstrdup(key);
417 int git_gpg_config(const char *var, const char *value, void *cb)
419 struct gpg_format *fmt = NULL;
420 char *fmtname = NULL;
421 char *trust;
422 int ret;
424 if (!strcmp(var, "user.signingkey")) {
425 if (!value)
426 return config_error_nonbool(var);
427 set_signing_key(value);
428 return 0;
431 if (!strcmp(var, "gpg.format")) {
432 if (!value)
433 return config_error_nonbool(var);
434 fmt = get_format_by_name(value);
435 if (!fmt)
436 return error("unsupported value for %s: %s",
437 var, value);
438 use_format = fmt;
439 return 0;
442 if (!strcmp(var, "gpg.mintrustlevel")) {
443 if (!value)
444 return config_error_nonbool(var);
446 trust = xstrdup_toupper(value);
447 ret = parse_gpg_trust_level(trust, &configured_min_trust_level);
448 free(trust);
450 if (ret)
451 return error("unsupported value for %s: %s", var,
452 value);
453 return 0;
456 if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
457 fmtname = "openpgp";
459 if (!strcmp(var, "gpg.x509.program"))
460 fmtname = "x509";
462 if (!strcmp(var, "gpg.ssh.program"))
463 fmtname = "ssh";
465 if (fmtname) {
466 fmt = get_format_by_name(fmtname);
467 return git_config_string(&fmt->program, var, value);
470 return 0;
473 const char *get_signing_key(void)
475 if (configured_signing_key)
476 return configured_signing_key;
477 return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
480 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
482 return use_format->sign_buffer(buffer, signature, signing_key);
486 * Strip CR from the line endings, in case we are on Windows.
487 * NEEDSWORK: make it trim only CRs before LFs and rename
489 static void remove_cr_after(struct strbuf *buffer, size_t offset)
491 size_t i, j;
493 for (i = j = offset; i < buffer->len; i++) {
494 if (buffer->buf[i] != '\r') {
495 if (i != j)
496 buffer->buf[j] = buffer->buf[i];
497 j++;
500 strbuf_setlen(buffer, j);
503 static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
504 const char *signing_key)
506 struct child_process gpg = CHILD_PROCESS_INIT;
507 int ret;
508 size_t bottom;
509 struct strbuf gpg_status = STRBUF_INIT;
511 strvec_pushl(&gpg.args,
512 use_format->program,
513 "--status-fd=2",
514 "-bsau", signing_key,
515 NULL);
517 bottom = signature->len;
520 * When the username signingkey is bad, program could be terminated
521 * because gpg exits without reading and then write gets SIGPIPE.
523 sigchain_push(SIGPIPE, SIG_IGN);
524 ret = pipe_command(&gpg, buffer->buf, buffer->len,
525 signature, 1024, &gpg_status, 0);
526 sigchain_pop(SIGPIPE);
528 ret |= !strstr(gpg_status.buf, "\n[GNUPG:] SIG_CREATED ");
529 strbuf_release(&gpg_status);
530 if (ret)
531 return error(_("gpg failed to sign the data"));
533 /* Strip CR from the line endings, in case we are on Windows. */
534 remove_cr_after(signature, bottom);
536 return 0;
539 static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
540 const char *signing_key)
542 struct child_process signer = CHILD_PROCESS_INIT;
543 int ret = -1;
544 size_t bottom, keylen;
545 struct strbuf signer_stderr = STRBUF_INIT;
546 struct tempfile *key_file = NULL, *buffer_file = NULL;
547 char *ssh_signing_key_file = NULL;
548 struct strbuf ssh_signature_filename = STRBUF_INIT;
550 if (!signing_key || signing_key[0] == '\0')
551 return error(
552 _("user.signingkey needs to be set for ssh signing"));
554 if (starts_with(signing_key, "ssh-")) {
555 /* A literal ssh key */
556 key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
557 if (!key_file)
558 return error_errno(
559 _("could not create temporary file"));
560 keylen = strlen(signing_key);
561 if (write_in_full(key_file->fd, signing_key, keylen) < 0 ||
562 close_tempfile_gently(key_file) < 0) {
563 error_errno(_("failed writing ssh signing key to '%s'"),
564 key_file->filename.buf);
565 goto out;
567 ssh_signing_key_file = strbuf_detach(&key_file->filename, NULL);
568 } else {
569 /* We assume a file */
570 ssh_signing_key_file = expand_user_path(signing_key, 1);
573 buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
574 if (!buffer_file) {
575 error_errno(_("could not create temporary file"));
576 goto out;
579 if (write_in_full(buffer_file->fd, buffer->buf, buffer->len) < 0 ||
580 close_tempfile_gently(buffer_file) < 0) {
581 error_errno(_("failed writing ssh signing key buffer to '%s'"),
582 buffer_file->filename.buf);
583 goto out;
586 strvec_pushl(&signer.args, use_format->program,
587 "-Y", "sign",
588 "-n", "git",
589 "-f", ssh_signing_key_file,
590 buffer_file->filename.buf,
591 NULL);
593 sigchain_push(SIGPIPE, SIG_IGN);
594 ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
595 sigchain_pop(SIGPIPE);
597 if (ret) {
598 if (strstr(signer_stderr.buf, "usage:"))
599 error(_("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)"));
601 error("%s", signer_stderr.buf);
602 goto out;
605 bottom = signature->len;
607 strbuf_addbuf(&ssh_signature_filename, &buffer_file->filename);
608 strbuf_addstr(&ssh_signature_filename, ".sig");
609 if (strbuf_read_file(signature, ssh_signature_filename.buf, 0) < 0) {
610 error_errno(
611 _("failed reading ssh signing data buffer from '%s'"),
612 ssh_signature_filename.buf);
614 unlink_or_warn(ssh_signature_filename.buf);
616 /* Strip CR from the line endings, in case we are on Windows. */
617 remove_cr_after(signature, bottom);
619 out:
620 if (key_file)
621 delete_tempfile(&key_file);
622 if (buffer_file)
623 delete_tempfile(&buffer_file);
624 strbuf_release(&signer_stderr);
625 strbuf_release(&ssh_signature_filename);
626 FREE_AND_NULL(ssh_signing_key_file);
627 return ret;