Control: affects 836554 + cdebootstrap Hi Bastian--
On Sun 2016-09-04 16:51:13 +0200, Bastian Blank wrote: > On Sun, Sep 04, 2016 at 10:04:54AM -0400, Daniel Kahn Gillmor wrote: >> I'm unclear as to why this is Severity: grave -- i've reset the Severity >> to normal, but i'm happy to have you reset the severity with an >> appropriate explanation. > > I'm inclined to forward that to ctte, as this is a clear breakage in > backward compatibility and you already broke that transition pretty bad > anyway. i'm sorry, but i don't see it as clearly as you do. Yes, there is a transition cost with moving to the modern version of GnuPG, and it's not as clearly understood as a traditional C library transition, but it's a transition that we can and will sort out. > The only way to verify an inline-signed message and also get the > unescaped message is to use gpg --decrypt. --verify does not even > accept --output. so if gpgv supported --output would that suit your needs? >> So maybe it's not file verification that's causing the agent to spawn >> but some other operation? > > The file is not encrypted, so not really. I believe the other operation is key import, as referenced in https://bugs.gnupg.org/gnupg/issue2669 -- if we can get that resolved upstream that might help out some. But cdebootstrap should really be using gpgv and not gpg in the first place. >> > As it is inline signed, it is not possible to use gpgv, which can't >> > decode messages. >> gpgv can verify inline-signed data, but does not produce output of the >> verified text. That's the concern, right? I've opened >> https://bugs.gnupg.org/gnupg/issue2668 to record that concern upstream. > > Isn't gpgv a debian-ism? no, gpgv is an upstream tool, designed for one specific use case, with a dramatically simplified API. For security-critical steps that meet this API, we should use the simpler tool. >> If you're talking about verifying InRelease, then that's a bit of a >> special case, because it has a constrained format that we can rely on. >> In particular, it's an RFC822 message, which means it has no lines with >> a leading hyphen (-) and it has no preamble or footer outside the >> signature. So it should be possible to convert it manually to separate >> files that can then be verified with gpgv and used independently. > > You can do several modification to such signed files without changing > the signature, esp dash-escaping and whitespaces at line endings. What > is a sane way to undo all of this? > > InRelease was introduced to fix race conditions, so no, this does not > work. the race condition is that someone could download Release and then Release.gpg, and they got Release from one rsync push and Release.gpg From another. is that right? I'm attaching the source for openpgp-split-clearsigned.c -- i'd be happy to ship something like this with the gpgv package, or as a separate, trivial package. it compiles to about 7KiB. If upstream doesn't want gpgv to support --output, would you be willing to have cdebootstrap avoid using gpg by doing the equivalent of: openpgp-split-clearsigned <InRelease >Release 3>Release.gpg gpgv --keyring /usr/share/keyrings/debian-archive-keyring.gpg Release.gpg Release Or, if you like, you're welcome to use the code in cdebootstrap directly so that it can make use of gpgv's simpler signature verification interface. (if cdebootstrap wants it under a different license, i'm happy to oblige) Let me know what you think! All the best, --dkg
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> /* openpgp-split-clearsigned * Author: Daniel Kahn Gillmor <[email protected]> * License: GPL v3+ * split an OpenPGP inline cleartext signature * (https://tools.ietf.org/html/rfc4880#section-7) into a detached * signature and body that can be usefully considered and manipulated. * reads from stdin. Writes body to stdout, signature to fd 3. * As Werner Koch says: signature verification "works best with a * detached signature, because only this format makes it easy to * decide what has been signed." * [ https://bugs.gnupg.org/gnupg/issue2668 ] */ enum cleartext_state { cts_before, cts_header, cts_body, cts_signature, cts_after }; const char msgbegin[] = "-----BEGIN PGP SIGNED MESSAGE-----"; const char sigbegin[] = "-----BEGIN PGP SIGNATURE-----"; const char sigend[] = "-----END PGP SIGNATURE-----"; int die (const char *msg) { fprintf (stderr, "openpgp-split-clearsigned: %s (%s)\n", msg, errno ? strerror (errno) : "errno not set"); return 1; } int main () { enum cleartext_state s = cts_before; int line_printed = 0; char *buf = NULL, *endptr = NULL, *linestart = 0; size_t bufsz = 0; ssize_t bytesread = 0; ssize_t linelen = 0; FILE *sigout = fdopen (3, "w"); if (sigout == NULL) return die ("could not open file descriptor 3 for output of signature"); while (!feof (stdin)) { bytesread = getline (&buf, &bufsz, stdin); if (bytesread == -1) { if (feof (stdin)) continue; return die ("failed to getline() from stdin"); } if (s == cts_after) continue; endptr = buf + bytesread; while (endptr > buf && (endptr[-1] == '\n' || endptr[-1] == '\r' || endptr[-1] == ' ' || endptr[-1] == '\t')) endptr--; *endptr = '\0'; linelen = endptr - buf; if (s == cts_body && linelen == sizeof (sigbegin) - 1 && !(strcmp (sigbegin, buf))) s = cts_signature; if (s == cts_signature) { if (linelen && fwrite (buf, linelen, 1, sigout) != 1) return die ("failed to write line of signature"); if (fwrite ("\n", 1, 1, sigout) != 1) return die ("failed to write trailing newline to signature"); if (linelen == sizeof (sigend) - 1 && (!strcmp (sigend, buf))) s = cts_after; } linestart = buf; if (s == cts_body) { if (buf[0] == '-') { if (buf[1] == ' ') { linestart = buf + 2; linelen -= 2; } else return die ("bad dash-escaping"); } if (line_printed) if (fwrite ("\n", 1, 1, stdout) != 1) return die ("failed to write newline to message body"); if (linelen && fwrite (linestart, linelen, 1, stdout) != 1) return die ("failed to write line to message body"); line_printed = 1; } if (s == cts_header && linelen == 0) s = cts_body; if (s == cts_before && linelen == sizeof (msgbegin) - 1 && !strcmp (msgbegin, buf)) s = cts_header; } if (s != cts_after) return die ("failed to find both message body and signature"); fclose (stdout); fclose (sigout); free (buf); return 0; }
signature.asc
Description: PGP signature

