Coverage Report

Created: 2026-01-10 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/gpg-interface.c
Line
Count
Source
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "commit.h"
5
#include "config.h"
6
#include "date.h"
7
#include "gettext.h"
8
#include "run-command.h"
9
#include "strbuf.h"
10
#include "dir.h"
11
#include "ident.h"
12
#include "gpg-interface.h"
13
#include "path.h"
14
#include "sigchain.h"
15
#include "tempfile.h"
16
#include "alias.h"
17
18
static int git_gpg_config(const char *, const char *,
19
        const struct config_context *, void *);
20
21
static void gpg_interface_lazy_init(void)
22
0
{
23
0
  static int done;
24
25
0
  if (done)
26
0
    return;
27
0
  done = 1;
28
0
  repo_config(the_repository, git_gpg_config, NULL);
29
0
}
30
31
static char *configured_signing_key;
32
static char *ssh_default_key_command;
33
static char *ssh_allowed_signers;
34
static char *ssh_revocation_file;
35
static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
36
37
struct gpg_format {
38
  const char *name;
39
  const char *program;
40
  const char **verify_args;
41
  const char **sigs;
42
  int (*verify_signed_buffer)(struct signature_check *sigc,
43
            struct gpg_format *fmt,
44
            const char *signature,
45
            size_t signature_size);
46
  int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
47
         const char *signing_key);
48
  char *(*get_default_key)(void);
49
  char *(*get_key_id)(void);
50
};
51
52
static const char *openpgp_verify_args[] = {
53
  "--keyid-format=long",
54
  NULL
55
};
56
static const char *openpgp_sigs[] = {
57
  "-----BEGIN PGP SIGNATURE-----",
58
  "-----BEGIN PGP MESSAGE-----",
59
  NULL
60
};
61
62
static const char *x509_verify_args[] = {
63
  NULL
64
};
65
static const char *x509_sigs[] = {
66
  "-----BEGIN SIGNED MESSAGE-----",
67
  NULL
68
};
69
70
static const char *ssh_verify_args[] = { NULL };
71
static const char *ssh_sigs[] = {
72
  "-----BEGIN SSH SIGNATURE-----",
73
  NULL
74
};
75
76
static int verify_gpg_signed_buffer(struct signature_check *sigc,
77
            struct gpg_format *fmt,
78
            const char *signature,
79
            size_t signature_size);
80
static int verify_ssh_signed_buffer(struct signature_check *sigc,
81
            struct gpg_format *fmt,
82
            const char *signature,
83
            size_t signature_size);
84
static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
85
         const char *signing_key);
86
static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
87
         const char *signing_key);
88
89
static char *get_default_ssh_signing_key(void);
90
91
static char *get_ssh_key_id(void);
92
93
static struct gpg_format gpg_format[] = {
94
  {
95
    .name = "openpgp",
96
    .program = "gpg",
97
    .verify_args = openpgp_verify_args,
98
    .sigs = openpgp_sigs,
99
    .verify_signed_buffer = verify_gpg_signed_buffer,
100
    .sign_buffer = sign_buffer_gpg,
101
    .get_default_key = NULL,
102
    .get_key_id = NULL,
103
  },
104
  {
105
    .name = "x509",
106
    .program = "gpgsm",
107
    .verify_args = x509_verify_args,
108
    .sigs = x509_sigs,
109
    .verify_signed_buffer = verify_gpg_signed_buffer,
110
    .sign_buffer = sign_buffer_gpg,
111
    .get_default_key = NULL,
112
    .get_key_id = NULL,
113
  },
114
  {
115
    .name = "ssh",
116
    .program = "ssh-keygen",
117
    .verify_args = ssh_verify_args,
118
    .sigs = ssh_sigs,
119
    .verify_signed_buffer = verify_ssh_signed_buffer,
120
    .sign_buffer = sign_buffer_ssh,
121
    .get_default_key = get_default_ssh_signing_key,
122
    .get_key_id = get_ssh_key_id,
123
  },
124
};
125
126
static struct gpg_format *use_format = &gpg_format[0];
127
128
static struct gpg_format *get_format_by_name(const char *str)
129
0
{
130
0
  for (size_t i = 0; i < ARRAY_SIZE(gpg_format); i++)
131
0
    if (!strcmp(gpg_format[i].name, str))
132
0
      return gpg_format + i;
133
0
  return NULL;
134
0
}
135
136
static struct gpg_format *get_format_by_sig(const char *sig)
137
0
{
138
0
  int j;
139
140
0
  for (size_t i = 0; i < ARRAY_SIZE(gpg_format); i++)
141
0
    for (j = 0; gpg_format[i].sigs[j]; j++)
142
0
      if (starts_with(sig, gpg_format[i].sigs[j]))
143
0
        return gpg_format + i;
144
0
  return NULL;
145
0
}
146
147
const char *get_signature_format(const char *buf)
148
0
{
149
0
  struct gpg_format *format = get_format_by_sig(buf);
150
0
  return format ? format->name : "unknown";
151
0
}
152
153
int valid_signature_format(const char *format)
154
0
{
155
0
       return (!!get_format_by_name(format) ||
156
0
         !strcmp(format, "unknown"));
157
0
}
158
159
void signature_check_clear(struct signature_check *sigc)
160
0
{
161
0
  FREE_AND_NULL(sigc->payload);
162
0
  FREE_AND_NULL(sigc->output);
163
0
  FREE_AND_NULL(sigc->gpg_status);
164
0
  FREE_AND_NULL(sigc->signer);
165
0
  FREE_AND_NULL(sigc->key);
166
0
  FREE_AND_NULL(sigc->fingerprint);
167
0
  FREE_AND_NULL(sigc->primary_key_fingerprint);
168
0
}
169
170
/* An exclusive status -- only one of them can appear in output */
171
0
#define GPG_STATUS_EXCLUSIVE  (1<<0)
172
/* The status includes key identifier */
173
0
#define GPG_STATUS_KEYID  (1<<1)
174
/* The status includes user identifier */
175
0
#define GPG_STATUS_UID    (1<<2)
176
/* The status includes key fingerprints */
177
0
#define GPG_STATUS_FINGERPRINT  (1<<3)
178
/* The status includes trust level */
179
0
#define GPG_STATUS_TRUST_LEVEL  (1<<4)
180
181
/* Short-hand for standard exclusive *SIG status with keyid & UID */
182
#define GPG_STATUS_STDSIG (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
183
184
static struct {
185
  char result;
186
  const char *check;
187
  unsigned int flags;
188
} sigcheck_gpg_status[] = {
189
  { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
190
  { 'B', "BADSIG ", GPG_STATUS_STDSIG },
191
  { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
192
  { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
193
  { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
194
  { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
195
  { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
196
  { 0, "TRUST_", GPG_STATUS_TRUST_LEVEL },
197
};
198
199
/* Keep the order same as enum signature_trust_level */
200
static struct sigcheck_gpg_trust_level {
201
  const char *key;
202
  const char *display_key;
203
  enum signature_trust_level value;
204
} sigcheck_gpg_trust_level[] = {
205
  { "UNDEFINED", "undefined", TRUST_UNDEFINED },
206
  { "NEVER", "never", TRUST_NEVER },
207
  { "MARGINAL", "marginal", TRUST_MARGINAL },
208
  { "FULLY", "fully", TRUST_FULLY },
209
  { "ULTIMATE", "ultimate", TRUST_ULTIMATE },
210
};
211
212
static void replace_cstring(char **field, const char *line, const char *next)
213
0
{
214
0
  free(*field);
215
216
0
  if (line && next)
217
0
    *field = xmemdupz(line, next - line);
218
0
  else
219
0
    *field = NULL;
220
0
}
221
222
static int parse_gpg_trust_level(const char *level,
223
         enum signature_trust_level *res)
224
0
{
225
0
  size_t i;
226
227
0
  for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_trust_level); i++) {
228
0
    if (!strcmp(sigcheck_gpg_trust_level[i].key, level)) {
229
0
      *res = sigcheck_gpg_trust_level[i].value;
230
0
      return 0;
231
0
    }
232
0
  }
233
0
  return 1;
234
0
}
235
236
static void parse_gpg_output(struct signature_check *sigc)
237
0
{
238
0
  const char *buf = sigc->gpg_status;
239
0
  const char *line, *next;
240
0
  int j;
241
0
  int seen_exclusive_status = 0;
242
243
  /* Iterate over all lines */
244
0
  for (line = buf; *line; line = strchrnul(line+1, '\n')) {
245
0
    while (*line == '\n')
246
0
      line++;
247
0
    if (!*line)
248
0
      break;
249
250
    /* Skip lines that don't start with GNUPG status */
251
0
    if (!skip_prefix(line, "[GNUPG:] ", &line))
252
0
      continue;
253
254
    /* Iterate over all search strings */
255
0
    for (size_t i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
256
0
      if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) {
257
        /*
258
         * GOODSIG, BADSIG etc. can occur only once for
259
         * each signature.  Therefore, if we had more
260
         * than one then we're dealing with multiple
261
         * signatures.  We don't support them
262
         * currently, and they're rather hard to
263
         * create, so something is likely fishy and we
264
         * should reject them altogether.
265
         */
266
0
        if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) {
267
0
          if (seen_exclusive_status++)
268
0
            goto error;
269
0
        }
270
271
0
        if (sigcheck_gpg_status[i].result)
272
0
          sigc->result = sigcheck_gpg_status[i].result;
273
        /* Do we have key information? */
274
0
        if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) {
275
0
          next = strchrnul(line, ' ');
276
0
          replace_cstring(&sigc->key, line, next);
277
          /* Do we have signer information? */
278
0
          if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
279
0
            line = next + 1;
280
0
            next = strchrnul(line, '\n');
281
0
            replace_cstring(&sigc->signer, line, next);
282
0
          }
283
0
        }
284
285
        /* Do we have trust level? */
286
0
        if (sigcheck_gpg_status[i].flags & GPG_STATUS_TRUST_LEVEL) {
287
          /*
288
           * GPG v1 and v2 differs in how the
289
           * TRUST_ lines are written.  Some
290
           * trust lines contain no additional
291
           * space-separated information for v1.
292
           */
293
0
          size_t trust_size = strcspn(line, " \n");
294
0
          char *trust = xmemdupz(line, trust_size);
295
296
0
          if (parse_gpg_trust_level(trust, &sigc->trust_level)) {
297
0
            free(trust);
298
0
            goto error;
299
0
          }
300
0
          free(trust);
301
0
        }
302
303
        /* Do we have fingerprint? */
304
0
        if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) {
305
0
          const char *limit;
306
0
          char **field;
307
308
0
          next = strchrnul(line, ' ');
309
0
          replace_cstring(&sigc->fingerprint, line, next);
310
311
          /*
312
           * Skip interim fields.  The search is
313
           * limited to the same line since only
314
           * OpenPGP signatures has a field with
315
           * the primary fingerprint.
316
           */
317
0
          limit = strchrnul(line, '\n');
318
0
          for (j = 9; j > 0; j--) {
319
0
            if (!*next || limit <= next)
320
0
              break;
321
0
            line = next + 1;
322
0
            next = strchrnul(line, ' ');
323
0
          }
324
325
0
          field = &sigc->primary_key_fingerprint;
326
0
          if (!j) {
327
0
            next = strchrnul(line, '\n');
328
0
            replace_cstring(field, line, next);
329
0
          } else {
330
0
            replace_cstring(field, NULL, NULL);
331
0
          }
332
0
        }
333
334
0
        break;
335
0
      }
336
0
    }
337
0
  }
338
0
  return;
339
340
0
error:
341
0
  sigc->result = 'E';
342
  /* Clear partial data to avoid confusion */
343
0
  FREE_AND_NULL(sigc->primary_key_fingerprint);
344
0
  FREE_AND_NULL(sigc->fingerprint);
345
0
  FREE_AND_NULL(sigc->signer);
346
0
  FREE_AND_NULL(sigc->key);
347
0
}
348
349
static int verify_gpg_signed_buffer(struct signature_check *sigc,
350
            struct gpg_format *fmt,
351
            const char *signature,
352
            size_t signature_size)
353
0
{
354
0
  struct child_process gpg = CHILD_PROCESS_INIT;
355
0
  struct tempfile *temp;
356
0
  int ret;
357
0
  struct strbuf gpg_stdout = STRBUF_INIT;
358
0
  struct strbuf gpg_stderr = STRBUF_INIT;
359
360
0
  temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
361
0
  if (!temp)
362
0
    return error_errno(_("could not create temporary file"));
363
0
  if (write_in_full(temp->fd, signature, signature_size) < 0 ||
364
0
      close_tempfile_gently(temp) < 0) {
365
0
    error_errno(_("failed writing detached signature to '%s'"),
366
0
          temp->filename.buf);
367
0
    delete_tempfile(&temp);
368
0
    return -1;
369
0
  }
370
371
0
  strvec_push(&gpg.args, fmt->program);
372
0
  strvec_pushv(&gpg.args, fmt->verify_args);
373
0
  strvec_pushl(&gpg.args,
374
0
         "--status-fd=1",
375
0
         "--verify", temp->filename.buf, "-",
376
0
         NULL);
377
378
0
  sigchain_push(SIGPIPE, SIG_IGN);
379
0
  ret = pipe_command(&gpg, sigc->payload, sigc->payload_len, &gpg_stdout, 0,
380
0
         &gpg_stderr, 0);
381
0
  sigchain_pop(SIGPIPE);
382
383
0
  delete_tempfile(&temp);
384
385
0
  ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG ");
386
0
  sigc->output = strbuf_detach(&gpg_stderr, NULL);
387
0
  sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
388
389
0
  parse_gpg_output(sigc);
390
391
0
  strbuf_release(&gpg_stdout);
392
0
  strbuf_release(&gpg_stderr);
393
394
0
  return ret;
395
0
}
396
397
static void parse_ssh_output(struct signature_check *sigc)
398
0
{
399
0
  const char *line, *principal, *search;
400
0
  char *to_free;
401
0
  char *key = NULL;
402
403
  /*
404
   * ssh-keygen output should be:
405
   * Good "git" signature for PRINCIPAL with RSA key SHA256:FINGERPRINT
406
   *
407
   * or for valid but unknown keys:
408
   * Good "git" signature with RSA key SHA256:FINGERPRINT
409
   *
410
   * Note that "PRINCIPAL" can contain whitespace, "RSA" and
411
   * "SHA256" part could be a different token that names of
412
   * the algorithms used, and "FINGERPRINT" is a hexadecimal
413
   * string.  By finding the last occurrence of " with ", we can
414
   * reliably parse out the PRINCIPAL.
415
   */
416
0
  sigc->result = 'B';
417
0
  sigc->trust_level = TRUST_NEVER;
418
419
0
  line = to_free = xmemdupz(sigc->output, strcspn(sigc->output, "\n"));
420
421
0
  if (skip_prefix(line, "Good \"git\" signature for ", &line)) {
422
    /* Search for the last "with" to get the full principal */
423
0
    principal = line;
424
0
    do {
425
0
      search = strstr(line, " with ");
426
0
      if (search)
427
0
        line = search + 1;
428
0
    } while (search != NULL);
429
0
    if (line == principal)
430
0
      goto cleanup;
431
432
    /* Valid signature and known principal */
433
0
    sigc->result = 'G';
434
0
    sigc->trust_level = TRUST_FULLY;
435
0
    sigc->signer = xmemdupz(principal, line - principal - 1);
436
0
  } else if (skip_prefix(line, "Good \"git\" signature with ", &line)) {
437
    /* Valid signature, but key unknown */
438
0
    sigc->result = 'G';
439
0
    sigc->trust_level = TRUST_UNDEFINED;
440
0
  } else {
441
0
    goto cleanup;
442
0
  }
443
444
0
  key = strstr(line, "key ");
445
0
  if (key) {
446
0
    sigc->fingerprint = xstrdup(key + 4);
447
0
    sigc->key = xstrdup(sigc->fingerprint);
448
0
  } else {
449
    /*
450
     * Output did not match what we expected
451
     * Treat the signature as bad
452
     */
453
0
    sigc->result = 'B';
454
0
  }
455
456
0
cleanup:
457
0
  free(to_free);
458
0
}
459
460
static int verify_ssh_signed_buffer(struct signature_check *sigc,
461
            struct gpg_format *fmt,
462
            const char *signature,
463
            size_t signature_size)
464
0
{
465
0
  struct child_process ssh_keygen = CHILD_PROCESS_INIT;
466
0
  struct tempfile *buffer_file;
467
0
  int ret = -1;
468
0
  const char *line;
469
0
  char *principal;
470
0
  struct strbuf ssh_principals_out = STRBUF_INIT;
471
0
  struct strbuf ssh_principals_err = STRBUF_INIT;
472
0
  struct strbuf ssh_keygen_out = STRBUF_INIT;
473
0
  struct strbuf ssh_keygen_err = STRBUF_INIT;
474
0
  struct strbuf verify_time = STRBUF_INIT;
475
0
  const struct date_mode verify_date_mode = {
476
0
    .type = DATE_STRFTIME,
477
0
    .strftime_fmt = "%Y%m%d%H%M%S",
478
    /* SSH signing key validity has no timezone information - Use the local timezone */
479
0
    .local = 1,
480
0
  };
481
482
0
  if (!ssh_allowed_signers) {
483
0
    error(_("gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification"));
484
0
    return -1;
485
0
  }
486
487
0
  buffer_file = mks_tempfile_t(".git_vtag_tmpXXXXXX");
488
0
  if (!buffer_file)
489
0
    return error_errno(_("could not create temporary file"));
490
0
  if (write_in_full(buffer_file->fd, signature, signature_size) < 0 ||
491
0
      close_tempfile_gently(buffer_file) < 0) {
492
0
    error_errno(_("failed writing detached signature to '%s'"),
493
0
          buffer_file->filename.buf);
494
0
    delete_tempfile(&buffer_file);
495
0
    return -1;
496
0
  }
497
498
0
  if (sigc->payload_timestamp)
499
0
    strbuf_addf(&verify_time, "-Overify-time=%s",
500
0
      show_date(sigc->payload_timestamp, 0, verify_date_mode));
501
502
  /* Find the principal from the signers */
503
0
  strvec_pushl(&ssh_keygen.args, fmt->program,
504
0
         "-Y", "find-principals",
505
0
         "-f", ssh_allowed_signers,
506
0
         "-s", buffer_file->filename.buf,
507
0
         verify_time.buf,
508
0
         NULL);
509
0
  ret = pipe_command(&ssh_keygen, NULL, 0, &ssh_principals_out, 0,
510
0
         &ssh_principals_err, 0);
511
0
  if (ret && strstr(ssh_principals_err.buf, "usage:")) {
512
0
    error(_("ssh-keygen -Y find-principals/verify is needed for ssh signature verification (available in openssh version 8.2p1+)"));
513
0
    goto out;
514
0
  }
515
0
  if (ret || !ssh_principals_out.len) {
516
    /*
517
     * We did not find a matching principal in the allowedSigners
518
     * Check without validation
519
     */
520
0
    child_process_init(&ssh_keygen);
521
0
    strvec_pushl(&ssh_keygen.args, fmt->program,
522
0
           "-Y", "check-novalidate",
523
0
           "-n", "git",
524
0
           "-s", buffer_file->filename.buf,
525
0
           verify_time.buf,
526
0
           NULL);
527
0
    pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
528
0
           &ssh_keygen_out, 0, &ssh_keygen_err, 0);
529
530
    /*
531
     * Fail on unknown keys
532
     * we still call check-novalidate to display the signature info
533
     */
534
0
    ret = -1;
535
0
  } else {
536
    /* Check every principal we found (one per line) */
537
0
    const char *next;
538
0
    for (line = ssh_principals_out.buf;
539
0
         *line;
540
0
         line = next) {
541
0
      const char *end_of_text;
542
543
0
      next = end_of_text = strchrnul(line, '\n');
544
545
       /* Did we find a LF, and did we have CR before it? */
546
0
      if (*end_of_text &&
547
0
          line < end_of_text &&
548
0
          end_of_text[-1] == '\r')
549
0
        end_of_text--;
550
551
      /* Unless we hit NUL, skip over the LF we found */
552
0
      if (*next)
553
0
        next++;
554
555
      /* Not all lines are data.  Skip empty ones */
556
0
      if (line == end_of_text)
557
0
        continue;
558
559
      /* We now know we have an non-empty line. Process it */
560
0
      principal = xmemdupz(line, end_of_text - line);
561
562
0
      child_process_init(&ssh_keygen);
563
0
      strbuf_release(&ssh_keygen_out);
564
0
      strbuf_release(&ssh_keygen_err);
565
0
      strvec_push(&ssh_keygen.args, fmt->program);
566
      /*
567
       * We found principals
568
       * Try with each until we find a match
569
       */
570
0
      strvec_pushl(&ssh_keygen.args, "-Y", "verify",
571
0
             "-n", "git",
572
0
             "-f", ssh_allowed_signers,
573
0
             "-I", principal,
574
0
             "-s", buffer_file->filename.buf,
575
0
             verify_time.buf,
576
0
             NULL);
577
578
0
      if (ssh_revocation_file) {
579
0
        if (file_exists(ssh_revocation_file)) {
580
0
          strvec_pushl(&ssh_keygen.args, "-r",
581
0
                 ssh_revocation_file, NULL);
582
0
        } else {
583
0
          warning(_("ssh signing revocation file configured but not found: %s"),
584
0
            ssh_revocation_file);
585
0
        }
586
0
      }
587
588
0
      sigchain_push(SIGPIPE, SIG_IGN);
589
0
      ret = pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
590
0
             &ssh_keygen_out, 0, &ssh_keygen_err, 0);
591
0
      sigchain_pop(SIGPIPE);
592
593
0
      FREE_AND_NULL(principal);
594
595
0
      if (!ret)
596
0
        ret = !starts_with(ssh_keygen_out.buf, "Good");
597
598
0
      if (!ret)
599
0
        break;
600
0
    }
601
0
  }
602
603
0
  strbuf_stripspace(&ssh_keygen_out, NULL);
604
0
  strbuf_stripspace(&ssh_keygen_err, NULL);
605
  /* Add stderr outputs to show the user actual ssh-keygen errors */
606
0
  strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
607
0
  strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
608
0
  sigc->output = strbuf_detach(&ssh_keygen_out, NULL);
609
0
  sigc->gpg_status = xstrdup(sigc->output);
610
611
0
  parse_ssh_output(sigc);
612
613
0
out:
614
0
  if (buffer_file)
615
0
    delete_tempfile(&buffer_file);
616
0
  strbuf_release(&ssh_principals_out);
617
0
  strbuf_release(&ssh_principals_err);
618
0
  strbuf_release(&ssh_keygen_out);
619
0
  strbuf_release(&ssh_keygen_err);
620
0
  strbuf_release(&verify_time);
621
622
0
  return ret;
623
0
}
624
625
static int parse_payload_metadata(struct signature_check *sigc)
626
0
{
627
0
  const char *ident_line = NULL;
628
0
  size_t ident_len;
629
0
  struct ident_split ident;
630
0
  const char *signer_header;
631
632
0
  switch (sigc->payload_type) {
633
0
  case SIGNATURE_PAYLOAD_COMMIT:
634
0
    signer_header = "committer";
635
0
    break;
636
0
  case SIGNATURE_PAYLOAD_TAG:
637
0
    signer_header = "tagger";
638
0
    break;
639
0
  case SIGNATURE_PAYLOAD_UNDEFINED:
640
0
  case SIGNATURE_PAYLOAD_PUSH_CERT:
641
    /* Ignore payloads we don't want to parse */
642
0
    return 0;
643
0
  default:
644
0
    BUG("invalid value for sigc->payload_type");
645
0
  }
646
647
0
  ident_line = find_commit_header(sigc->payload, signer_header, &ident_len);
648
0
  if (!ident_line || !ident_len)
649
0
    return 1;
650
651
0
  if (split_ident_line(&ident, ident_line, ident_len))
652
0
    return 1;
653
654
0
  if (!sigc->payload_timestamp && ident.date_begin && ident.date_end)
655
0
    sigc->payload_timestamp = parse_timestamp(ident.date_begin, NULL, 10);
656
657
0
  return 0;
658
0
}
659
660
int check_signature(struct signature_check *sigc,
661
        const char *signature, size_t slen)
662
0
{
663
0
  struct gpg_format *fmt;
664
0
  int status;
665
666
0
  gpg_interface_lazy_init();
667
668
0
  sigc->result = 'N';
669
0
  sigc->trust_level = TRUST_UNDEFINED;
670
671
0
  fmt = get_format_by_sig(signature);
672
0
  if (!fmt)
673
0
    die(_("bad/incompatible signature '%s'"), signature);
674
675
0
  if (parse_payload_metadata(sigc))
676
0
    return 1;
677
678
0
  status = fmt->verify_signed_buffer(sigc, fmt, signature, slen);
679
680
0
  if (status && !sigc->output)
681
0
    return !!status;
682
683
0
  status |= sigc->result != 'G';
684
0
  status |= sigc->trust_level < configured_min_trust_level;
685
686
0
  return !!status;
687
0
}
688
689
void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
690
0
{
691
0
  const char *output = flags & GPG_VERIFY_RAW ? sigc->gpg_status :
692
0
                  sigc->output;
693
694
0
  if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
695
0
    fwrite(sigc->payload, 1, sigc->payload_len, stdout);
696
697
0
  if (output)
698
0
    fputs(output, stderr);
699
0
}
700
701
size_t parse_signed_buffer(const char *buf, size_t size)
702
0
{
703
0
  size_t len = 0;
704
0
  size_t match = size;
705
0
  while (len < size) {
706
0
    const char *eol;
707
708
0
    if (get_format_by_sig(buf + len))
709
0
      match = len;
710
711
0
    eol = memchr(buf + len, '\n', size - len);
712
0
    len += eol ? (size_t) (eol - (buf + len) + 1) : size - len;
713
0
  }
714
0
  return match;
715
0
}
716
717
int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
718
0
{
719
0
  size_t match = parse_signed_buffer(buf, size);
720
0
  if (match != size) {
721
0
    strbuf_add(payload, buf, match);
722
0
    remove_signature(payload);
723
0
    strbuf_add(signature, buf + match, size - match);
724
0
    return 1;
725
0
  }
726
0
  return 0;
727
0
}
728
729
void set_signing_key(const char *key)
730
0
{
731
0
  gpg_interface_lazy_init();
732
733
0
  free(configured_signing_key);
734
0
  configured_signing_key = xstrdup(key);
735
0
}
736
737
static int git_gpg_config(const char *var, const char *value,
738
        const struct config_context *ctx UNUSED,
739
        void *cb UNUSED)
740
0
{
741
0
  struct gpg_format *fmt = NULL;
742
0
  const char *fmtname = NULL;
743
0
  char *trust;
744
0
  int ret;
745
746
0
  if (!strcmp(var, "user.signingkey")) {
747
0
    if (!value)
748
0
      return config_error_nonbool(var);
749
0
    set_signing_key(value);
750
0
    return 0;
751
0
  }
752
753
0
  if (!strcmp(var, "gpg.format")) {
754
0
    if (!value)
755
0
      return config_error_nonbool(var);
756
0
    fmt = get_format_by_name(value);
757
0
    if (!fmt)
758
0
      return error(_("invalid value for '%s': '%s'"),
759
0
             var, value);
760
0
    use_format = fmt;
761
0
    return 0;
762
0
  }
763
764
0
  if (!strcmp(var, "gpg.mintrustlevel")) {
765
0
    if (!value)
766
0
      return config_error_nonbool(var);
767
768
0
    trust = xstrdup_toupper(value);
769
0
    ret = parse_gpg_trust_level(trust, &configured_min_trust_level);
770
0
    free(trust);
771
772
0
    if (ret)
773
0
      return error(_("invalid value for '%s': '%s'"),
774
0
             var, value);
775
0
    return 0;
776
0
  }
777
778
0
  if (!strcmp(var, "gpg.ssh.defaultkeycommand"))
779
0
    return git_config_string(&ssh_default_key_command, var, value);
780
781
0
  if (!strcmp(var, "gpg.ssh.allowedsignersfile"))
782
0
    return git_config_pathname(&ssh_allowed_signers, var, value);
783
784
0
  if (!strcmp(var, "gpg.ssh.revocationfile"))
785
0
    return git_config_pathname(&ssh_revocation_file, var, value);
786
787
0
  if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
788
0
    fmtname = "openpgp";
789
790
0
  if (!strcmp(var, "gpg.x509.program"))
791
0
    fmtname = "x509";
792
793
0
  if (!strcmp(var, "gpg.ssh.program"))
794
0
    fmtname = "ssh";
795
796
0
  if (fmtname) {
797
0
    char *program;
798
0
    int status;
799
800
0
    fmt = get_format_by_name(fmtname);
801
0
    status = git_config_pathname(&program, var, value);
802
0
    if (status)
803
0
      return status;
804
0
    if (program)
805
0
      fmt->program = program;
806
0
    return status;
807
0
  }
808
809
0
  return 0;
810
0
}
811
812
/*
813
 * Returns 1 if `string` contains a literal ssh key, 0 otherwise
814
 * `key` will be set to the start of the actual key if a prefix is present.
815
 */
816
static int is_literal_ssh_key(const char *string, const char **key)
817
0
{
818
0
  if (skip_prefix(string, "key::", key))
819
0
    return 1;
820
0
  if (starts_with(string, "ssh-")) {
821
0
    *key = string;
822
0
    return 1;
823
0
  }
824
0
  return 0;
825
0
}
826
827
static char *get_ssh_key_fingerprint(const char *signing_key)
828
0
{
829
0
  struct child_process ssh_keygen = CHILD_PROCESS_INIT;
830
0
  int ret = -1;
831
0
  struct strbuf fingerprint_stdout = STRBUF_INIT;
832
0
  char *fingerprint_ret, *begin, *delim;
833
0
  const char *literal_key = NULL;
834
835
  /*
836
   * With SSH Signing this can contain a filename or a public key
837
   * For textual representation we usually want a fingerprint
838
   */
839
0
  if (is_literal_ssh_key(signing_key, &literal_key)) {
840
0
    strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf", "-", NULL);
841
0
    ret = pipe_command(&ssh_keygen, literal_key,
842
0
           strlen(literal_key), &fingerprint_stdout, 0,
843
0
           NULL, 0);
844
0
  } else {
845
0
    strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf",
846
0
           configured_signing_key, NULL);
847
0
    ret = pipe_command(&ssh_keygen, NULL, 0, &fingerprint_stdout, 0,
848
0
           NULL, 0);
849
0
  }
850
851
0
  if (!!ret)
852
0
    die_errno(_("failed to get the ssh fingerprint for key '%s'"),
853
0
        signing_key);
854
855
0
  begin = fingerprint_stdout.buf;
856
0
  delim = strchr(begin, ' ');
857
0
  if (!delim)
858
0
    die(_("failed to get the ssh fingerprint for key %s"),
859
0
        signing_key);
860
0
  begin = delim + 1;
861
0
  delim = strchr(begin, ' ');
862
0
  if (!delim)
863
0
      die(_("failed to get the ssh fingerprint for key %s"),
864
0
        signing_key);
865
0
  fingerprint_ret = xmemdupz(begin, delim - begin);
866
0
  strbuf_release(&fingerprint_stdout);
867
0
  return fingerprint_ret;
868
0
}
869
870
/* Returns the first public key from an ssh-agent to use for signing */
871
static char *get_default_ssh_signing_key(void)
872
0
{
873
0
  struct child_process ssh_default_key = CHILD_PROCESS_INIT;
874
0
  int ret = -1;
875
0
  struct strbuf key_stdout = STRBUF_INIT, key_stderr = STRBUF_INIT;
876
0
  char *key_command = NULL;
877
0
  const char **argv;
878
0
  int n;
879
0
  char *default_key = NULL;
880
0
  const char *literal_key = NULL;
881
0
  char *begin, *new_line, *first_line;
882
883
0
  if (!ssh_default_key_command)
884
0
    die(_("either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"));
885
886
0
  key_command = xstrdup(ssh_default_key_command);
887
0
  n = split_cmdline(key_command, &argv);
888
889
0
  if (n < 0)
890
0
    die(_("malformed build-time gpg.ssh.defaultKeyCommand: %s"),
891
0
        split_cmdline_strerror(n));
892
893
0
  strvec_pushv(&ssh_default_key.args, argv);
894
0
  ret = pipe_command(&ssh_default_key, NULL, 0, &key_stdout, 0,
895
0
         &key_stderr, 0);
896
897
0
  if (!ret) {
898
0
    begin = key_stdout.buf;
899
0
    new_line = strchr(begin, '\n');
900
0
    if (new_line)
901
0
      first_line = xmemdupz(begin, new_line - begin);
902
0
    else
903
0
      first_line = xstrdup(begin);
904
0
    if (is_literal_ssh_key(first_line, &literal_key)) {
905
      /*
906
       * We only use `is_literal_ssh_key` here to check validity
907
       * The prefix will be stripped when the key is used.
908
       */
909
0
      default_key = first_line;
910
0
    } else {
911
0
      free(first_line);
912
0
      warning(_("gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"),
913
0
        key_stderr.buf, key_stdout.buf);
914
0
    }
915
916
0
  } else {
917
0
    warning(_("gpg.ssh.defaultKeyCommand failed: %s %s"),
918
0
      key_stderr.buf, key_stdout.buf);
919
0
  }
920
921
0
  free(key_command);
922
0
  free(argv);
923
0
  strbuf_release(&key_stdout);
924
925
0
  return default_key;
926
0
}
927
928
static char *get_ssh_key_id(void)
929
0
{
930
0
  char *signing_key = get_signing_key();
931
0
  char *key_id = get_ssh_key_fingerprint(signing_key);
932
0
  free(signing_key);
933
0
  return key_id;
934
0
}
935
936
/* Returns a textual but unique representation of the signing key */
937
char *get_signing_key_id(void)
938
0
{
939
0
  gpg_interface_lazy_init();
940
941
0
  if (use_format->get_key_id) {
942
0
    return use_format->get_key_id();
943
0
  }
944
945
  /* GPG/GPGSM only store a key id on this variable */
946
0
  return get_signing_key();
947
0
}
948
949
char *get_signing_key(void)
950
0
{
951
0
  gpg_interface_lazy_init();
952
953
0
  if (configured_signing_key)
954
0
    return xstrdup(configured_signing_key);
955
0
  if (use_format->get_default_key) {
956
0
    return use_format->get_default_key();
957
0
  }
958
959
0
  return xstrdup(git_committer_info(IDENT_STRICT | IDENT_NO_DATE));
960
0
}
961
962
const char *gpg_trust_level_to_str(enum signature_trust_level level)
963
0
{
964
0
  struct sigcheck_gpg_trust_level *trust;
965
966
0
  if (level < 0 || level >= ARRAY_SIZE(sigcheck_gpg_trust_level))
967
0
    BUG("invalid trust level requested %d", level);
968
969
0
  trust = &sigcheck_gpg_trust_level[level];
970
0
  if (trust->value != level)
971
0
    BUG("sigcheck_gpg_trust_level[] unsorted");
972
973
0
  return sigcheck_gpg_trust_level[level].display_key;
974
0
}
975
976
int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
977
0
{
978
0
  gpg_interface_lazy_init();
979
980
0
  return use_format->sign_buffer(buffer, signature, signing_key);
981
0
}
982
983
/*
984
 * Strip CR from the line endings, in case we are on Windows.
985
 * NEEDSWORK: make it trim only CRs before LFs and rename
986
 */
987
static void remove_cr_after(struct strbuf *buffer, size_t offset)
988
0
{
989
0
  size_t i, j;
990
991
0
  for (i = j = offset; i < buffer->len; i++) {
992
0
    if (buffer->buf[i] != '\r') {
993
0
      if (i != j)
994
0
        buffer->buf[j] = buffer->buf[i];
995
0
      j++;
996
0
    }
997
0
  }
998
0
  strbuf_setlen(buffer, j);
999
0
}
1000
1001
static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
1002
        const char *signing_key)
1003
0
{
1004
0
  struct child_process gpg = CHILD_PROCESS_INIT;
1005
0
  int ret;
1006
0
  size_t bottom;
1007
0
  const char *cp;
1008
0
  struct strbuf gpg_status = STRBUF_INIT;
1009
1010
0
  strvec_pushl(&gpg.args,
1011
0
         use_format->program,
1012
0
         "--status-fd=2",
1013
0
         "-bsau", signing_key,
1014
0
         NULL);
1015
1016
0
  bottom = signature->len;
1017
1018
  /*
1019
   * When the username signingkey is bad, program could be terminated
1020
   * because gpg exits without reading and then write gets SIGPIPE.
1021
   */
1022
0
  sigchain_push(SIGPIPE, SIG_IGN);
1023
0
  ret = pipe_command(&gpg, buffer->buf, buffer->len,
1024
0
         signature, 1024, &gpg_status, 0);
1025
0
  sigchain_pop(SIGPIPE);
1026
1027
0
  for (cp = gpg_status.buf;
1028
0
       cp && (cp = strstr(cp, "[GNUPG:] SIG_CREATED "));
1029
0
       cp++) {
1030
0
    if (cp == gpg_status.buf || cp[-1] == '\n')
1031
0
      break; /* found */
1032
0
  }
1033
0
  ret |= !cp;
1034
0
  if (ret) {
1035
0
    error(_("gpg failed to sign the data:\n%s"),
1036
0
          gpg_status.len ? gpg_status.buf : "(no gpg output)");
1037
0
    strbuf_release(&gpg_status);
1038
0
    return -1;
1039
0
  }
1040
0
  strbuf_release(&gpg_status);
1041
1042
  /* Strip CR from the line endings, in case we are on Windows. */
1043
0
  remove_cr_after(signature, bottom);
1044
1045
0
  return 0;
1046
0
}
1047
1048
static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
1049
         const char *signing_key)
1050
0
{
1051
0
  struct child_process signer = CHILD_PROCESS_INIT;
1052
0
  int ret = -1;
1053
0
  size_t bottom, keylen;
1054
0
  struct strbuf signer_stderr = STRBUF_INIT;
1055
0
  struct tempfile *key_file = NULL, *buffer_file = NULL;
1056
0
  char *ssh_signing_key_file = NULL;
1057
0
  struct strbuf ssh_signature_filename = STRBUF_INIT;
1058
0
  const char *literal_key = NULL;
1059
0
  int literal_ssh_key = 0;
1060
1061
0
  if (!signing_key || signing_key[0] == '\0')
1062
0
    return error(
1063
0
      _("user.signingKey needs to be set for ssh signing"));
1064
1065
0
  if (is_literal_ssh_key(signing_key, &literal_key)) {
1066
    /* A literal ssh key */
1067
0
    literal_ssh_key = 1;
1068
0
    key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
1069
0
    if (!key_file)
1070
0
      return error_errno(
1071
0
        _("could not create temporary file"));
1072
0
    keylen = strlen(literal_key);
1073
0
    if (write_in_full(key_file->fd, literal_key, keylen) < 0 ||
1074
0
        close_tempfile_gently(key_file) < 0) {
1075
0
      error_errno(_("failed writing ssh signing key to '%s'"),
1076
0
            key_file->filename.buf);
1077
0
      goto out;
1078
0
    }
1079
0
    ssh_signing_key_file = xstrdup(key_file->filename.buf);
1080
0
  } else {
1081
    /* We assume a file */
1082
0
    ssh_signing_key_file = interpolate_path(signing_key, 1);
1083
0
  }
1084
1085
0
  buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
1086
0
  if (!buffer_file) {
1087
0
    error_errno(_("could not create temporary file"));
1088
0
    goto out;
1089
0
  }
1090
1091
0
  if (write_in_full(buffer_file->fd, buffer->buf, buffer->len) < 0 ||
1092
0
      close_tempfile_gently(buffer_file) < 0) {
1093
0
    error_errno(_("failed writing ssh signing key buffer to '%s'"),
1094
0
          buffer_file->filename.buf);
1095
0
    goto out;
1096
0
  }
1097
1098
0
  strvec_pushl(&signer.args, use_format->program,
1099
0
         "-Y", "sign",
1100
0
         "-n", "git",
1101
0
         "-f", ssh_signing_key_file,
1102
0
         NULL);
1103
0
  if (literal_ssh_key)
1104
0
    strvec_push(&signer.args, "-U");
1105
0
  strvec_push(&signer.args, buffer_file->filename.buf);
1106
1107
0
  sigchain_push(SIGPIPE, SIG_IGN);
1108
0
  ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
1109
0
  sigchain_pop(SIGPIPE);
1110
1111
0
  if (ret) {
1112
0
    if (strstr(signer_stderr.buf, "usage:"))
1113
0
      error(_("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)"));
1114
1115
0
    ret = error("%s", signer_stderr.buf);
1116
0
    goto out;
1117
0
  }
1118
1119
0
  bottom = signature->len;
1120
1121
0
  strbuf_addbuf(&ssh_signature_filename, &buffer_file->filename);
1122
0
  strbuf_addstr(&ssh_signature_filename, ".sig");
1123
0
  if (strbuf_read_file(signature, ssh_signature_filename.buf, 0) < 0) {
1124
0
    ret = error_errno(
1125
0
      _("failed reading ssh signing data buffer from '%s'"),
1126
0
      ssh_signature_filename.buf);
1127
0
    goto out;
1128
0
  }
1129
  /* Strip CR from the line endings, in case we are on Windows. */
1130
0
  remove_cr_after(signature, bottom);
1131
1132
0
out:
1133
0
  if (key_file)
1134
0
    delete_tempfile(&key_file);
1135
0
  if (buffer_file)
1136
0
    delete_tempfile(&buffer_file);
1137
0
  if (ssh_signature_filename.len)
1138
0
    unlink_or_warn(ssh_signature_filename.buf);
1139
0
  strbuf_release(&signer_stderr);
1140
0
  strbuf_release(&ssh_signature_filename);
1141
0
  FREE_AND_NULL(ssh_signing_key_file);
1142
0
  return ret;
1143
0
}
1144
1145
int parse_sign_mode(const char *arg, enum sign_mode *mode)
1146
0
{
1147
0
  if (!strcmp(arg, "abort"))
1148
0
    *mode = SIGN_ABORT;
1149
0
  else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
1150
0
    *mode = SIGN_VERBATIM;
1151
0
  else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
1152
0
    *mode = SIGN_WARN_VERBATIM;
1153
0
  else if (!strcmp(arg, "warn-strip"))
1154
0
    *mode = SIGN_WARN_STRIP;
1155
0
  else if (!strcmp(arg, "strip"))
1156
0
    *mode = SIGN_STRIP;
1157
0
  else if (!strcmp(arg, "strip-if-invalid"))
1158
0
    *mode = SIGN_STRIP_IF_INVALID;
1159
0
  else
1160
0
    return -1;
1161
0
  return 0;
1162
0
}