summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMake/config.h.in1
-rw-r--r--CMakeLists.txt1
-rw-r--r--apt-pkg/acquire-item.cc8
-rw-r--r--apt-pkg/contrib/gpgv.cc20
-rw-r--r--apt-pkg/contrib/gpgv.h9
-rw-r--r--methods/CMakeLists.txt7
-rw-r--r--methods/sqv.cc346
-rwxr-xr-xtest/integration/test-apt-update-ims2
-rwxr-xr-xtest/integration/test-apt-update-nofallback19
-rwxr-xr-xtest/integration/test-apt-update-repeated-ims-hit4
-rwxr-xr-xtest/integration/test-apt-update-rollback9
-rwxr-xr-xtest/integration/test-releasefile-verification77
-rwxr-xr-xtest/integration/test-signed-by-option2
13 files changed, 456 insertions, 49 deletions
diff --git a/CMake/config.h.in b/CMake/config.h.in
index ced74d8d8..b2c5eac56 100644
--- a/CMake/config.h.in
+++ b/CMake/config.h.in
@@ -85,3 +85,4 @@
#cmakedefine DEFAULT_PAGER "${DEFAULT_PAGER}"
#cmakedefine PAGER_ENV "${PAGER_ENV}"
+#cmakedefine SQV_EXECUTABLE "${SQV_EXECUTABLE}"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af2ec3a86..03796e09c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,6 +46,7 @@ find_package(Iconv REQUIRED)
find_package(Perl REQUIRED)
find_program(TRIEHASH_EXECUTABLE NAMES triehash)
+find_program(SQV_EXECUTABLE NAMES sqv)
if (NOT TRIEHASH_EXECUTABLE)
message(FATAL_ERROR "Could not find triehash executable")
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index 12524778e..69644883b 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -1423,7 +1423,15 @@ string pkgAcqMetaBase::Custom600Headers() const
void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem * const I, std::string const &File, std::string const &Signature)
{
AuthPass = true;
+#ifdef SQV_EXECUTABLE
+ if (not _config->Find("APT::Key::GPGVCommand").empty() || not FileExists(SQV_EXECUTABLE))
+ I->Desc.URI = "gpgv:" + pkgAcquire::URIEncode(Signature);
+ else {
+ I->Desc.URI = "sqv:" + pkgAcquire::URIEncode(Signature);
+ }
+#else
I->Desc.URI = "gpgv:" + pkgAcquire::URIEncode(Signature);
+#endif
I->DestFile = File;
QueueURI(I->Desc);
I->SetActiveSubprocess("gpgv");
diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc
index 7b0a0d240..48d31a44c 100644
--- a/apt-pkg/contrib/gpgv.cc
+++ b/apt-pkg/contrib/gpgv.cc
@@ -169,7 +169,7 @@ static bool CheckGPGV(std::unordered_map<std::string, std::forward_list<std::str
/// Verifies a file containing a detached signature has the right format
/// @return 0 if succesful, or an exit code for ExecGPGV otherwise.
-static int VerifyDetachedSignatureFile(std::string FileGPG, int fd[2], int statusfd = -1)
+static int VerifyDetachedSignatureFile(std::string const &FileGPG, int fd[2], int statusfd = -1)
{
auto detached = make_unique_FILE(FileGPG, "r");
if (detached.get() == nullptr)
@@ -211,10 +211,17 @@ static int VerifyDetachedSignatureFile(std::string FileGPG, int fd[2], int statu
}
}
}
- if (found_signatures == 0 && statusfd != -1)
+ if (found_signatures == 0)
{
- auto const errtag = "[GNUPG:] NODATA\n";
- FileFd::Write(fd[1], errtag, strlen(errtag));
+ if (statusfd != -1 && fd)
+ {
+ auto const errtag = "[GNUPG:] NODATA\n";
+ FileFd::Write(fd[1], errtag, strlen(errtag));
+ }
+ else
+ {
+ _error->Error("Signed file isn't valid, got 'NODATA' (does the network require authentication?)");
+ }
// guess if this is a binary signature, we never officially supported them,
// but silently accepted them via passing them unchecked to gpgv
if (found_badcontent)
@@ -247,6 +254,11 @@ static int VerifyDetachedSignatureFile(std::string FileGPG, int fd[2], int statu
return 0;
}
+bool VerifyDetachedSignatureFile(std::string const &DetachedSignatureFileName)
+{
+ return VerifyDetachedSignatureFile(DetachedSignatureFileName, nullptr, -1) == 0;
+}
+
std::pair<std::string, std::forward_list<std::string>> APT::Internal::FindGPGV(bool Debug)
{
static thread_local std::unordered_map<std::string, std::forward_list<std::string>> checkedCommands;
diff --git a/apt-pkg/contrib/gpgv.h b/apt-pkg/contrib/gpgv.h
index d4520f3a2..0b84f6bb7 100644
--- a/apt-pkg/contrib/gpgv.h
+++ b/apt-pkg/contrib/gpgv.h
@@ -96,5 +96,14 @@ APT_PUBLIC bool SplitClearSignedFile(std::string const &InFile, FileFd * const C
*/
APT_PUBLIC bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &MessageFile);
+/** \brief verifiy a detached signature file for correctness.
+ *
+ * We want to expect unavoided content. This may set an error when returning false
+ * but it might not necessarily do so (in case of empty signature file).
+ *
+ * @return true if the detached signature files contains ASCII-armored signatures, otherwise false
+ */
+APT_PUBLIC bool VerifyDetachedSignatureFile(std::string const &DetachedSignatureFileName);
+
APT_PUBLIC bool IsAssertedPubKeyAlgo(std::string const &pkstr, std::string const &option);
#endif
diff --git a/methods/CMakeLists.txt b/methods/CMakeLists.txt
index beb08a81d..161cd91d1 100644
--- a/methods/CMakeLists.txt
+++ b/methods/CMakeLists.txt
@@ -8,6 +8,11 @@ add_executable(file file.cc)
add_executable(copy copy.cc)
add_executable(store store.cc)
add_executable(gpgv gpgv.cc)
+if (SQV_EXECUTABLE)
+add_executable(sqv sqv.cc)
+install(TARGETS sqv
+ RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/apt/methods)
+endif()
add_executable(cdrom cdrom.cc)
add_executable(http http.cc basehttp.cc $<TARGET_OBJECTS:connectlib>)
add_executable(mirror mirror.cc)
@@ -23,7 +28,7 @@ target_link_libraries(http OpenSSL::SSL $<$<BOOL:${SYSTEMD_FOUND}>:${SYSTEMD_LIB
target_link_libraries(rred apt-private)
# Install the library
-install(TARGETS file copy store gpgv cdrom http rred mirror
+install(TARGETS file copy store cdrom gpgv http rred mirror
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/apt/methods)
add_links(${CMAKE_INSTALL_LIBEXECDIR}/apt/methods mirror mirror+http mirror+https mirror+file mirror+copy)
diff --git a/methods/sqv.cc b/methods/sqv.cc
new file mode 100644
index 000000000..63ccdc08f
--- /dev/null
+++ b/methods/sqv.cc
@@ -0,0 +1,346 @@
+#include <config.h>
+
+#include "aptmethod.h"
+#include <apt-pkg/gpgv.h>
+#include <apt-pkg/strutl.h>
+#include <iterator>
+#include <optional>
+#include <ostream>
+#include <sstream>
+
+using std::string;
+using std::vector;
+
+class SQVMethod : public aptMethod
+{
+ private:
+ std::optional<std::string> policy{};
+ void SetPolicy();
+ bool VerifyGetSigners(const char *file, const char *outfile,
+ vector<string> keyFiles,
+ vector<string> &signers);
+
+ protected:
+ virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE;
+
+ public:
+ SQVMethod();
+};
+
+SQVMethod::SQVMethod() : aptMethod("sqv", "1.1", SingleInstance | SendConfig | SendURIEncoded)
+{
+}
+
+void SQVMethod::SetPolicy()
+{
+ constexpr const char *policies[] = {
+ // APT overrides
+ "APT_SEQUOIA_CRYPTO_POLICY",
+ "/etc/crypto-policies/back-ends/apt-sequoia.config",
+ "/var/lib/crypto-config/profiles/current/apt-sequoia.config",
+ // Sequoia overrides
+ "SEQUOIA_CRYPTO_POLICY",
+ "/etc/crypto-policies/back-ends/sequoia.config",
+ "/var/lib/crypto-config/profiles/current/sequoia.config",
+ // Fallback APT defaults
+ "/usr/share/apt/default-sequoia.config",
+ };
+
+ if (policy)
+ return;
+
+ policy = "";
+
+ for (auto policy : policies)
+ {
+ if (not strchr(policy, '/'))
+ {
+ if (auto value = getenv(policy))
+ {
+ this->policy = value;
+ break;
+ }
+ }
+ else if (FileExists(policy))
+ {
+ this->policy = policy;
+ break;
+ }
+ }
+
+ if (not policy->empty())
+ {
+ if (DebugEnabled())
+ std::clog << "Setting SEQUOIA_CRYPTO_POLICY=" << *policy << std::endl;
+ setenv("SEQUOIA_CRYPTO_POLICY", policy->c_str(), 1);
+ }
+}
+bool SQVMethod::VerifyGetSigners(const char *file, const char *outfile,
+ vector<string> keyFiles,
+ vector<string> &signers)
+{
+ bool const Debug = DebugEnabled();
+
+ std::vector<std::string> args;
+
+ SetPolicy();
+
+ args.push_back(SQV_EXECUTABLE);
+ auto dearmorKeyOrCheckFormat = [&](std::string const &k) -> bool
+ {
+ _error->PushToStack();
+ FileFd keyFd(k, FileFd::ReadOnly);
+ _error->RevertToStack();
+ if (not keyFd.IsOpen())
+ return _error->Warning("The key(s) in the keyring %s are ignored as the file is not readable by user executing gpgv.\n", k.c_str());
+ else if (APT::String::Endswith(k, ".asc"))
+ {
+ std::string b64msg;
+ int state = 0;
+ for (std::string line; keyFd.ReadLine(line);)
+ {
+ line = APT::String::Strip(line);
+ if (APT::String::Startswith(line, "-----BEGIN PGP PUBLIC KEY BLOCK-----"))
+ state = 1;
+ else if (state == 1 && line == "")
+ state = 2;
+ else if (state == 2 && line != "" && line[0] != '=' && line[0] != '-')
+ b64msg += line;
+ else if (APT::String::Startswith(line, "-----END"))
+ state = 3;
+ }
+ if (state != 3)
+ goto err;
+
+ return true;
+ }
+ else
+ {
+ unsigned char c;
+ if (not keyFd.Read(&c, sizeof(c)))
+ goto err;
+ // Identify the leading byte of an OpenPGP public key packet
+ // 0x98 -- old-format OpenPGP public key packet, up to 255 octets
+ // 0x99 -- old-format OpenPGP public key packet, 256-65535 octets
+ // 0xc6 -- new-format OpenPGP public key packet, any length
+ if (c != 0x98 && c != 0x99 && c != 0xc6)
+ goto err;
+ return true;
+ }
+ err:
+ return _error->Warning("The key(s) in the keyring %s are ignored as the file has an unsupported filetype.", k.c_str());
+ };
+ if (keyFiles.empty())
+ {
+ auto Parts = GetListOfFilesInDir(_config->FindDir("Dir::Etc::TrustedParts"), std::vector<std::string>{"gpg", "asc"}, true);
+ for (auto &Part : Parts)
+ {
+ if (Debug)
+ std::clog << "Trying TrustedPart: " << Part << std::endl;
+ if (struct stat st; stat(Part.c_str(), &st) != 0 || st.st_size == 0)
+ continue;
+ if (not dearmorKeyOrCheckFormat(Part))
+ {
+ std::string msg;
+ _error->PopMessage(msg);
+ if (not msg.empty())
+ Warning(std::move(msg));
+ continue;
+ }
+ keyFiles.push_back(Part);
+ }
+ }
+
+ if (keyFiles.empty())
+ return _error->Error("The signatures couldn't be verified because no keyring is specified");
+
+ for (auto const &keyring : keyFiles)
+ {
+ args.push_back("--keyring");
+ args.push_back(keyring);
+ }
+
+ FileFd signatureFd;
+ FileFd messageFd;
+ DEFER([&]
+ {
+ if (signatureFd.IsOpen()) RemoveFile("RemoveSignature", signatureFd.Name());
+ if (messageFd.IsOpen()) RemoveFile("RemoveMessage", messageFd.Name()); });
+
+ if (strcmp(file, outfile) == 0)
+ {
+ if (GetTempFile("apt.sig", false, &signatureFd) == nullptr)
+ return false;
+ if (GetTempFile("apt.data", false, &messageFd) == nullptr)
+ return false;
+
+ // FIXME: The test suite only expects the final message.
+ _error->PushToStack();
+ if (signatureFd.Failed() || messageFd.Failed() ||
+ not SplitClearSignedFile(file, &messageFd, nullptr, &signatureFd))
+ return _error->RevertToStack(), _error->Error("Splitting up %s into data and signature failed", file);
+ _error->RevertToStack();
+
+ args.push_back(signatureFd.Name());
+ args.push_back(messageFd.Name());
+ }
+ else
+ {
+ if (not VerifyDetachedSignatureFile(file))
+ return false;
+ args.push_back(file);
+ args.push_back(outfile);
+ }
+
+ // FIXME: Use a select() loop
+ FileFd sqvout;
+ FileFd sqverr;
+ if (GetTempFile("apt.sqvout", false, &sqvout) == nullptr)
+ return "Internal error: Cannot create temporary file";
+
+ DEFER([&]
+ { RemoveFile("CleanSQVOut", sqvout.Name()); });
+
+ if (GetTempFile("apt.sqverr", false, &sqverr) == nullptr)
+ return "Internal error: Cannot create temporary file";
+
+ DEFER([&]
+ { RemoveFile("CleanSQVErr", sqverr.Name()); });
+
+ // Translate the argument list to a C array. This should happen before
+ // the fork so we don't allocate money between fork() and execvp().
+ if (Debug)
+ std::clog << "Executing " << APT::String::Join(args, " ") << std::endl;
+ std::vector<const char *> cArgs;
+ cArgs.reserve(args.size() + 1);
+ for (auto const &arg : args)
+ cArgs.push_back(arg.c_str());
+ cArgs.push_back(nullptr);
+ pid_t pid = ExecFork({sqvout.Fd(), sqverr.Fd()});
+ if (pid < 0)
+ return _error->Errno("VerifyGetSigners", "Couldn't spawn new process");
+ else if (pid == 0)
+ {
+ dup2(sqvout.Fd(), STDOUT_FILENO);
+ dup2(sqverr.Fd(), STDERR_FILENO);
+ execvp(cArgs[0], (char **)&cArgs[0]);
+ _exit(123);
+ }
+
+ int status;
+ waitpid(pid, &status, 0);
+ sqverr.Seek(0);
+ sqvout.Seek(0);
+
+ if (Debug == true)
+ ioprintf(std::clog, "sqv exited with status %i\n", WEXITSTATUS(status));
+ if (WEXITSTATUS(status) != 0)
+ {
+ std::string msg;
+ for (std::string err; sqverr.ReadLine(err);)
+ msg.append(err).append("\n");
+ return _error->Error(_("Sub-process %s returned an error code (%u), error message is:\n%s"), cArgs[0], WEXITSTATUS(status), msg.c_str());
+ }
+
+ for (std::string signer; sqvout.ReadLine(signer);)
+ {
+ if (Debug)
+ std::clog << "Got GOODSIG " << signer << std::endl;
+ signers.push_back(signer);
+ }
+
+ return true;
+}
+
+static std::string GenerateKeyFile(std::string const key)
+{
+ FileFd fd;
+ GetTempFile("apt-key.XXXXXX.asc", false, &fd);
+ fd.Write(key.data(), key.size());
+ return fd.Name();
+}
+
+bool SQVMethod::URIAcquire(std::string const &Message, FetchItem *Itm)
+{
+ URI const Get(Itm->Uri);
+ std::string const Path = DecodeSendURI(Get.Host + Get.Path); // To account for relative paths
+
+ std::vector<std::string> Signers, keyFpts, keyFiles;
+ struct TemporaryFile
+ {
+ std::string name = "";
+ ~TemporaryFile() { RemoveFile("~TemporaryFile", name); }
+ } tmpKey;
+
+ std::string SignedBy = DeQuoteString(LookupTag(Message, "Signed-By"));
+
+ if (SignedBy.find("-----BEGIN PGP PUBLIC KEY BLOCK-----") != std::string::npos)
+ {
+ tmpKey.name = GenerateKeyFile(SignedBy);
+ keyFiles.emplace_back(tmpKey.name);
+ }
+ else
+ {
+ for (auto &&key : VectorizeString(SignedBy, ','))
+ if (key.empty() == false && key[0] == '/')
+ keyFiles.emplace_back(std::move(key));
+ else
+ keyFpts.emplace_back(std::move(key));
+ }
+
+ // Run apt-key on file, extract contents and get the key ID of the signer
+ VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), keyFiles, Signers);
+ if (_error->PendingError())
+ {
+ // Legacy fallback to trusted.gpg
+ auto trusted = _config->FindFile("Dir::Etc::Trusted");
+ _error->PushToStack();
+ VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), {trusted}, Signers);
+ bool error = _error->PendingError();
+ _error->RevertToStack();
+ if (error)
+ return false;
+ std::string warning;
+ strprintf(warning,
+ _("Key is stored in legacy trusted.gpg keyring (%s). Use Signed-By instead. See the USER CONFIGURATION section in apt-secure(8) for details."),
+ trusted.c_str());
+ Warning(std::move(warning));
+ }
+
+ if (Signers.empty())
+ return _error->Error("No good signature");
+
+ if (not keyFpts.empty())
+ {
+ Signers.erase(std::remove_if(Signers.begin(), Signers.end(), [&](std::string const &signer)
+ {
+ bool allowedSigner = std::find(keyFpts.begin(), keyFpts.end(), signer) != keyFpts.end();
+ if (not allowedSigner && DebugEnabled())
+ std::cerr << "NoPubKey: GOODSIG " << signer << "\n";
+ return not allowedSigner; }),
+ Signers.end());
+
+ if (Signers.empty())
+ {
+ if (keyFpts.size() > 1)
+ return _error->Error(_("No good signature from required signers: %s"), APT::String::Join(keyFpts, ", ").c_str());
+ return _error->Error(_("No good signature from required signer: %s"), APT::String::Join(keyFpts, ", ").c_str());
+ }
+ }
+ std::unordered_map<std::string, std::string> fields;
+ fields.emplace("URI", Itm->Uri);
+ fields.emplace("Filename", Itm->DestFile);
+ fields.emplace("Signed-By", APT::String::Join(Signers, "\n"));
+ SendMessage("201 URI Done", std::move(fields));
+ Dequeue();
+
+ if (DebugEnabled())
+ std::clog << "sqv succeeded\n";
+
+ return true;
+}
+
+int main()
+{
+ return SQVMethod().Run();
+}
diff --git a/test/integration/test-apt-update-ims b/test/integration/test-apt-update-ims
index 1894c3adf..101c2f298 100755
--- a/test/integration/test-apt-update-ims
+++ b/test/integration/test-apt-update-ims
@@ -48,7 +48,7 @@ runtest() {
# ensure that we still do a hash check for other files on ims hit of Release
if grep -q '^Hit:[0-9]\+ .* InRelease$' expected.output || ! grep -q '^Ign:[0-9]\+ .* Release\(\.gpg\)\?$' expected.output; then
- $TEST aptget update -o Debug::Acquire::gpgv=1 $APTOPT
+ $TEST aptget update -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1 $APTOPT
cp rootdir/tmp/${TEST}.output goodsign.output
testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
testsuccess grep '^Got GOODSIG ' goodsign.output
diff --git a/test/integration/test-apt-update-nofallback b/test/integration/test-apt-update-nofallback
index 18f12b1e3..c9ee75756 100755
--- a/test/integration/test-apt-update-nofallback
+++ b/test/integration/test-apt-update-nofallback
@@ -198,9 +198,16 @@ test_inrelease_to_invalid_inrelease()
sed -i 's/^Codename:.*/Codename: evil!/' "$APTARCHIVE/dists/unstable/InRelease"
inject_evil_package
- testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
+ if test -e /usr/bin/sqv; then
+ # FIXME: Do not assert sqv output
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: Sub-process /usr/bin/sqv returned an error code (1), error message is: Verifying signature: Message has been manipulated
+W: Failed to fetch file:${APTARCHIVE}/dists/unstable/InRelease Sub-process /usr/bin/sqv returned an error code (1), error message is: Verifying signature: Message has been manipulated
+W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ else
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Failed to fetch file:${APTARCHIVE}/dists/unstable/InRelease The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ fi
# ensure we keep the repo
testfailure grep 'evil' rootdir/var/lib/apt/lists/*InRelease
@@ -218,10 +225,16 @@ test_release_gpg_to_invalid_release_release_gpg()
# now subvert Release do no longer verify
echo "Some evil data" >> "$APTARCHIVE/dists/unstable/Release"
inject_evil_package
-
- testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable Release: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
+ if test -e /usr/bin/sqv; then
+ # FIXME: Do not assert sqv output
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable Release: Sub-process /usr/bin/sqv returned an error code (1), error message is: Verifying signature: Message has been manipulated
+W: Failed to fetch file:${APTARCHIVE}/dists/unstable/Release.gpg Sub-process /usr/bin/sqv returned an error code (1), error message is: Verifying signature: Message has been manipulated
+W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ else
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable Release: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Failed to fetch file:${APTARCHIVE}/dists/unstable/Release.gpg The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ fi
testfailure grep 'evil' rootdir/var/lib/apt/lists/*Release
testfileequal lists.before "$(listcurrentlistsdirectory)"
diff --git a/test/integration/test-apt-update-repeated-ims-hit b/test/integration/test-apt-update-repeated-ims-hit
index 74d46b31b..43871a31f 100755
--- a/test/integration/test-apt-update-repeated-ims-hit
+++ b/test/integration/test-apt-update-repeated-ims-hit
@@ -40,7 +40,11 @@ rm -f rootdir/etc/apt/trusted.gpg.d/*
sed -i -e 's#^deb #deb [trusted=yes] #' rootdir/etc/apt/sources.list.d/*
APTARCHIVE="$(readlink -f ./aptarchive)"
+if test -e /usr/bin/sqv; then
+GPGERROR="W: GPG error: file:$APTARCHIVE Release: The signatures couldn't be verified because no keyring is specified"
+else
GPGERROR="W: GPG error: file:$APTARCHIVE Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 5A90D141DBAC8DAE"
+fi
msgmsg 'Running update again does not change result' '0'
testwarningmsg "$GPGERROR" apt update
diff --git a/test/integration/test-apt-update-rollback b/test/integration/test-apt-update-rollback
index 8235968bb..68505f6ba 100755
--- a/test/integration/test-apt-update-rollback
+++ b/test/integration/test-apt-update-rollback
@@ -156,9 +156,16 @@ test_inrelease_to_unauth_inrelease() {
signreleasefiles 'Marvin Paranoid'
- testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY E8525D47528144E2
+ if test -e /usr/bin/sqv; then
+ # FIXME: Do not assert sqv output
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: Sub-process /usr/bin/sqv returned an error code (1), error message is: Missing key DE66AECA9151AFA1877EC31DE8525D47528144E2, which is needed to verify signature.
+W: Failed to fetch file:$APTARCHIVE/dists/unstable/InRelease Sub-process /usr/bin/sqv returned an error code (1), error message is: Missing key DE66AECA9151AFA1877EC31DE8525D47528144E2, which is needed to verify signature.
+W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ else
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY E8525D47528144E2
W: Failed to fetch file:$APTARCHIVE/dists/unstable/InRelease The following signatures couldn't be verified because the public key is not available: NO_PUBKEY E8525D47528144E2
W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+ fi
testfileequal lists.before "$(listcurrentlistsdirectory)"
testnotempty find "${ROOTDIR}/var/lib/apt/lists" -name '*_InRelease'
diff --git a/test/integration/test-releasefile-verification b/test/integration/test-releasefile-verification
index 1392a05d1..00c72d7d9 100755
--- a/test/integration/test-releasefile-verification
+++ b/test/integration/test-releasefile-verification
@@ -97,13 +97,20 @@ echo -n 'apt' > aptarchive/apt.deb
PKGFILE="${TESTDIR}/$(echo "$(basename "$0")" | sed 's#^test-#Packages-#')"
updatewithwarnings() {
- testwarning aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testwarning aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
testsuccess grep -E "$1" rootdir/tmp/testwarning.output
}
foreachgpg() {
rm -f rootdir/etc/apt/apt.conf.d/00gpgvcmd
- "$@"
+ local sqv="true"
+ if [ "$1" = "--no-sqv" ]; then
+ local sqv=
+ shift
+ fi
+ if [ "$sqv" ]; then
+ "$@"
+ fi
for GPGV in "gpgv-sq" "gpgv-g10code"; do
msgmsg "Forcing $GPGV to be used"
echo "APT::Key::GPGVCommand \"$GPGV\";" > "rootdir/etc/apt/apt.conf.d/00gpgvcmd"
@@ -147,7 +154,7 @@ runtest() {
rm -rf rootdir/var/lib/apt/lists
cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg
signreleasefiles 'Rex Expired'
- updatewithwarnings '^W: .* EXPKEYSIG'
+ updatewithwarnings '^W: .* (EXPKEYSIG|Expired)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
failaptold
@@ -157,7 +164,7 @@ runtest() {
prepare "${PKGFILE}"
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack,Marvin Paranoid'
- successfulaptgetupdate 'NO_PUBKEY'
+ successfulaptgetupdate 'NO_PUBKEY\|GOODSIG 34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
@@ -167,7 +174,7 @@ runtest() {
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack,Rex Expired'
cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg
- successfulaptgetupdate 'EXPKEYSIG'
+ successfulaptgetupdate 'EXPKEYSIG\|GOODSIG 34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE'
rm -f rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
@@ -177,7 +184,7 @@ runtest() {
prepare "${PKGFILE}"
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Marvin Paranoid'
- updatewithwarnings '^W: .* NO_PUBKEY'
+ updatewithwarnings '^W: .* (NO_PUBKEY|Missing key)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
failaptold
@@ -202,7 +209,7 @@ runtest() {
msgmsg 'Good warm archive signed by' 'Marvin Paranoid'
prepare "${PKGFILE}-new"
signreleasefiles 'Marvin Paranoid'
- updatewithwarnings '^W: .* NO_PUBKEY'
+ updatewithwarnings '^W: .* (NO_PUBKEY|Missing key)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
@@ -212,7 +219,7 @@ runtest() {
# Use a colon here to test weird filenames too
cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rex:expired.gpg
signreleasefiles 'Rex Expired'
- updatewithwarnings '^W: .* EXPKEYSIG'
+ updatewithwarnings '^W: .* (EXPKEYSIG|Expired)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
@@ -230,7 +237,7 @@ runtest() {
rm -rf rootdir/var/lib/apt/lists
local MARVIN="$(readlink -f keys/marvinparanoid.pub)"
sed -i "s#^\(deb\(-src\)\?\) #\1 [signed-by=$MARVIN] #" rootdir/etc/apt/sources.list.d/*
- updatewithwarnings '^W: .* NO_PUBKEY'
+ updatewithwarnings '^W: .* (NO_PUBKEY|Missing key)'
msgmsg 'Cold archive signed by good keyring' 'Marvin Paranoid'
prepare "${PKGFILE}"
@@ -265,7 +272,7 @@ runtest() {
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack'
sed -i "s#^\(deb\(-src\)\?\) #\1 [signed-by=$MARVIN] #" rootdir/etc/apt/sources.list.d/*
- updatewithwarnings '^W: .* be verified because the public key is not available: .*'
+ updatewithwarnings '^W: .* (be verified because the public key is not available: .*|No good signature from required signer)'
msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid'
rm -rf rootdir/var/lib/apt/lists
@@ -279,7 +286,7 @@ runtest() {
msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid,Joe Sixpack'
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Marvin Paranoid,Joe Sixpack'
- successfulaptgetupdate 'NoPubKey: GOODSIG'
+ successfulaptgetupdate 'NoPubKey: GOODSIG\|DE66AECA9151AFA1877EC31DE8525D47528144E2'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
@@ -324,7 +331,7 @@ Signed-By: ${SIXPACK}" rootdir/var/lib/apt/lists/*Release
sed -i "/^Valid-Until: / a\
Signed-By: ${MARVIN}" rootdir/var/lib/apt/lists/*Release
touch -d 'now - 1 year' rootdir/var/lib/apt/lists/*Release
- updatewithwarnings 'W: .* public key is not available: GOODSIG'
+ updatewithwarnings 'W: .* (public key is not available: GOODSIG|No good signature from required signer:)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
@@ -373,22 +380,26 @@ Signed-By: ${SEBASTIAN}" rootdir/var/lib/apt/lists/*Release
sed -i "/^Valid-Until: / a\
Signed-By: ${SEBASTIAN}!" rootdir/var/lib/apt/lists/*Release
touch -d 'now - 1 year' rootdir/var/lib/apt/lists/*Release
- updatewithwarnings 'W: .* public key is not available: GOODSIG'
+ updatewithwarnings 'W: .* (public key is not available: GOODSIG|No good signature from required signer:)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
installaptold
local SUBKEY="4281DEDBD466EAE8C1F4157E5B6896415D44C43E"
+ # This is only supported for gpgv, so require an explicit gpgv command,
+ # otherwise the default verification backend may be sqv.
+ if [ "$GPGV" ]; then
msgmsg 'Warm archive with correct exact subkey signing' 'Sebastian Subkey'
rm -rf rootdir/var/lib/apt/lists
cp -a rootdir/var/lib/apt/lists-bak rootdir/var/lib/apt/lists
- sed -i "/^Valid-Until: / a\
+ sed -i "/^Valid-Until: / a\
Signed-By: ${SUBKEY}!" rootdir/var/lib/apt/lists/*Release
- touch -d 'now - 1 year' rootdir/var/lib/apt/lists/*Release
- successfulaptgetupdate
- testsuccessequal "$(cat "${PKGFILE}-new")
+ touch -d 'now - 1 year' rootdir/var/lib/apt/lists/*Release
+ successfulaptgetupdate
+ testsuccessequal "$(cat "${PKGFILE}-new")
" aptcache show apt
- installaptnew
+ installaptnew
+ fi
rm -f rootdir/etc/apt/trusted.gpg.d/sebastiansubkey.gpg
}
@@ -419,16 +430,6 @@ runtest2() {
find aptarchive -name Release -exec sh -c "echo Hello > {}.gpg" \;
testfailuremsg "E: GPG error: http://localhost:${APTHTTPPORT} Release: Signed file isn't valid, got 'NODATA' (does the network require authentication?)" aptget update
- msgmsg 'Cold archive signed by' 'Empty inline'
- rm -rf rootdir/var/lib/apt/lists
- find aptarchive -name Release -exec sh -c '( echo -----BEGIN PGP SIGNED MESSAGE-----; echo Hash: SHA512; echo; cat {} ; echo; echo -----BEGIN PGP SIGNATURE-----; echo ; echo -----END PGP SIGNATURE----- ) > $(dirname {})/In$(basename {})' \;
- testfailuremsg "E: GPG error: http://localhost:${APTHTTPPORT} InRelease: Signed file isn't valid, got 'NODATA' (does the network require authentication?)" aptget update
-
- msgmsg 'Cold archive signed by' 'Bad inline'
- rm -rf rootdir/var/lib/apt/lists
- find aptarchive -name Release -exec sh -c '( echo -----BEGIN PGP SIGNED MESSAGE-----; echo Hash: SHA512; echo; cat {} ; echo; echo -----BEGIN PGP SIGNATURE-----; echo ; echo SGVsbG8K; echo =nFa9; echo -----END PGP SIGNATURE----- ) > $(dirname {})/In$(basename {})' \;
- testfailuremsg "E: GPG error: http://localhost:${APTHTTPPORT} InRelease: Signed file isn't valid, got 'NODATA' (does the network require authentication?)" aptget update
-
find aptarchive/ \( -name InRelease -o -name Release.gpg \) -delete
# Unsigned archive from the beginning must also be detected.
@@ -463,7 +464,7 @@ EOF
export APT_TESTS_DIGEST_ALGO='SHA512'
successfulaptgetupdate() {
- testsuccess aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testsuccess aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
if [ -n "$1" ]; then
cp rootdir/tmp/testsuccess.output aptupdate.output
testsuccess grep "$1" aptupdate.output
@@ -472,13 +473,13 @@ successfulaptgetupdate() {
foreachgpg runtest3 'Trusted'
successfulaptgetupdate() {
- testwarning aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testwarning aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
if [ -n "$1" ]; then
testsuccess grep "$1" rootdir/tmp/testwarning.output
fi
testsuccess grep 'uses weak algorithm' rootdir/tmp/testwarning.output
}
-foreachgpg runtest3 'Weak'
+foreachgpg --no-sqv runtest3 'Weak'
msgmsg "Running test with apt-untrusted digest"
echo "APT::Hashes::$APT_TESTS_DIGEST_ALGO::Untrusted \"yes\";" > rootdir/etc/apt/apt.conf.d/truststate
@@ -489,14 +490,14 @@ runfailure() {
prepare "${PKGFILE}"
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack'
- testfailure aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
- testsuccess grep 'The following signatures were invalid' rootdir/tmp/testfailure.output
+ testfailure aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
+ testsuccess grep 'The following signatures were invalid\|MD5 is not considered secure' rootdir/tmp/testfailure.output
testnopackage 'apt'
- testwarning aptget update --allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testwarning aptget update --allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
failaptold
rm -rf rootdir/var/lib/apt/lists
sed -i 's#^deb\(-src\)\? #deb\1 [allow-insecure=yes] #' rootdir/etc/apt/sources.list.d/*
- testwarning aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testwarning aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
failaptold
sed -i 's#^deb\(-src\)\? \[allow-insecure=yes\] #deb\1 #' rootdir/etc/apt/sources.list.d/*
@@ -504,13 +505,13 @@ runfailure() {
prepare "${PKGFILE}"
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Marvin Paranoid'
- testfailure aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+ testfailure aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1 -o Debug::Acquire::sqv=1
testnopackage 'apt'
- updatewithwarnings '^W: .* NO_PUBKEY'
+ updatewithwarnings '^W: .* (NO_PUBKEY|Missing key)'
testsuccessequal "$(cat "${PKGFILE}")
" aptcache show apt
failaptold
export APT_DONT_SIGN='Release.gpg'
done
}
-foreachgpg runfailure
+foreachgpg --no-sqv runfailure
diff --git a/test/integration/test-signed-by-option b/test/integration/test-signed-by-option
index 8e1e9a8c2..e6a3fbb86 100755
--- a/test/integration/test-signed-by-option
+++ b/test/integration/test-signed-by-option
@@ -66,7 +66,7 @@ xSigned-By:
-----END PGP PUBLIC KEY BLOCK-----
EOF
testfailure apt update -o Debug::Acquire::gpgv=1
-testsuccess grep "NO_PUBKEY 5A90D141DBAC8DAE" rootdir/tmp/testfailure.output
+testsuccess grep -E "(NO_PUBKEY 5A90D141DBAC8DAE|no keyring is specified)" rootdir/tmp/testfailure.output
sed -i s/^xSigned-By/Signed-By/ rootdir/etc/apt/sources.list.d/deb822.sources
testsuccess apt update -o Debug::Acquire::gpgv=1
# make sure we did not leave leftover files (LP: #1995247)