Coverage Report

Created: 2026-03-21 06:46

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
         !strstr(gpg_stdout.buf, "\n[GNUPG:] EXPKEYSIG ");
387
0
  sigc->output = strbuf_detach(&gpg_stderr, NULL);
388
0
  sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
389
390
0
  parse_gpg_output(sigc);
391
392
0
  strbuf_release(&gpg_stdout);
393
0
  strbuf_release(&gpg_stderr);
394
395
0
  return ret;
396
0
}
397
398
static void parse_ssh_output(struct signature_check *sigc)
399
0
{
400
0
  const char *line, *principal, *search;
401
0
  char *to_free;
402
0
  const char *key;
403
404
  /*
405
   * ssh-keygen output should be:
406
   * Good "git" signature for PRINCIPAL with RSA key SHA256:FINGERPRINT
407
   *
408
   * or for valid but unknown keys:
409
   * Good "git" signature with RSA key SHA256:FINGERPRINT
410
   *
411
   * Note that "PRINCIPAL" can contain whitespace, "RSA" and
412
   * "SHA256" part could be a different token that names of
413
   * the algorithms used, and "FINGERPRINT" is a hexadecimal
414
   * string.  By finding the last occurrence of " with ", we can
415
   * reliably parse out the PRINCIPAL.
416
   */
417
0
  sigc->result = 'B';
418
0
  sigc->trust_level = TRUST_NEVER;
419
420
0
  line = to_free = xmemdupz(sigc->output, strcspn(sigc->output, "\n"));
421
422
0
  if (skip_prefix(line, "Good \"git\" signature for ", &line)) {
423
    /* Search for the last "with" to get the full principal */
424
0
    principal = line;
425
0
    do {
426
0
      search = strstr(line, " with ");
427
0
      if (search)
428
0
        line = search + 1;
429
0
    } while (search != NULL);
430
0
    if (line == principal)
431
0
      goto cleanup;
432
433
    /* Valid signature and known principal */
434
0
    sigc->result = 'G';
435
0
    sigc->trust_level = TRUST_FULLY;
436
0
    sigc->signer = xmemdupz(principal, line - principal - 1);
437
0
  } else if (skip_prefix(line, "Good \"git\" signature with ", &line)) {
438
    /* Valid signature, but key unknown */
439
0
    sigc->result = 'G';
440
0
    sigc->trust_level = TRUST_UNDEFINED;
441
0
  } else {
442
0
    goto cleanup;
443
0
  }
444
445
0
  key = strstr(line, "key ");
446
0
  if (key) {
447
0
    sigc->fingerprint = xstrdup(key + 4);
448
0
    sigc->key = xstrdup(sigc->fingerprint);
449
0
  } else {
450
    /*
451
     * Output did not match what we expected
452
     * Treat the signature as bad
453
     */
454
0
    sigc->result = 'B';
455
0
  }
456
457
0
cleanup:
458
0
  free(to_free);
459
0
}
460
461
static int verify_ssh_signed_buffer(struct signature_check *sigc,
462
            struct gpg_format *fmt,
463
            const char *signature,
464
            size_t signature_size)
465
0
{
466
0
  struct child_process ssh_keygen = CHILD_PROCESS_INIT;
467
0
  struct tempfile *buffer_file;
468
0
  int ret = -1;
469
0
  const char *line;
470
0
  char *principal;
471
0
  struct strbuf ssh_principals_out = STRBUF_INIT;
472
0
  struct strbuf ssh_principals_err = STRBUF_INIT;
473
0
  struct strbuf ssh_keygen_out = STRBUF_INIT;
474
0
  struct strbuf ssh_keygen_err = STRBUF_INIT;
475
0
  struct strbuf verify_time = STRBUF_INIT;
476
0
  const struct date_mode verify_date_mode = {
477
0
    .type = DATE_STRFTIME,
478
0
    .strftime_fmt = "%Y%m%d%H%M%S",
479
    /* SSH signing key validity has no timezone information - Use the local timezone */
480
0
    .local = 1,
481
0
  };
482
483
0
  if (!ssh_allowed_signers) {
484
0
    error(_("gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification"));
485
0
    return -1;
486
0
  }
487
488
0
  buffer_file = mks_tempfile_t(".git_vtag_tmpXXXXXX");
489
0
  if (!buffer_file)
490
0
    return error_errno(_("could not create temporary file"));
491
0
  if (write_in_full(buffer_file->fd, signature, signature_size) < 0 ||
492
0
      close_tempfile_gently(buffer_file) < 0) {
493
0
    error_errno(_("failed writing detached signature to '%s'"),
494
0
          buffer_file->filename.buf);
495
0
    delete_tempfile(&buffer_file);
496
0
    return -1;
497
0
  }
498
499
0
  if (sigc->payload_timestamp)
500
0
    strbuf_addf(&verify_time, "-Overify-time=%s",
501
0
      show_date(sigc->payload_timestamp, 0, verify_date_mode));
502
503
  /* Find the principal from the signers */
504
0
  strvec_pushl(&ssh_keygen.args, fmt->program,
505
0
         "-Y", "find-principals",
506
0
         "-f", ssh_allowed_signers,
507
0
         "-s", buffer_file->filename.buf,
508
0
         verify_time.buf,
509
0
         NULL);
510
0
  ret = pipe_command(&ssh_keygen, NULL, 0, &ssh_principals_out, 0,
511
0
         &ssh_principals_err, 0);
512
0
  if (ret && strstr(ssh_principals_err.buf, "usage:")) {
513
0
    error(_("ssh-keygen -Y find-principals/verify is needed for ssh signature verification (available in openssh version 8.2p1+)"));
514
0
    goto out;
515
0
  }
516
0
  if (ret || !ssh_principals_out.len) {
517
    /*
518
     * We did not find a matching principal in the allowedSigners
519
     * Check without validation
520
     */
521
0
    child_process_init(&ssh_keygen);
522
0
    strvec_pushl(&ssh_keygen.args, fmt->program,
523
0
           "-Y", "check-novalidate",
524
0
           "-n", "git",
525
0
           "-s", buffer_file->filename.buf,
526
0
           verify_time.buf,
527
0
           NULL);
528
0
    pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
529
0
           &ssh_keygen_out, 0, &ssh_keygen_err, 0);
530
531
    /*
532
     * Fail on unknown keys
533
     * we still call check-novalidate to display the signature info
534
     */
535
0
    ret = -1;
536
0
  } else {
537
    /* Check every principal we found (one per line) */
538
0
    const char *next;
539
0
    for (line = ssh_principals_out.buf;
540
0
         *line;
541
0
         line = next) {
542
0
      const char *end_of_text;
543
544
0
      next = end_of_text = strchrnul(line, '\n');
545
546
       /* Did we find a LF, and did we have CR before it? */
547
0
      if (*end_of_text &&
548
0
          line < end_of_text &&
549
0
          end_of_text[-1] == '\r')
550
0
        end_of_text--;
551
552
      /* Unless we hit NUL, skip over the LF we found */
553
0
      if (*next)
554
0
        next++;
555
556
      /* Not all lines are data.  Skip empty ones */
557
0
      if (line == end_of_text)
558
0
        continue;
559
560
      /* We now know we have an non-empty line. Process it */
561
0
      principal = xmemdupz(line, end_of_text - line);
562
563
0
      child_process_init(&ssh_keygen);
564
0
      strbuf_release(&ssh_keygen_out);
565
0
      strbuf_release(&ssh_keygen_err);
566
0
      strvec_push(&ssh_keygen.args, fmt->program);
567
      /*
568
       * We found principals
569
       * Try with each until we find a match
570
       */
571
0
      strvec_pushl(&ssh_keygen.args, "-Y", "verify",
572
0
             "-n", "git",
573
0
             "-f", ssh_allowed_signers,
574
0
             "-I", principal,
575
0
             "-s", buffer_file->filename.buf,
576
0
             verify_time.buf,
577
0
             NULL);
578
579
0
      if (ssh_revocation_file) {
580
0
        if (file_exists(ssh_revocation_file)) {
581
0
          strvec_pushl(&ssh_keygen.args, "-r",
582
0
                 ssh_revocation_file, NULL);
583
0
        } else {
584
0
          warning(_("ssh signing revocation file configured but not found: %s"),
585
0
            ssh_revocation_file);
586
0
        }
587
0
      }
588
589
0
      sigchain_push(SIGPIPE, SIG_IGN);
590
0
      ret = pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
591
0
             &ssh_keygen_out, 0, &ssh_keygen_err, 0);
592
0
      sigchain_pop(SIGPIPE);
593
594
0
      FREE_AND_NULL(principal);
595
596
0
      if (!ret)
597
0
        ret = !starts_with(ssh_keygen_out.buf, "Good");
598
599
0
      if (!ret)
600
0
        break;
601
0
    }
602
0
  }
603
604
0
  strbuf_stripspace(&ssh_keygen_out, NULL);
605
0
  strbuf_stripspace(&ssh_keygen_err, NULL);
606
  /* Add stderr outputs to show the user actual ssh-keygen errors */
607
0
  strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
608
0
  strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
609
0
  sigc->output = strbuf_detach(&ssh_keygen_out, NULL);
610
0
  sigc->gpg_status = xstrdup(sigc->output);
611
612
0
  parse_ssh_output(sigc);
613
614
0
out:
615
0
  if (buffer_file)
616
0
    delete_tempfile(&buffer_file);
617
0
  strbuf_release(&ssh_principals_out);
618
0
  strbuf_release(&ssh_principals_err);
619
0
  strbuf_release(&ssh_keygen_out);
620
0
  strbuf_release(&ssh_keygen_err);
621
0
  strbuf_release(&verify_time);
622
623
0
  return ret;
624
0
}
625
626
static int parse_payload_metadata(struct signature_check *sigc)
627
0
{
628
0
  const char *ident_line = NULL;
629
0
  size_t ident_len;
630
0
  struct ident_split ident;
631
0
  const char *signer_header;
632
633
0
  switch (sigc->payload_type) {
634
0
  case SIGNATURE_PAYLOAD_COMMIT:
635
0
    signer_header = "committer";
636
0
    break;
637
0
  case SIGNATURE_PAYLOAD_TAG:
638
0
    signer_header = "tagger";
639
0
    break;
640
0
  case SIGNATURE_PAYLOAD_UNDEFINED:
641
0
  case SIGNATURE_PAYLOAD_PUSH_CERT:
642
    /* Ignore payloads we don't want to parse */
643
0
    return 0;
644
0
  default:
645
0
    BUG("invalid value for sigc->payload_type");
646
0
  }
647
648
0
  ident_line = find_commit_header(sigc->payload, signer_header, &ident_len);
649
0
  if (!ident_line || !ident_len)
650
0
    return 1;
651
652
0
  if (split_ident_line(&ident, ident_line, ident_len))
653
0
    return 1;
654
655
0
  if (!sigc->payload_timestamp && ident.date_begin && ident.date_end)
656
0
    sigc->payload_timestamp = parse_timestamp(ident.date_begin, NULL, 10);
657
658
0
  return 0;
659
0
}
660
661
int check_signature(struct signature_check *sigc,
662
        const char *signature, size_t slen)
663
0
{
664
0
  struct gpg_format *fmt;
665
0
  int status;
666
667
0
  gpg_interface_lazy_init();
668
669
0
  sigc->result = 'N';
670
0
  sigc->trust_level = TRUST_UNDEFINED;
671
672
0
  fmt = get_format_by_sig(signature);
673
0
  if (!fmt)
674
0
    die(_("bad/incompatible signature '%s'"), signature);
675
676
0
  if (parse_payload_metadata(sigc))
677
0
    return 1;
678
679
0
  status = fmt->verify_signed_buffer(sigc, fmt, signature, slen);
680
681
0
  if (status && !sigc->output)
682
0
    return !!status;
683
684
0
  status |= sigc->result != 'G' && sigc->result != 'Y';
685
0
  status |= sigc->trust_level < configured_min_trust_level;
686
687
0
  return !!status;
688
0
}
689
690
void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
691
0
{
692
0
  const char *output = flags & GPG_VERIFY_RAW ? sigc->gpg_status :
693
0
                  sigc->output;
694
695
0
  if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
696
0
    fwrite(sigc->payload, 1, sigc->payload_len, stdout);
697
698
0
  if (output)
699
0
    fputs(output, stderr);
700
0
}
701
702
size_t parse_signed_buffer(const char *buf, size_t size)
703
0
{
704
0
  size_t len = 0;
705
0
  size_t match = size;
706
0
  while (len < size) {
707
0
    const char *eol;
708
709
0
    if (get_format_by_sig(buf + len))
710
0
      match = len;
711
712
0
    eol = memchr(buf + len, '\n', size - len);
713
0
    len += eol ? (size_t) (eol - (buf + len) + 1) : size - len;
714
0
  }
715
0
  return match;
716
0
}
717
718
int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
719
0
{
720
0
  size_t match = parse_signed_buffer(buf, size);
721
0
  if (match != size) {
722
0
    strbuf_add(payload, buf, match);
723
0
    remove_signature(payload);
724
0
    strbuf_add(signature, buf + match, size - match);
725
0
    return 1;
726
0
  }
727
0
  return 0;
728
0
}
729
730
void set_signing_key(const char *key)
731
0
{
732
0
  gpg_interface_lazy_init();
733
734
0
  free(configured_signing_key);
735
0
  configured_signing_key = xstrdup(key);
736
0
}
737
738
static int git_gpg_config(const char *var, const char *value,
739
        const struct config_context *ctx UNUSED,
740
        void *cb UNUSED)
741
0
{
742
0
  struct gpg_format *fmt = NULL;
743
0
  const char *fmtname = NULL;
744
0
  char *trust;
745
0
  int ret;
746
747
0
  if (!strcmp(var, "user.signingkey")) {
748
0
    if (!value)
749
0
      return config_error_nonbool(var);
750
0
    set_signing_key(value);
751
0
    return 0;
752
0
  }
753
754
0
  if (!strcmp(var, "gpg.format")) {
755
0
    if (!value)
756
0
      return config_error_nonbool(var);
757
0
    fmt = get_format_by_name(value);
758
0
    if (!fmt)
759
0
      return error(_("invalid value for '%s': '%s'"),
760
0
             var, value);
761
0
    use_format = fmt;
762
0
    return 0;
763
0
  }
764
765
0
  if (!strcmp(var, "gpg.mintrustlevel")) {
766
0
    if (!value)
767
0
      return config_error_nonbool(var);
768
769
0
    trust = xstrdup_toupper(value);
770
0
    ret = parse_gpg_trust_level(trust, &configured_min_trust_level);
771
0
    free(trust);
772
773
0
    if (ret)
774
0
      return error(_("invalid value for '%s': '%s'"),
775
0
             var, value);
776
0
    return 0;
777
0
  }
778
779
0
  if (!strcmp(var, "gpg.ssh.defaultkeycommand"))
780
0
    return git_config_string(&ssh_default_key_command, var, value);
781
782
0
  if (!strcmp(var, "gpg.ssh.allowedsignersfile"))
783
0
    return git_config_pathname(&ssh_allowed_signers, var, value);
784
785
0
  if (!strcmp(var, "gpg.ssh.revocationfile"))
786
0
    return git_config_pathname(&ssh_revocation_file, var, value);
787
788
0
  if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
789
0
    fmtname = "openpgp";
790
791
0
  if (!strcmp(var, "gpg.x509.program"))
792
0
    fmtname = "x509";
793
794
0
  if (!strcmp(var, "gpg.ssh.program"))
795
0
    fmtname = "ssh";
796
797
0
  if (fmtname) {
798
0
    char *program;
799
0
    int status;
800
801
0
    fmt = get_format_by_name(fmtname);
802
0
    status = git_config_pathname(&program, var, value);
803
0
    if (status)
804
0
      return status;
805
0
    if (program)
806
0
      fmt->program = program;
807
0
    return status;
808
0
  }
809
810
0
  return 0;
811
0
}
812
813
/*
814
 * Returns 1 if `string` contains a literal ssh key, 0 otherwise
815
 * `key` will be set to the start of the actual key if a prefix is present.
816
 */
817
static int is_literal_ssh_key(const char *string, const char **key)
818
0
{
819
0
  if (skip_prefix(string, "key::", key))
820
0
    return 1;
821
0
  if (starts_with(string, "ssh-")) {
822
0
    *key = string;
823
0
    return 1;
824
0
  }
825
0
  return 0;
826
0
}
827
828
static char *get_ssh_key_fingerprint(const char *signing_key)
829
0
{
830
0
  struct child_process ssh_keygen = CHILD_PROCESS_INIT;
831
0
  int ret = -1;
832
0
  struct strbuf fingerprint_stdout = STRBUF_INIT;
833
0
  char *fingerprint_ret, *begin, *delim;
834
0
  const char *literal_key = NULL;
835
836
  /*
837
   * With SSH Signing this can contain a filename or a public key
838
   * For textual representation we usually want a fingerprint
839
   */
840
0
  if (is_literal_ssh_key(signing_key, &literal_key)) {
841
0
    strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf", "-", NULL);
842
0
    ret = pipe_command(&ssh_keygen, literal_key,
843
0
           strlen(literal_key), &fingerprint_stdout, 0,
844
0
           NULL, 0);
845
0
  } else {
846
0
    strvec_pushl(&ssh_keygen.args, "ssh-keygen", "-lf",
847
0
           configured_signing_key, NULL);
848
0
    ret = pipe_command(&ssh_keygen, NULL, 0, &fingerprint_stdout, 0,
849
0
           NULL, 0);
850
0
  }
851
852
0
  if (!!ret)
853
0
    die_errno(_("failed to get the ssh fingerprint for key '%s'"),
854
0
        signing_key);
855
856
0
  begin = fingerprint_stdout.buf;
857
0
  delim = strchr(begin, ' ');
858
0
  if (!delim)
859
0
    die(_("failed to get the ssh fingerprint for key %s"),
860
0
        signing_key);
861
0
  begin = delim + 1;
862
0
  delim = strchr(begin, ' ');
863
0
  if (!delim)
864
0
      die(_("failed to get the ssh fingerprint for key %s"),
865
0
        signing_key);
866
0
  fingerprint_ret = xmemdupz(begin, delim - begin);
867
0
  strbuf_release(&fingerprint_stdout);
868
0
  return fingerprint_ret;
869
0
}
870
871
/* Returns the first public key from an ssh-agent to use for signing */
872
static char *get_default_ssh_signing_key(void)
873
0
{
874
0
  struct child_process ssh_default_key = CHILD_PROCESS_INIT;
875
0
  int ret = -1;
876
0
  struct strbuf key_stdout = STRBUF_INIT, key_stderr = STRBUF_INIT;
877
0
  char *key_command = NULL;
878
0
  const char **argv;
879
0
  int n;
880
0
  char *default_key = NULL;
881
0
  const char *literal_key = NULL;
882
0
  char *begin, *new_line, *first_line;
883
884
0
  if (!ssh_default_key_command)
885
0
    die(_("either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"));
886
887
0
  key_command = xstrdup(ssh_default_key_command);
888
0
  n = split_cmdline(key_command, &argv);
889
890
0
  if (n < 0)
891
0
    die(_("malformed build-time gpg.ssh.defaultKeyCommand: %s"),
892
0
        split_cmdline_strerror(n));
893
894
0
  strvec_pushv(&ssh_default_key.args, argv);
895
0
  ret = pipe_command(&ssh_default_key, NULL, 0, &key_stdout, 0,
896
0
         &key_stderr, 0);
897
898
0
  if (!ret) {
899
0
    begin = key_stdout.buf;
900
0
    new_line = strchr(begin, '\n');
901
0
    if (new_line)
902
0
      first_line = xmemdupz(begin, new_line - begin);
903
0
    else
904
0
      first_line = xstrdup(begin);
905
0
    if (is_literal_ssh_key(first_line, &literal_key)) {
906
      /*
907
       * We only use `is_literal_ssh_key` here to check validity
908
       * The prefix will be stripped when the key is used.
909
       */
910
0
      default_key = first_line;
911
0
    } else {
912
0
      free(first_line);
913
0
      warning(_("gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"),
914
0
        key_stderr.buf, key_stdout.buf);
915
0
    }
916
917
0
  } else {
918
0
    warning(_("gpg.ssh.defaultKeyCommand failed: %s %s"),
919
0
      key_stderr.buf, key_stdout.buf);
920
0
  }
921
922
0
  free(key_command);
923
0
  free(argv);
924
0
  strbuf_release(&key_stdout);
925
926
0
  return default_key;
927
0
}
928
929
static char *get_ssh_key_id(void)
930
0
{
931
0
  char *signing_key = get_signing_key();
932
0
  char *key_id = get_ssh_key_fingerprint(signing_key);
933
0
  free(signing_key);
934
0
  return key_id;
935
0
}
936
937
/* Returns a textual but unique representation of the signing key */
938
char *get_signing_key_id(void)
939
0
{
940
0
  gpg_interface_lazy_init();
941
942
0
  if (use_format->get_key_id) {
943
0
    return use_format->get_key_id();
944
0
  }
945
946
  /* GPG/GPGSM only store a key id on this variable */
947
0
  return get_signing_key();
948
0
}
949
950
char *get_signing_key(void)
951
0
{
952
0
  gpg_interface_lazy_init();
953
954
0
  if (configured_signing_key)
955
0
    return xstrdup(configured_signing_key);
956
0
  if (use_format->get_default_key) {
957
0
    return use_format->get_default_key();
958
0
  }
959
960
0
  return xstrdup(git_committer_info(IDENT_STRICT | IDENT_NO_DATE));
961
0
}
962
963
const char *gpg_trust_level_to_str(enum signature_trust_level level)
964
0
{
965
0
  struct sigcheck_gpg_trust_level *trust;
966
967
0
  if (level < 0 || level >= ARRAY_SIZE(sigcheck_gpg_trust_level))
968
0
    BUG("invalid trust level requested %d", level);
969
970
0
  trust = &sigcheck_gpg_trust_level[level];
971
0
  if (trust->value != level)
972
0
    BUG("sigcheck_gpg_trust_level[] unsorted");
973
974
0
  return sigcheck_gpg_trust_level[level].display_key;
975
0
}
976
977
int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
978
0
{
979
0
  gpg_interface_lazy_init();
980
981
0
  return use_format->sign_buffer(buffer, signature, signing_key);
982
0
}
983
984
/*
985
 * Strip CR from the line endings, in case we are on Windows.
986
 * NEEDSWORK: make it trim only CRs before LFs and rename
987
 */
988
static void remove_cr_after(struct strbuf *buffer, size_t offset)
989
0
{
990
0
  size_t i, j;
991
992
0
  for (i = j = offset; i < buffer->len; i++) {
993
0
    if (buffer->buf[i] != '\r') {
994
0
      if (i != j)
995
0
        buffer->buf[j] = buffer->buf[i];
996
0
      j++;
997
0
    }
998
0
  }
999
0
  strbuf_setlen(buffer, j);
1000
0
}
1001
1002
static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
1003
        const char *signing_key)
1004
0
{
1005
0
  struct child_process gpg = CHILD_PROCESS_INIT;
1006
0
  int ret;
1007
0
  size_t bottom;
1008
0
  const char *cp;
1009
0
  struct strbuf gpg_status = STRBUF_INIT;
1010
1011
0
  strvec_pushl(&gpg.args,
1012
0
         use_format->program,
1013
0
         "--status-fd=2",
1014
0
         "-bsau", signing_key,
1015
0
         NULL);
1016
1017
0
  bottom = signature->len;
1018
1019
  /*
1020
   * When the username signingkey is bad, program could be terminated
1021
   * because gpg exits without reading and then write gets SIGPIPE.
1022
   */
1023
0
  sigchain_push(SIGPIPE, SIG_IGN);
1024
0
  ret = pipe_command(&gpg, buffer->buf, buffer->len,
1025
0
         signature, 1024, &gpg_status, 0);
1026
0
  sigchain_pop(SIGPIPE);
1027
1028
0
  for (cp = gpg_status.buf;
1029
0
       cp && (cp = strstr(cp, "[GNUPG:] SIG_CREATED "));
1030
0
       cp++) {
1031
0
    if (cp == gpg_status.buf || cp[-1] == '\n')
1032
0
      break; /* found */
1033
0
  }
1034
0
  ret |= !cp;
1035
0
  if (ret) {
1036
0
    error(_("gpg failed to sign the data:\n%s"),
1037
0
          gpg_status.len ? gpg_status.buf : "(no gpg output)");
1038
0
    strbuf_release(&gpg_status);
1039
0
    return -1;
1040
0
  }
1041
0
  strbuf_release(&gpg_status);
1042
1043
  /* Strip CR from the line endings, in case we are on Windows. */
1044
0
  remove_cr_after(signature, bottom);
1045
1046
0
  return 0;
1047
0
}
1048
1049
static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
1050
         const char *signing_key)
1051
0
{
1052
0
  struct child_process signer = CHILD_PROCESS_INIT;
1053
0
  int ret = -1;
1054
0
  size_t bottom, keylen;
1055
0
  struct strbuf signer_stderr = STRBUF_INIT;
1056
0
  struct tempfile *key_file = NULL, *buffer_file = NULL;
1057
0
  char *ssh_signing_key_file = NULL;
1058
0
  struct strbuf ssh_signature_filename = STRBUF_INIT;
1059
0
  const char *literal_key = NULL;
1060
0
  int literal_ssh_key = 0;
1061
1062
0
  if (!signing_key || signing_key[0] == '\0')
1063
0
    return error(
1064
0
      _("user.signingKey needs to be set for ssh signing"));
1065
1066
0
  if (is_literal_ssh_key(signing_key, &literal_key)) {
1067
    /* A literal ssh key */
1068
0
    literal_ssh_key = 1;
1069
0
    key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
1070
0
    if (!key_file)
1071
0
      return error_errno(
1072
0
        _("could not create temporary file"));
1073
0
    keylen = strlen(literal_key);
1074
0
    if (write_in_full(key_file->fd, literal_key, keylen) < 0 ||
1075
0
        close_tempfile_gently(key_file) < 0) {
1076
0
      error_errno(_("failed writing ssh signing key to '%s'"),
1077
0
            key_file->filename.buf);
1078
0
      goto out;
1079
0
    }
1080
0
    ssh_signing_key_file = xstrdup(key_file->filename.buf);
1081
0
  } else {
1082
    /* We assume a file */
1083
0
    ssh_signing_key_file = interpolate_path(signing_key, 1);
1084
0
  }
1085
1086
0
  buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
1087
0
  if (!buffer_file) {
1088
0
    error_errno(_("could not create temporary file"));
1089
0
    goto out;
1090
0
  }
1091
1092
0
  if (write_in_full(buffer_file->fd, buffer->buf, buffer->len) < 0 ||
1093
0
      close_tempfile_gently(buffer_file) < 0) {
1094
0
    error_errno(_("failed writing ssh signing key buffer to '%s'"),
1095
0
          buffer_file->filename.buf);
1096
0
    goto out;
1097
0
  }
1098
1099
0
  strvec_pushl(&signer.args, use_format->program,
1100
0
         "-Y", "sign",
1101
0
         "-n", "git",
1102
0
         "-f", ssh_signing_key_file,
1103
0
         NULL);
1104
0
  if (literal_ssh_key)
1105
0
    strvec_push(&signer.args, "-U");
1106
0
  strvec_push(&signer.args, buffer_file->filename.buf);
1107
1108
0
  sigchain_push(SIGPIPE, SIG_IGN);
1109
0
  ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
1110
0
  sigchain_pop(SIGPIPE);
1111
1112
0
  if (ret) {
1113
0
    if (strstr(signer_stderr.buf, "usage:"))
1114
0
      error(_("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)"));
1115
1116
0
    ret = error("%s", signer_stderr.buf);
1117
0
    goto out;
1118
0
  }
1119
1120
0
  bottom = signature->len;
1121
1122
0
  strbuf_addbuf(&ssh_signature_filename, &buffer_file->filename);
1123
0
  strbuf_addstr(&ssh_signature_filename, ".sig");
1124
0
  if (strbuf_read_file(signature, ssh_signature_filename.buf, 0) < 0) {
1125
0
    ret = error_errno(
1126
0
      _("failed reading ssh signing data buffer from '%s'"),
1127
0
      ssh_signature_filename.buf);
1128
0
    goto out;
1129
0
  }
1130
  /* Strip CR from the line endings, in case we are on Windows. */
1131
0
  remove_cr_after(signature, bottom);
1132
1133
0
out:
1134
0
  if (key_file)
1135
0
    delete_tempfile(&key_file);
1136
0
  if (buffer_file)
1137
0
    delete_tempfile(&buffer_file);
1138
0
  if (ssh_signature_filename.len)
1139
0
    unlink_or_warn(ssh_signature_filename.buf);
1140
0
  strbuf_release(&signer_stderr);
1141
0
  strbuf_release(&ssh_signature_filename);
1142
0
  FREE_AND_NULL(ssh_signing_key_file);
1143
0
  return ret;
1144
0
}
1145
1146
int parse_sign_mode(const char *arg, enum sign_mode *mode)
1147
0
{
1148
0
  if (!strcmp(arg, "abort"))
1149
0
    *mode = SIGN_ABORT;
1150
0
  else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
1151
0
    *mode = SIGN_VERBATIM;
1152
0
  else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
1153
0
    *mode = SIGN_WARN_VERBATIM;
1154
0
  else if (!strcmp(arg, "warn-strip"))
1155
0
    *mode = SIGN_WARN_STRIP;
1156
0
  else if (!strcmp(arg, "strip"))
1157
0
    *mode = SIGN_STRIP;
1158
0
  else if (!strcmp(arg, "strip-if-invalid"))
1159
0
    *mode = SIGN_STRIP_IF_INVALID;
1160
0
  else
1161
0
    return -1;
1162
0
  return 0;
1163
0
}