summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2015-07-07 22:11:20 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2015-08-10 17:25:26 +0200
commit4e03c47de15164f2656d9655edab6fb3570cb2f2 (patch)
treeb3475a46b3cc5ede3a4da4042c9bc80569549aba
parent25f2731928f0b571f7521d7d7a7e301499d0f6ee (diff)
implement Signed-By without using gpg for verification
The previous commit returns to the possibility of using just gpgv for verification proposes. There is one problem through: We can't enforce a specific keyid without using gpg, but our acquire method can as it parses gpgv output anyway, so it can deal with good signatures from not expected signatures and treats them as unknown keys instead. Git-Dch: Ignore
-rw-r--r--methods/gpgv.cc69
-rwxr-xr-xtest/integration/test-apt-key1
-rwxr-xr-xtest/integration/test-releasefile-verification4
3 files changed, 63 insertions, 11 deletions
diff --git a/methods/gpgv.cc b/methods/gpgv.cc
index 014430041..d88a06789 100644
--- a/methods/gpgv.cc
+++ b/methods/gpgv.cc
@@ -15,6 +15,8 @@
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
+
+#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
@@ -74,6 +76,7 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
std::clog << "inside VerifyGetSigners" << std::endl;
int fd[2];
+ bool const keyIsID = (key.empty() == false && key[0] != '/');
if (pipe(fd) < 0)
return "Couldn't create pipe";
@@ -82,12 +85,13 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
if (pid < 0)
return string("Couldn't spawn new process") + strerror(errno);
else if (pid == 0)
- ExecGPGV(outfile, file, 3, fd, key);
+ ExecGPGV(outfile, file, 3, fd, (keyIsID ? "" : key));
close(fd[1]);
FILE *pipein = fdopen(fd[0], "r");
// Loop over the output of apt-key (which really is gnupg), and check the signatures.
+ std::vector<std::string> ValidSigners;
size_t buffersize = 0;
char *buffer = NULL;
while (1)
@@ -107,32 +111,31 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
std::clog << "Got BADSIG! " << std::endl;
BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
}
-
- if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0)
+ else if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0)
{
if (Debug == true)
std::clog << "Got NO_PUBKEY " << std::endl;
NoPubKeySigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
}
- if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0)
+ else if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0)
{
if (Debug == true)
std::clog << "Got NODATA! " << std::endl;
BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
}
- if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0)
+ else if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0)
{
if (Debug == true)
std::clog << "Got KEYEXPIRED! " << std::endl;
WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
}
- if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0)
+ else if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0)
{
if (Debug == true)
std::clog << "Got REVKEYSIG! " << std::endl;
WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
}
- if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0)
+ else if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0)
{
char *sig = buffer + sizeof(GNUPGPREFIX);
char *p = sig + sizeof("GOODSIG");
@@ -143,10 +146,48 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
std::clog << "Got GOODSIG, key ID:" << sig << std::endl;
GoodSigners.push_back(string(sig));
}
+ else if (strncmp(buffer, GNUPGVALIDSIG, sizeof(GNUPGVALIDSIG)-1) == 0)
+ {
+ char *sig = buffer + sizeof(GNUPGVALIDSIG);
+ char *p = sig;
+ while (*p && isxdigit(*p))
+ p++;
+ *p = 0;
+ if (Debug == true)
+ std::clog << "Got VALIDSIG, key ID: " << sig << std::endl;
+ ValidSigners.push_back(string(sig));
+ }
}
fclose(pipein);
free(buffer);
+ // apt-key has a --keyid parameter, but this requires gpg, so we call it without it
+ // and instead check after the fact which keyids where used for verification
+ if (keyIsID == true)
+ {
+ if (Debug == true)
+ std::clog << "GoodSigs needs to be limited to keyid " << key << std::endl;
+ std::vector<std::string>::iterator const foundItr = std::find(ValidSigners.begin(), ValidSigners.end(), key);
+ bool const found = (foundItr != ValidSigners.end());
+ std::copy(GoodSigners.begin(), GoodSigners.end(), std::back_insert_iterator<std::vector<std::string> >(NoPubKeySigners));
+ if (found)
+ {
+ // we look for GOODSIG here as well as an expired sig is a valid sig as well (but not a good one)
+ std::string const goodlongkeyid = "GOODSIG " + key.substr(24, 16);
+ bool const foundGood = std::find(GoodSigners.begin(), GoodSigners.end(), goodlongkeyid) != GoodSigners.end();
+ if (Debug == true)
+ std::clog << "Key " << key << " is valid sig, is " << goodlongkeyid << " also a good one? " << (foundGood ? "yes" : "no") << std::endl;
+ GoodSigners.clear();
+ if (foundGood)
+ {
+ GoodSigners.push_back(goodlongkeyid);
+ NoPubKeySigners.erase(std::remove(NoPubKeySigners.begin(), NoPubKeySigners.end(), goodlongkeyid), NoPubKeySigners.end());
+ }
+ }
+ else
+ GoodSigners.clear();
+ }
+
int status;
waitpid(pid, &status, 0);
if (Debug == true)
@@ -156,8 +197,18 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
if (WEXITSTATUS(status) == 0)
{
- if (GoodSigners.empty())
- return _("Internal error: Good signature, but could not determine key fingerprint?!");
+ if (keyIsID)
+ {
+ // gpgv will report success, but we want to enforce a certain keyring
+ // so if we haven't found the key the valid we found is in fact invalid
+ if (GoodSigners.empty())
+ return _("At least one invalid signature was encountered.");
+ }
+ else
+ {
+ if (GoodSigners.empty())
+ return _("Internal error: Good signature, but could not determine key fingerprint?!");
+ }
return "";
}
else if (WEXITSTATUS(status) == 1)
diff --git a/test/integration/test-apt-key b/test/integration/test-apt-key
index 1226e7dc4..a1a0d883d 100755
--- a/test/integration/test-apt-key
+++ b/test/integration/test-apt-key
@@ -204,6 +204,7 @@ gpg: unchanged: 1' aptkey --fakeroot update
testfailure --nomsg aptkey --quiet --readonly --keyring keys/does-not-exist.pub verify signature.gpg signature
testfailure test -e keys/does-not-exist.pub
+ # note: this isn't how apts gpgv method implements keyid for verify
msgtest 'Test verify a file' 'with good keyid'
testsuccess --nomsg aptkey --quiet --readonly --keyid 'Paranoid' verify signature.gpg signature
diff --git a/test/integration/test-releasefile-verification b/test/integration/test-releasefile-verification
index 1c3953c8b..759242514 100755
--- a/test/integration/test-releasefile-verification
+++ b/test/integration/test-releasefile-verification
@@ -92,7 +92,7 @@ touch aptarchive/apt.deb
PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')"
updatewithwarnings() {
- testwarning aptget update
+ testwarning aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
testsuccess grep -E "$1" rootdir/tmp/testwarning.output
}
@@ -225,7 +225,7 @@ runtest() {
signreleasefiles 'Joe Sixpack'
find aptarchive/ -name "$DELETEFILE" -delete
msgmsg 'Cold archive signed by bad keyid' 'Joe Sixpack'
- updatewithwarnings '^W: .* NO_PUBKEY'
+ updatewithwarnings '^W: .* be verified because the public key is not available: .*'
sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 #" rootdir/etc/apt/sources.list.d/*
}