diff-files: integrate with sparse index
[git.git] / gpg-interface.c
blobaceeb083367bd5c147e809ac8f0f4c2e155622e6
1 #include "git-compat-util.h"
2 #include "commit.h"
3 #include "config.h"
4 #include "gettext.h"
5 #include "run-command.h"
6 #include "strbuf.h"
7 #include "dir.h"
8 #include "ident.h"
9 #include "gpg-interface.h"
10 #include "sigchain.h"
11 #include "tempfile.h"
12 #include "alias.h"
13 #include "wrapper.h"
15 static int git_gpg_config(const char *, const char *, void *);
17 static void gpg_interface_lazy_init(void)
19 static int done;
21 if (done)
22 return;
23 done = 1;
24 git_config(git_gpg_config, NULL);
27 static char *configured_signing_key;
28 static const char *ssh_default_key_command, *ssh_allowed_signers, *ssh_revocation_file;
29 static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
31 struct gpg_format {
32 const char *name;
33 const char *program;
34 const char **verify_args;
35 const char **sigs;
36 int (*verify_signed_buffer)(struct signature_check *sigc,
37 struct gpg_format *fmt,
38 const char *signature,
39 size_t signature_size);
40 int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
41 const char *signing_key);
42 const char *(*get_default_key)(void);
43 const char *(*get_key_id)(void);
46 static const char *openpgp_verify_args[] = {
47 "--keyid-format=long",
48 NULL
50 static const char *openpgp_sigs[] = {
51 "-----BEGIN PGP SIGNATURE-----",
52 "-----BEGIN PGP MESSAGE-----",
53 NULL
56 static const char *x509_verify_args[] = {
57 NULL
59 static const char *x509_sigs[] = {
60 "-----BEGIN SIGNED MESSAGE-----",
61 NULL
64 static const char *ssh_verify_args[] = { NULL };
65 static const char *ssh_sigs[] = {
66 "-----BEGIN SSH SIGNATURE-----",
67 NULL
70 static int verify_gpg_signed_buffer(struct signature_check *sigc,
71 struct gpg_format *fmt,
72 const char *signature,
73 size_t signature_size);
74 static int verify_ssh_signed_buffer(struct signature_check *sigc,
75 struct gpg_format *fmt,
76 const char *signature,
77 size_t signature_size);
78 static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
79 const char *signing_key);
80 static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
81 const char *signing_key);
83 static const char *get_default_ssh_signing_key(void);
85 static const char *get_ssh_key_id(void);
87 static struct gpg_format gpg_format[] = {
89 .name = "openpgp",
90 .program = "gpg",
91 .verify_args = openpgp_verify_args,
92 .sigs = openpgp_sigs,
93 .verify_signed_buffer = verify_gpg_signed_buffer,
94 .sign_buffer = sign_buffer_gpg,
95 .get_default_key = NULL,
96 .get_key_id = NULL,
99 .name = "x509",
100 .program = "gpgsm",
101 .verify_args = x509_verify_args,
102 .sigs = x509_sigs,
103 .verify_signed_buffer = verify_gpg_signed_buffer,
104 .sign_buffer = sign_buffer_gpg,
105 .get_default_key = NULL,
106 .get_key_id = NULL,
109 .name = "ssh",
110 .program = "ssh-keygen",
111 .verify_args = ssh_verify_args,
112 .sigs = ssh_sigs,
113 .verify_signed_buffer = verify_ssh_signed_buffer,
114 .sign_buffer = sign_buffer_ssh,
115 .get_default_key = get_default_ssh_signing_key,
116 .get_key_id = get_ssh_key_id,
120 static struct gpg_format *use_format = &gpg_format[0];
122 static struct gpg_format *get_format_by_name(const char *str)
124 int i;
126 for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
127 if (!strcmp(gpg_format[i].name, str))
128 return gpg_format + i;
129 return NULL;
132 static struct gpg_format *get_format_by_sig(const char *sig)
134 int i, j;
136 for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
137 for (j = 0; gpg_format[i].sigs[j]; j++)
138 if (starts_with(sig, gpg_format[i].sigs[j]))
139 return gpg_format + i;
140 return NULL;
143 void signature_check_clear(struct signature_check *sigc)
145 FREE_AND_NULL(sigc->payload);
146 FREE_AND_NULL(sigc->output);
147 FREE_AND_NULL(sigc->gpg_status);
148 FREE_AND_NULL(sigc->signer);
149 FREE_AND_NULL(sigc->key);
150 FREE_AND_NULL(sigc->fingerprint);
151 FREE_AND_NULL(sigc->primary_key_fingerprint);
154 /* An exclusive status -- only one of them can appear in output */
155 #define GPG_STATUS_EXCLUSIVE (1<<0)
156 /* The status includes key identifier */
157 #define GPG_STATUS_KEYID (1<<1)
158 /* The status includes user identifier */
159 #define GPG_STATUS_UID (1<<2)
160 /* The status includes key fingerprints */
161 #define GPG_STATUS_FINGERPRINT (1<<3)
162 /* The status includes trust level */
163 #define GPG_STATUS_TRUST_LEVEL (1<<4)
165 /* Short-hand for standard exclusive *SIG status with keyid & UID */
166 #define GPG_STATUS_STDSIG (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
168 static struct {
169 char result;
170 const char *check;
171 unsigned int flags;
172 } sigcheck_gpg_status[] = {
173 { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
174 { 'B', "BADSIG ", GPG_STATUS_STDSIG },
175 { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
176 { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
177 { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
178 { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
179 { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
180 { 0, "TRUST_", GPG_STATUS_TRUST_LEVEL },
183 /* Keep the order same as enum signature_trust_level */
184 static struct sigcheck_gpg_trust_level {
185 const char *key;
186 const char *display_key;
187 enum signature_trust_level value;
188 } sigcheck_gpg_trust_level[] = {
189 { "UNDEFINED", "undefined", TRUST_UNDEFINED },
190 { "NEVER", "never", TRUST_NEVER },
191 { "MARGINAL", "marginal", TRUST_MARGINAL },
192 { "FULLY", "fully", TRUST_FULLY },
193 { "ULTIMATE", "ultimate", TRUST_ULTIMATE },
196 static void replace_cstring(char **field, const char *line, const char *next)
198 free(*field);
200 if (line && next)
201 *field = xmemdupz(line, next - line);
202 else
203 *field = NULL;
206 static int parse_gpg_trust_level(const char *level,
207 enum signature_trust_level *res)
209 size_t i;
211 for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_trust_level); i++) {
212 if (!strcmp(sigcheck_gpg_trust_level[i].key, level)) {
213 *res = sigcheck_gpg_trust_level[i].value;
214 return 0;
217 return 1;
220 static void parse_gpg_output(struct signature_check *sigc)
222 const char *buf = sigc->gpg_status;
223 const char *line, *next;
224 int i, j;
225 int seen_exclusive_status = 0;
227 /* Iterate over all lines */
228 for (line = buf; *line; line = strchrnul(line+1, '\n')) {
229 while (*line == '\n')
230 line++;
231 if (!*line)
232 break;
234 /* Skip lines that don't start with GNUPG status */
235 if (!skip_prefix(line, "[GNUPG:] ", &line))
236 continue;
238 /* Iterate over all search strings */
239 for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
240 if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) {
242 * GOODSIG, BADSIG etc. can occur only once for
243 * each signature. Therefore, if we had more
244 * than one then we're dealing with multiple
245 * signatures. We don't support them
246 * currently, and they're rather hard to
247 * create, so something is likely fishy and we
248 * should reject them altogether.
250 if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) {
251 if (seen_exclusive_status++)
252 goto error;
255 if (sigcheck_gpg_status[i].result)
256 sigc->result = sigcheck_gpg_status[i].result;
257 /* Do we have key information? */
258 if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) {
259 next = strchrnul(line, ' ');
260 replace_cstring(&sigc->key, line, next);
261 /* Do we have signer information? */
262 if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
263 line = next + 1;
264 next = strchrnul(line, '\n');
265 replace_cstring(&sigc->signer, line, next);
269 /* Do we have trust level? */
270 if (sigcheck_gpg_status[i].flags & GPG_STATUS_TRUST_LEVEL) {
272 * GPG v1 and v2 differs in how the
273 * TRUST_ lines are written. Some
274 * trust lines contain no additional
275 * space-separated information for v1.
277 size_t trust_size = strcspn(line, " \n");
278 char *trust = xmemdupz(line, trust_size);
280 if (parse_gpg_trust_level(trust, &sigc->trust_level)) {
281 free(trust);
282 goto error;
284 free(trust);
287 /* Do we have fingerprint? */
288 if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) {
289 const char *limit;
290 char **field;
292 next = strchrnul(line, ' ');
293 replace_cstring(&sigc->fingerprint, line, next);
296 * Skip interim fields. The search is
297 * limited to the same line since only
298 * OpenPGP signatures has a field with
299 * the primary fingerprint.
301 limit = strchrnul(line, '\n');
302 for (j = 9; j > 0; j--) {
303 if (!*next || limit <= next)
304 break;
305 line = next + 1;
306 next = strchrnul(line, ' ');
309 field = &sigc->primary_key_fingerprint;
310 if (!j) {
311 next = strchrnul(line, '\n');
312 replace_cstring(field, line, next);
313 } else {
314 replace_cstring(field, NULL, NULL);
318 break;
322 return;
324 error:
325 sigc->result = 'E';
326 /* Clear partial data to avoid confusion */
327 FREE_AND_NULL(sigc->primary_key_fingerprint);
328 FREE_AND_NULL(sigc->fingerprint);
329 FREE_AND_NULL(sigc->signer);
330 FREE_AND_NULL(sigc->key);
333 static int verify_gpg_signed_buffer(struct signature_check *sigc,
334 struct gpg_format *fmt,
335 const char *signature,
336 size_t signature_size)
338 struct child_process gpg = CHILD_PROCESS_INIT;
339 struct tempfile *temp;
340 int ret;
341 struct strbuf gpg_stdout = STRBUF_INIT;
342 struct strbuf gpg_stderr = STRBUF_INIT;
344 temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
345 if (!temp)
346 return error_errno(_("could not create temporary file"));
347 if (write_in_full(temp->fd, signature, signature_size) < 0 ||
348 close_tempfile_gently(temp) < 0) {
349 error_errno(_("failed writing detached signature to '%s'"),
350 temp->filename.buf);
351 delete_tempfile(&temp);
352 return -1;
355 strvec_push(&gpg.args, fmt->program);
356 strvec_pushv(&gpg.args, fmt->verify_args);
357 strvec_pushl(&gpg.args,
358 "--status-fd=1",
359 "--verify", temp->filename.buf, "-",
360 NULL);
362 sigchain_push(SIGPIPE, SIG_IGN);
363 ret = pipe_command(&gpg, sigc->payload, sigc->payload_len, &gpg_stdout, 0,
364 &gpg_stderr, 0);
365 sigchain_pop(SIGPIPE);
367 delete_tempfile(&temp);
369 ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG ");
370 sigc->output = strbuf_detach(&gpg_stderr, NULL);
371 sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
373 parse_gpg_output(sigc);
375 strbuf_release(&gpg_stdout);
376 strbuf_release(&gpg_stderr);
378 return ret;
381 static void parse_ssh_output(struct signature_check *sigc)
383 const char *line, *principal, *search;
384 char *to_free;
385 char *key = NULL;
388 * ssh-keygen output should be:
389 * Good "git" signature for PRINCIPAL with RSA key SHA256:FINGERPRINT
391 * or for valid but unknown keys:
392 * Good "git" signature with RSA key SHA256:FINGERPRINT
394 * Note that "PRINCIPAL" can contain whitespace, "RSA" and
395 * "SHA256" part could be a different token that names of
396 * the algorithms used, and "FINGERPRINT" is a hexadecimal
397 * string. By finding the last occurence of " with ", we can
398 * reliably parse out the PRINCIPAL.
400 sigc->result = 'B';
401 sigc->trust_level = TRUST_NEVER;
403 line = to_free = xmemdupz(sigc->output, strcspn(sigc->output, "\n"));
405 if (skip_prefix(line, "Good \"git\" signature for ", &line)) {
406 /* Search for the last "with" to get the full principal */
407 principal = line;
408 do {
409 search = strstr(line, " with ");
410 if (search)
411 line = search + 1;
412 } while (search != NULL);
413 if (line == principal)
414 goto cleanup;
416 /* Valid signature and known principal */
417 sigc->result = 'G';
418 sigc->trust_level = TRUST_FULLY;
419 sigc->signer = xmemdupz(principal, line - principal - 1);
420 } else if (skip_prefix(line, "Good \"git\" signature with ", &line)) {
421 /* Valid signature, but key unknown */
422 sigc->result = 'G';
423 sigc->trust_level = TRUST_UNDEFINED;
424 } else {
425 goto cleanup;
428 key = strstr(line, "key ");
429 if (key) {
430 sigc->fingerprint = xstrdup(strstr(line, "key ") + 4);
431 sigc->key = xstrdup(sigc->fingerprint);
432 } else {
434 * Output did not match what we expected
435 * Treat the signature as bad
437 sigc->result = 'B';
440 cleanup:
441 free(to_free);
444 static int verify_ssh_signed_buffer(struct signature_check *sigc,
445 struct gpg_format *fmt,
446 const char *signature,
447 size_t signature_size)
449 struct child_process ssh_keygen = CHILD_PROCESS_INIT;
450 struct tempfile *buffer_file;
451 int ret = -1;
452 const char *line;
453 char *principal;
454 struct strbuf ssh_principals_out = STRBUF_INIT;
455 struct strbuf ssh_principals_err = STRBUF_INIT;
456 struct strbuf ssh_keygen_out = STRBUF_INIT;
457 struct strbuf ssh_keygen_err = STRBUF_INIT;
458 struct strbuf verify_time = STRBUF_INIT;
459 const struct date_mode verify_date_mode = {
460 .type = DATE_STRFTIME,
461 .strftime_fmt = "%Y%m%d%H%M%S",
462 /* SSH signing key validity has no timezone information - Use the local timezone */
463 .local = 1,
466 if (!ssh_allowed_signers) {
467 error(_("gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification"));
468 return -1;
471 buffer_file = mks_tempfile_t(".git_vtag_tmpXXXXXX");
472 if (!buffer_file)
473 return error_errno(_("could not create temporary file"));
474 if (write_in_full(buffer_file->fd, signature, signature_size) < 0 ||
475 close_tempfile_gently(buffer_file) < 0) {
476 error_errno(_("failed writing detached signature to '%s'"),
477 buffer_file->filename.buf);
478 delete_tempfile(&buffer_file);
479 return -1;
482 if (sigc->payload_timestamp)
483 strbuf_addf(&verify_time, "-Overify-time=%s",
484 show_date(sigc->payload_timestamp, 0, &verify_date_mode));
486 /* Find the principal from the signers */
487 strvec_pushl(&ssh_keygen.args, fmt->program,
488 "-Y", "find-principals",
489 "-f", ssh_allowed_signers,
490 "-s", buffer_file->filename.buf,
491 verify_time.buf,
492 NULL);
493 ret = pipe_command(&ssh_keygen, NULL, 0, &ssh_principals_out, 0,
494 &ssh_principals_err, 0);
495 if (ret && strstr(ssh_principals_err.buf, "usage:")) {
496 error(_("ssh-keygen -Y find-principals/verify is needed for ssh signature verification (available in openssh version 8.2p1+)"));
497 goto out;
499 if (ret || !ssh_principals_out.len) {
501 * We did not find a matching principal in the allowedSigners
502 * Check without validation
504 child_process_init(&ssh_keygen);
505 strvec_pushl(&ssh_keygen.args, fmt->program,
506 "-Y", "check-novalidate",
507 "-n", "git",
508 "-s", buffer_file->filename.buf,
509 verify_time.buf,
510 NULL);
511 pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
512 &ssh_keygen_out, 0, &ssh_keygen_err, 0);
515 * Fail on unknown keys
516 * we still call check-novalidate to display the signature info
518 ret = -1;
519 } else {
520 /* Check every principal we found (one per line) */
521 const char *next;
522 for (line = ssh_principals_out.buf;
523 *line;
524 line = next) {
525 const char *end_of_text;
527 next = end_of_text = strchrnul(line, '\n');
529 /* Did we find a LF, and did we have CR before it? */
530 if (*end_of_text &&
531 line < end_of_text &&
532 end_of_text[-1] == '\r')
533 end_of_text--;
535 /* Unless we hit NUL, skip over the LF we found */
536 if (*next)
537 next++;
539 /* Not all lines are data. Skip empty ones */
540 if (line == end_of_text)
541 continue;
543 /* We now know we have an non-empty line. Process it */
544 principal = xmemdupz(line, end_of_text - line);
546 child_process_init(&ssh_keygen);
547 strbuf_release(&ssh_keygen_out);
548 strbuf_release(&ssh_keygen_err);
549 strvec_push(&ssh_keygen.args, fmt->program);
551 * We found principals
552 * Try with each until we find a match
554 strvec_pushl(&ssh_keygen.args, "-Y", "verify",
555 "-n", "git",
556 "-f", ssh_allowed_signers,
557 "-I", principal,
558 "-s", buffer_file->filename.buf,
559 verify_time.buf,
560 NULL);
562 if (ssh_revocation_file) {
563 if (file_exists(ssh_revocation_file)) {
564 strvec_pushl(&ssh_keygen.args, "-r",
565 ssh_revocation_file, NULL);
566 } else {
567 warning(_("ssh signing revocation file configured but not found: %s"),
568 ssh_revocation_file);
572 sigchain_push(SIGPIPE, SIG_IGN);
573 ret = pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
574 &ssh_keygen_out, 0, &ssh_keygen_err, 0);
575 sigchain_pop(SIGPIPE);
577 FREE_AND_NULL(principal);
579 if (!ret)
580 ret = !starts_with(ssh_keygen_out.buf, "Good");
582 if (!ret)
583 break;
587 strbuf_stripspace(&ssh_keygen_out, 0);
588 strbuf_stripspace(&ssh_keygen_err, 0);
589 /* Add stderr outputs to show the user actual ssh-keygen errors */
590 strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
591 strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
592 sigc->output = strbuf_detach(&ssh_keygen_out, NULL);
593 sigc->gpg_status = xstrdup(sigc->output);
595 parse_ssh_output(sigc);
597 out:
598 if (buffer_file)
599 delete_tempfile(&buffer_file);
600 strbuf_release(&ssh_principals_out);
601 strbuf_release(&ssh_principals_err);
602 strbuf_release(&ssh_keygen_out);
603 strbuf_release(&ssh_keygen_err);
604 strbuf_release(&verify_time);
606 return ret;
609 static int parse_payload_metadata(struct signature_check *sigc)
611 const char *ident_line = NULL;
612 size_t ident_len;
613 struct ident_split ident;
614 const char *signer_header;
616 switch (sigc->payload_type) {
617 case SIGNATURE_PAYLOAD_COMMIT:
618 signer_header = "committer";
619 break;
620 case SIGNATURE_PAYLOAD_TAG:
621 signer_header = "tagger";
622 break;
623 case SIGNATURE_PAYLOAD_UNDEFINED:
624 case SIGNATURE_PAYLOAD_PUSH_CERT:
625 /* Ignore payloads we don't want to parse */
626 return 0;
627 default:
628 BUG("invalid value for sigc->payload_type");
631 ident_line = find_commit_header(sigc->payload, signer_header, &ident_len);
632 if (!ident_line || !ident_len)
633 return 1;
635 if (split_ident_line(&ident, ident_line, ident_len))
636 return 1;
638 if (!sigc->payload_timestamp && ident.date_begin && ident.date_end)
639 sigc->payload_timestamp = parse_timestamp(ident.date_begin, NULL, 10);
641 return 0;
644 int check_signature(struct signature_check *sigc,
645 const char *signature, size_t slen)
647 struct gpg_format *fmt;
648 int status;
650 gpg_interface_lazy_init();
652 sigc->result = 'N';
653 sigc->trust_level = -1;
655 fmt = get_format_by_sig(signature);
656 if (!fmt)
657 die(_("bad/incompatible signature '%s'"), signature);
659 if (parse_payload_metadata(sigc))
660 return 1;
662 status = fmt->verify_signed_buffer(sigc, fmt, signature, slen);
664 if (status && !sigc->output)
665 return !!status;
667 status |= sigc->result != 'G';
668 status |= sigc->trust_level < configured_min_trust_level;
670 return !!status;
673 void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
675 const char *output = flags & GPG_VERIFY_RAW ? sigc->gpg_status :
676 sigc->output;
678 if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
679 fwrite(sigc->payload, 1, sigc->payload_len, stdout);
681 if (output)
682 fputs(output, stderr);
685 size_t parse_signed_buffer(const char *buf, size_t size)
687 size_t len = 0;
688 size_t match = size;
689 while (len < size) {
690 const char *eol;
692 if (get_format_by_sig(buf + len))
693 match = len;
695 eol = memchr(buf + len, '\n', size - len);
696 len += eol ? eol - (buf + len) + 1 : size - len;
698 return match;
701 int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
703 size_t match = parse_signed_buffer(buf, size);
704 if (match != size) {
705 strbuf_add(payload, buf, match);
706 remove_signature(payload);
707 strbuf_add(signature, buf + match, size - match);
708 return 1;
710 return 0;
713 void set_signing_key(const char *key)
715 gpg_interface_lazy_init();
717 free(configured_signing_key);
718 configured_signing_key = xstrdup(key);
721 static int git_gpg_config(const char *var, const char *value, void *cb UNUSED)
723 struct gpg_format *fmt = NULL;
724 char *fmtname = NULL;
725 char *trust;
726 int ret;
728 if (!strcmp(var, "user.signingkey")) {
729 if (!value)
730 return config_error_nonbool(var);
731 set_signing_key(value);
732 return 0;
735 if (!strcmp(var, "gpg.format")) {
736 if (!value)
737 return config_error_nonbool(var);
738 fmt = get_format_by_name(value);
739 if (!fmt)
740 return error(_("invalid value for '%s': '%s'"),
741 var, value);
742 use_format = fmt;
743 return 0;
746 if (!strcmp(var, "gpg.mintrustlevel")) {
747 if (!value)
748 return config_error_nonbool(var);
750 trust = xstrdup_toupper(value);
751 ret = parse_gpg_trust_level(trust, &configured_min_trust_level);
752 free(trust);
754 if (ret)
755 return error(_("invalid value for '%s': '%s'"),
756 var, value);
757 return 0;
760 if (!strcmp(var, "gpg.ssh.defaultkeycommand")) {
761 if (!value)
762 return config_error_nonbool(var);
763 return git_config_string(&ssh_default_key_command, var, value);
766 if (!strcmp(var, "gpg.ssh.allowedsignersfile")) {
767 if (!value)
768 return config_error_nonbool(var);
769 return git_config_pathname(&ssh_allowed_signers, var, value);
772 if (!strcmp(var, "gpg.ssh.revocationfile")) {
773 if (!value)
774 return config_error_nonbool(var);
775 return git_config_pathname(&ssh_revocation_file, var, value);
778 if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
779 fmtname = "openpgp";
781 if (!strcmp(var, "gpg.x509.program"))
782 fmtname = "x509";
784 if (!strcmp(var, "gpg.ssh.program"))
785 fmtname = "ssh";
787 if (fmtname) {
788 fmt = get_format_by_name(fmtname);
789 return git_config_string(&fmt->program, var, value);
792 return 0;
796 * Returns 1 if `string` contains a literal ssh key, 0 otherwise
797 * `key` will be set to the start of the actual key if a prefix is present.
799 static int is_literal_ssh_key(const char *string, const char **key)
801 if (skip_prefix(string, "key::", key))
802 return 1;
803 if (starts_with(string, "ssh-")) {
804 *key = string;
805 return 1;
807 return 0;
810 static char *get_ssh_key_fingerprint(const char *signing_key)
812 struct child_process ssh_keygen = CHILD_PROCESS_INIT;
813 int ret = -1;
814 struct strbuf fingerprint_stdout = STRBUF_INIT;
815 struct strbuf **fingerprint;
816 char *fingerprint_ret;
817 const char *literal_key = NULL;
820 * With SSH Signing this can contain a filename or a public key
821 * For textual representation we usually want a fingerprint
823 if (is_literal_ssh_key(signing_key, &literal_key)) {
824 strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf", "-", NULL);
825 ret = pipe_command(&ssh_keygen, literal_key,
826 strlen(literal_key), &fingerprint_stdout, 0,
827 NULL, 0);
828 } else {
829 strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf",
830 configured_signing_key, NULL);
831 ret = pipe_command(&ssh_keygen, NULL, 0, &fingerprint_stdout, 0,
832 NULL, 0);
835 if (!!ret)
836 die_errno(_("failed to get the ssh fingerprint for key '%s'"),
837 signing_key);
839 fingerprint = strbuf_split_max(&fingerprint_stdout, ' ', 3);
840 if (!fingerprint[1])
841 die_errno(_("failed to get the ssh fingerprint for key '%s'"),
842 signing_key);
844 fingerprint_ret = strbuf_detach(fingerprint[1], NULL);
845 strbuf_list_free(fingerprint);
846 strbuf_release(&fingerprint_stdout);
847 return fingerprint_ret;
850 /* Returns the first public key from an ssh-agent to use for signing */
851 static const char *get_default_ssh_signing_key(void)
853 struct child_process ssh_default_key = CHILD_PROCESS_INIT;
854 int ret = -1;
855 struct strbuf key_stdout = STRBUF_INIT, key_stderr = STRBUF_INIT;
856 struct strbuf **keys;
857 char *key_command = NULL;
858 const char **argv;
859 int n;
860 char *default_key = NULL;
861 const char *literal_key = NULL;
863 if (!ssh_default_key_command)
864 die(_("either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"));
866 key_command = xstrdup(ssh_default_key_command);
867 n = split_cmdline(key_command, &argv);
869 if (n < 0)
870 die("malformed build-time gpg.ssh.defaultKeyCommand: %s",
871 split_cmdline_strerror(n));
873 strvec_pushv(&ssh_default_key.args, argv);
874 ret = pipe_command(&ssh_default_key, NULL, 0, &key_stdout, 0,
875 &key_stderr, 0);
877 if (!ret) {
878 keys = strbuf_split_max(&key_stdout, '\n', 2);
879 if (keys[0] && is_literal_ssh_key(keys[0]->buf, &literal_key)) {
881 * We only use `is_literal_ssh_key` here to check validity
882 * The prefix will be stripped when the key is used.
884 default_key = strbuf_detach(keys[0], NULL);
885 } else {
886 warning(_("gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"),
887 key_stderr.buf, key_stdout.buf);
890 strbuf_list_free(keys);
891 } else {
892 warning(_("gpg.ssh.defaultKeyCommand failed: %s %s"),
893 key_stderr.buf, key_stdout.buf);
896 free(key_command);
897 free(argv);
898 strbuf_release(&key_stdout);
900 return default_key;
903 static const char *get_ssh_key_id(void) {
904 return get_ssh_key_fingerprint(get_signing_key());
907 /* Returns a textual but unique representation of the signing key */
908 const char *get_signing_key_id(void)
910 gpg_interface_lazy_init();
912 if (use_format->get_key_id) {
913 return use_format->get_key_id();
916 /* GPG/GPGSM only store a key id on this variable */
917 return get_signing_key();
920 const char *get_signing_key(void)
922 gpg_interface_lazy_init();
924 if (configured_signing_key)
925 return configured_signing_key;
926 if (use_format->get_default_key) {
927 return use_format->get_default_key();
930 return git_committer_info(IDENT_STRICT | IDENT_NO_DATE);
933 const char *gpg_trust_level_to_str(enum signature_trust_level level)
935 struct sigcheck_gpg_trust_level *trust;
937 if (level < 0 || level >= ARRAY_SIZE(sigcheck_gpg_trust_level))
938 BUG("invalid trust level requested %d", level);
940 trust = &sigcheck_gpg_trust_level[level];
941 if (trust->value != level)
942 BUG("sigcheck_gpg_trust_level[] unsorted");
944 return sigcheck_gpg_trust_level[level].display_key;
947 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
949 gpg_interface_lazy_init();
951 return use_format->sign_buffer(buffer, signature, signing_key);
955 * Strip CR from the line endings, in case we are on Windows.
956 * NEEDSWORK: make it trim only CRs before LFs and rename
958 static void remove_cr_after(struct strbuf *buffer, size_t offset)
960 size_t i, j;
962 for (i = j = offset; i < buffer->len; i++) {
963 if (buffer->buf[i] != '\r') {
964 if (i != j)
965 buffer->buf[j] = buffer->buf[i];
966 j++;
969 strbuf_setlen(buffer, j);
972 static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
973 const char *signing_key)
975 struct child_process gpg = CHILD_PROCESS_INIT;
976 int ret;
977 size_t bottom;
978 const char *cp;
979 struct strbuf gpg_status = STRBUF_INIT;
981 strvec_pushl(&gpg.args,
982 use_format->program,
983 "--status-fd=2",
984 "-bsau", signing_key,
985 NULL);
987 bottom = signature->len;
990 * When the username signingkey is bad, program could be terminated
991 * because gpg exits without reading and then write gets SIGPIPE.
993 sigchain_push(SIGPIPE, SIG_IGN);
994 ret = pipe_command(&gpg, buffer->buf, buffer->len,
995 signature, 1024, &gpg_status, 0);
996 sigchain_pop(SIGPIPE);
998 for (cp = gpg_status.buf;
999 cp && (cp = strstr(cp, "[GNUPG:] SIG_CREATED "));
1000 cp++) {
1001 if (cp == gpg_status.buf || cp[-1] == '\n')
1002 break; /* found */
1004 ret |= !cp;
1005 if (ret) {
1006 error(_("gpg failed to sign the data:\n%s"),
1007 gpg_status.len ? gpg_status.buf : "(no gpg output)");
1008 strbuf_release(&gpg_status);
1009 return -1;
1011 strbuf_release(&gpg_status);
1013 /* Strip CR from the line endings, in case we are on Windows. */
1014 remove_cr_after(signature, bottom);
1016 return 0;
1019 static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
1020 const char *signing_key)
1022 struct child_process signer = CHILD_PROCESS_INIT;
1023 int ret = -1;
1024 size_t bottom, keylen;
1025 struct strbuf signer_stderr = STRBUF_INIT;
1026 struct tempfile *key_file = NULL, *buffer_file = NULL;
1027 char *ssh_signing_key_file = NULL;
1028 struct strbuf ssh_signature_filename = STRBUF_INIT;
1029 const char *literal_key = NULL;
1030 int literal_ssh_key = 0;
1032 if (!signing_key || signing_key[0] == '\0')
1033 return error(
1034 _("user.signingKey needs to be set for ssh signing"));
1036 if (is_literal_ssh_key(signing_key, &literal_key)) {
1037 /* A literal ssh key */
1038 literal_ssh_key = 1;
1039 key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
1040 if (!key_file)
1041 return error_errno(
1042 _("could not create temporary file"));
1043 keylen = strlen(literal_key);
1044 if (write_in_full(key_file->fd, literal_key, keylen) < 0 ||
1045 close_tempfile_gently(key_file) < 0) {
1046 error_errno(_("failed writing ssh signing key to '%s'"),
1047 key_file->filename.buf);
1048 goto out;
1050 ssh_signing_key_file = strbuf_detach(&key_file->filename, NULL);
1051 } else {
1052 /* We assume a file */
1053 ssh_signing_key_file = interpolate_path(signing_key, 1);
1056 buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
1057 if (!buffer_file) {
1058 error_errno(_("could not create temporary file"));
1059 goto out;
1062 if (write_in_full(buffer_file->fd, buffer->buf, buffer->len) < 0 ||
1063 close_tempfile_gently(buffer_file) < 0) {
1064 error_errno(_("failed writing ssh signing key buffer to '%s'"),
1065 buffer_file->filename.buf);
1066 goto out;
1069 strvec_pushl(&signer.args, use_format->program,
1070 "-Y", "sign",
1071 "-n", "git",
1072 "-f", ssh_signing_key_file,
1073 NULL);
1074 if (literal_ssh_key)
1075 strvec_push(&signer.args, "-U");
1076 strvec_push(&signer.args, buffer_file->filename.buf);
1078 sigchain_push(SIGPIPE, SIG_IGN);
1079 ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
1080 sigchain_pop(SIGPIPE);
1082 if (ret) {
1083 if (strstr(signer_stderr.buf, "usage:"))
1084 error(_("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)"));
1086 error("%s", signer_stderr.buf);
1087 goto out;
1090 bottom = signature->len;
1092 strbuf_addbuf(&ssh_signature_filename, &buffer_file->filename);
1093 strbuf_addstr(&ssh_signature_filename, ".sig");
1094 if (strbuf_read_file(signature, ssh_signature_filename.buf, 0) < 0) {
1095 ret = error_errno(
1096 _("failed reading ssh signing data buffer from '%s'"),
1097 ssh_signature_filename.buf);
1098 goto out;
1100 /* Strip CR from the line endings, in case we are on Windows. */
1101 remove_cr_after(signature, bottom);
1103 out:
1104 if (key_file)
1105 delete_tempfile(&key_file);
1106 if (buffer_file)
1107 delete_tempfile(&buffer_file);
1108 if (ssh_signature_filename.len)
1109 unlink_or_warn(ssh_signature_filename.buf);
1110 strbuf_release(&signer_stderr);
1111 strbuf_release(&ssh_signature_filename);
1112 FREE_AND_NULL(ssh_signing_key_file);
1113 return ret;