From 6bf93605fdb8e858d3f0a79a124c1d39f760094d Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 18 May 2015 22:15:06 +0200 Subject: [PATCH] treat older Release files than we already have as an IMSHit Valid-Until protects us from long-living downgrade attacks, but not all repositories have it and an attacker could still use older but still valid files to downgrade us. While this makes it sounds like a security improvement now, its a bit theoretical at best as an attacker with capabilities to pull this off could just as well always keep us days (but in the valid period) behind and always knows which state we have, as we tell him with the If-Modified-Since header. This is also why this is 'silently' ignored and treated as an IMSHit rather than screamed at the user as this can at best be an annoyance for attackers. An error here would 'regularily' be encountered by users by out-of-sync mirrors serving a single run (e.g. load balancer) or in two consecutive runs on the other hand, so it would just help teaching people ignore it. That said, most of the code churn is caused by enforcing this additional requirement. Crisscross from InRelease to Release.gpg is e.g. very unlikely in practice, but if we would ignore it an attacker could sidestep it this way. --- apt-pkg/acquire-item.cc | 264 +++++++++++++----- apt-pkg/acquire-item.h | 105 +++---- apt-pkg/indexrecords.cc | 28 +- apt-pkg/indexrecords.h | 2 + test/integration/framework | 7 +- test/integration/test-apt-update-ims | 12 +- test/integration/test-apt-update-nofallback | 5 +- test/integration/test-apt-update-not-modified | 4 - test/integration/test-apt-update-rollback | 4 +- test/integration/test-releasefile-date-older | 62 ++++ test/integration/test-releasefile-valid-until | 37 ++- .../integration/test-releasefile-verification | 70 ++--- 12 files changed, 383 insertions(+), 217 deletions(-) create mode 100755 test/integration/test-releasefile-date-older diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 78dace12c..8155b9bfe 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1637,7 +1637,7 @@ pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire *Owner, HashStringList const &ExpectedHashes, pkgAcqMetaBase *TransactionManager) : Item(Owner, ExpectedHashes, TransactionManager), - MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), + MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL), IndexTargets(IndexTargets), AuthPass(false), RealURI(RealURI), IMSHit(false) { } @@ -1697,6 +1697,14 @@ void pkgAcqMetaBase::CommitTransaction() Transaction.clear(); } /*}}}*/ +bool pkgAcqMetaBase::TransactionState(TransactionStates const state) /*{{{*/ +{ + // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey] + if (TransactionManager->IMSHit == false) + return pkgAcquire::Item::TransactionState(state); + return true; +} + /*}}}*/ // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/ void pkgAcqMetaBase::TransactionStageCopy(Item *I, const std::string &From, @@ -1715,15 +1723,15 @@ void pkgAcqMetaBase::TransactionStageRemoval(Item *I, } /*}}}*/ // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/ -bool pkgAcqMetaBase::CheckStopAuthentication(const std::string &Message) +bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message) { // FIXME: this entire function can do now that we disallow going to // a unauthenticated state and can cleanly rollback - string const Final = GetFinalFilename(); + string const Final = I->GetFinalFilename(); if(FileExists(Final)) { - Status = StatTransientNetworkError; + I->Status = StatTransientNetworkError; _error->Warning(_("An error occurred during the signature " "verification. The repository is not updated " "and the previous index files will be used. " @@ -1737,7 +1745,7 @@ bool pkgAcqMetaBase::CheckStopAuthentication(const std::string &Message) _error->Error(_("GPG error: %s: %s"), Desc.Description.c_str(), LookupTag(Message,"Message").c_str()); - Status = StatError; + I->Status = StatError; return true; } else { _error->Warning(_("GPG error: %s: %s"), @@ -1751,17 +1759,13 @@ bool pkgAcqMetaBase::CheckStopAuthentication(const std::string &Message) /*}}}*/ // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, - pkgAcqMetaBase *TransactionManager, - string URI,string URIDesc,string ShortDesc, - string MetaIndexFile, - const vector* IndexTargets, - indexRecords* MetaIndexParser) : - pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser, URI, - HashStringList(), TransactionManager), - MetaIndexFile(MetaIndexFile), URIDesc(URIDesc), - ShortDesc(ShortDesc) + pkgAcqMetaBase *TransactionManager, + string const &URI, string const &URIDesc,string const &ShortDesc, + pkgAcqMetaIndex * const MetaIndex) : + pkgAcquire::Item(Owner, HashStringList(), TransactionManager), MetaIndex(MetaIndex), + URIDesc(URIDesc), RealURI(URI) { - DestFile = GetPartialFileNameFromURI(RealURI); + DestFile = GetPartialFileNameFromURI(URI); // remove any partial downloaded sig-file in partial/. // it may confuse proxies and is too small to warrant a @@ -1779,11 +1783,28 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, Desc.ShortDesc = ShortDesc; Desc.URI = URI; - QueueURI(Desc); + // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors), + // so we skip the download step and go instantly to verification + if (TransactionManager->IMSHit == true && RealFileExists(GetFinalFilename())) + { + Complete = true; + Status = StatDone; + PartialFile = DestFile = GetFinalFilename(); + MetaIndexFileSignature = DestFile; + MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile); + } + else + QueueURI(Desc); } /*}}}*/ pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/ { +} + /*}}}*/ +// pkgAcqMetaSig::GetFinalFilename - Return the full final file path /*{{{*/ +std::string pkgAcqMetaSig::GetFinalFilename() const +{ + return GetFinalFileNameFromURI(RealURI); } /*}}}*/ // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/ @@ -1793,21 +1814,32 @@ void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList const &Hashes, pkgAcquire::MethodConfig *Cfg) { + if (MetaIndexFileSignature.empty() == false) + { + DestFile = MetaIndexFileSignature; + MetaIndexFileSignature.clear(); + } Item::Done(Message, Size, Hashes, Cfg); - if(AuthPass == false) + if(MetaIndex->AuthPass == false) { - if(CheckDownloadDone(Message, Hashes) == true) + if(MetaIndex->CheckDownloadDone(this, Message, Hashes) == true) { - // destfile will be modified to point to MetaIndexFile for the - // gpgv method, so we need to save it here - MetaIndexFileSignature = DestFile; - QueueForSignatureVerify(MetaIndexFile, MetaIndexFileSignature); + // destfile will be modified to point to MetaIndexFile for the + // gpgv method, so we need to save it here + MetaIndexFileSignature = DestFile; + MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile); } return; } - else if(CheckAuthDone(Message) == true) - TransactionManager->TransactionStageCopy(this, MetaIndexFileSignature, GetFinalFilename()); + else if(MetaIndex->CheckAuthDone(Message) == true) + { + if (TransactionManager->IMSHit == false) + { + TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename()); + } + } } /*}}}*/ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ @@ -1815,20 +1847,18 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ Item::Failed(Message,Cnf); // check if we need to fail at this point - if (AuthPass == true && CheckStopAuthentication(Message)) + if (MetaIndex->AuthPass == true && MetaIndex->CheckStopAuthentication(this, Message)) return; - // FIXME: meh, this is not really elegant - string const Final = GetFinalFileNameFromURI(RealURI); - string const InReleaseURI = RealURI.replace(RealURI.rfind("Release.gpg"), 12, - "InRelease"); - string const FinalInRelease = GetFinalFileNameFromURI(InReleaseURI); + string const FinalRelease = MetaIndex->GetFinalFilename(); + string const FinalReleasegpg = GetFinalFilename(); + string const FinalInRelease = TransactionManager->GetFinalFilename(); - if (RealFileExists(Final) || RealFileExists(FinalInRelease)) + if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease)) { std::string downgrade_msg; strprintf(downgrade_msg, _("The repository '%s' is no longer signed."), - URIDesc.c_str()); + MetaIndex->URIDesc.c_str()); if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories")) { // meh, the users wants to take risks (we still mark the packages @@ -1841,7 +1871,7 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ } else { _error->Error("%s", downgrade_msg.c_str()); if (TransactionManager->IMSHit == false) - Rename(MetaIndexFile, MetaIndexFile+".FAILED"); + Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED"); Item::Failed("Message: " + downgrade_msg, Cnf); TransactionManager->AbortTransaction(); return; @@ -1850,23 +1880,44 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ else _error->Warning(_("The data from '%s' is not signed. Packages " "from that repository can not be authenticated."), - URIDesc.c_str()); + MetaIndex->URIDesc.c_str()); - // this ensures that any file in the lists/ dir is removed by the - // transaction - DestFile = GetPartialFileNameFromURI(RealURI); + // ensures that a Release.gpg file in the lists/ is removed by the transaction TransactionManager->TransactionStageRemoval(this, DestFile); // only allow going further if the users explicitely wants it - if(AllowInsecureRepositories(MetaIndexParser, TransactionManager, this) == true) + if(AllowInsecureRepositories(MetaIndex->MetaIndexParser, TransactionManager, this) == true) { + if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease)) + { + // open the last Release if we have it + if (TransactionManager->IMSHit == false) + { + MetaIndex->LastMetaIndexParser = new indexRecords; + _error->PushToStack(); + if (RealFileExists(FinalInRelease)) + MetaIndex->LastMetaIndexParser->Load(FinalInRelease); + else + MetaIndex->LastMetaIndexParser->Load(FinalRelease); + // its unlikely to happen, but if what we have is bad ignore it + if (_error->PendingError()) + { + delete MetaIndex->LastMetaIndexParser; + MetaIndex->LastMetaIndexParser = NULL; + } + _error->RevertToStack(); + } + } + // we parse the indexes here because at this point the user wanted // a repository that may potentially harm him - MetaIndexParser->Load(MetaIndexFile); - if (!VerifyVendor(Message)) + MetaIndex->MetaIndexParser->Load(MetaIndex->DestFile); + if (MetaIndex->VerifyVendor(Message) == false) /* expired Release files are still a problem you need extra force for */; else - QueueIndexes(true); + MetaIndex->QueueIndexes(true); + + TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename()); } // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor @@ -1926,18 +1977,14 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size, /*{{{*/ { Item::Done(Message,Size,Hashes,Cfg); - if(CheckDownloadDone(Message, Hashes)) + if(CheckDownloadDone(this, Message, Hashes)) { // we have a Release file, now download the Signature, all further // verify/queue for additional downloads will be done in the // pkgAcqMetaSig::Done() code - std::string const MetaIndexFile = DestFile; - new pkgAcqMetaSig(Owner, TransactionManager, + new pkgAcqMetaSig(Owner, TransactionManager, MetaIndexSigURI, MetaIndexSigURIDesc, - MetaIndexSigShortDesc, MetaIndexFile, IndexTargets, - MetaIndexParser); - - TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + MetaIndexSigShortDesc, this); } } /*}}}*/ @@ -1948,6 +1995,40 @@ bool pkgAcqMetaBase::CheckAuthDone(string Message) /*{{{*/ // perform additional verification of its contents, and use them // to verify the indexes we are about to download + if (TransactionManager->IMSHit == false) + { + // open the last (In)Release if we have it + std::string const FinalFile = GetFinalFilename(); + std::string FinalRelease; + std::string FinalInRelease; + if (APT::String::Endswith(FinalFile, "InRelease")) + { + FinalInRelease = FinalFile; + FinalRelease = FinalFile.substr(0, FinalFile.length() - strlen("InRelease")) + "Release"; + } + else + { + FinalInRelease = FinalFile.substr(0, FinalFile.length() - strlen("Release")) + "InRelease"; + FinalRelease = FinalFile; + } + if (RealFileExists(FinalInRelease) || RealFileExists(FinalRelease)) + { + LastMetaIndexParser = new indexRecords; + _error->PushToStack(); + if (RealFileExists(FinalInRelease)) + LastMetaIndexParser->Load(FinalInRelease); + else + LastMetaIndexParser->Load(FinalRelease); + // its unlikely to happen, but if what we have is bad ignore it + if (_error->PendingError()) + { + delete LastMetaIndexParser; + LastMetaIndexParser = NULL; + } + _error->RevertToStack(); + } + } + if (!MetaIndexParser->Load(DestFile)) { Status = StatAuthError; @@ -2001,48 +2082,47 @@ std::string pkgAcqMetaBase::GetFinalFilename() const } /*}}}*/ // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/ -void pkgAcqMetaBase::QueueForSignatureVerify(const std::string &MetaIndexFile, - const std::string &MetaIndexFileSignature) +void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcquire::Item * const I, std::string const &File, std::string const &Signature) { AuthPass = true; - Desc.URI = "gpgv:" + MetaIndexFileSignature; - DestFile = MetaIndexFile; - QueueURI(Desc); - SetActiveSubprocess("gpgv"); + I->Desc.URI = "gpgv:" + Signature; + I->DestFile = File; + QueueURI(I->Desc); + I->SetActiveSubprocess("gpgv"); } /*}}}*/ // pkgAcqMetaBase::CheckDownloadDone /*{{{*/ -bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message, HashStringList const &Hashes) +bool pkgAcqMetaBase::CheckDownloadDone(pkgAcquire::Item * const I, const std::string &Message, HashStringList const &Hashes) const { // We have just finished downloading a Release file (it is not // verified yet) - string FileName = LookupTag(Message,"Filename"); + string const FileName = LookupTag(Message,"Filename"); if (FileName.empty() == true) { - Status = StatError; - ErrorText = "Method gave a blank filename"; + I->Status = StatError; + I->ErrorText = "Method gave a blank filename"; return false; } - if (FileName != DestFile) + if (FileName != I->DestFile) { - Local = true; - Desc.URI = "copy:" + FileName; - QueueURI(Desc); + I->Local = true; + I->Desc.URI = "copy:" + FileName; + I->QueueURI(I->Desc); return false; } // make sure to verify against the right file on I-M-S hit - IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false); - if (IMSHit == false) + bool IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"), false); + if (IMSHit == false && Hashes.usable()) { // detect IMS-Hits servers haven't detected by Hash comparison - std::string FinalFile = GetFinalFilename(); + std::string const FinalFile = I->GetFinalFilename(); if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true) { IMSHit = true; - unlink(DestFile.c_str()); + unlink(I->DestFile.c_str()); } } @@ -2052,11 +2132,11 @@ bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message, HashStringLis // even if it doesn't exist. if (TransactionManager != NULL) TransactionManager->IMSHit = true; - DestFile = GetFinalFilename(); + I->PartialFile = I->DestFile = I->GetFinalFilename(); } // set Item to complete as the remaining work is all local (verify etc) - Complete = true; + I->Complete = true; return true; } @@ -2175,6 +2255,19 @@ bool pkgAcqMetaBase::VerifyVendor(string Message) /*{{{*/ } } + /* Did we get a file older than what we have? This is a last minute IMS hit and doubles + as a prevention of downgrading us to older (still valid) files */ + if (TransactionManager->IMSHit == false && LastMetaIndexParser != NULL && + LastMetaIndexParser->GetDate() > MetaIndexParser->GetDate()) + { + TransactionManager->IMSHit = true; + unlink(DestFile.c_str()); + PartialFile = DestFile = GetFinalFilename(); + delete MetaIndexParser; + MetaIndexParser = LastMetaIndexParser; + LastMetaIndexParser = NULL; + } + if (_config->FindB("Debug::pkgAcquire::Auth", false)) { std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl; @@ -2248,7 +2341,6 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/ { // index targets + (worst case:) Release/Release.gpg ExpectedAdditionalItems = IndexTargets->size() + 2; - } /*}}}*/ pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/ @@ -2268,14 +2360,25 @@ string pkgAcqMetaClearSig::Custom600Headers() } /*}}}*/ // pkgAcqMetaClearSig::Done - We got a file /*{{{*/ -// --------------------------------------------------------------------- +class APT_HIDDEN DummyItem : public pkgAcquire::Item +{ + std::string URI; + public: + virtual std::string DescURI() {return URI;}; + + DummyItem(pkgAcquire *Owner, std::string const &URI) : pkgAcquire::Item(Owner), URI(URI) + { + Status = StatDone; + DestFile = GetFinalFileNameFromURI(URI); + } +}; void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size, HashStringList const &Hashes, pkgAcquire::MethodConfig *Cnf) { Item::Done(Message, Size, Hashes, Cnf); - // if we expect a ClearTextSignature (InRelase), ensure that + // if we expect a ClearTextSignature (InRelease), ensure that // this is what we get and if not fail to queue a // Release/Release.gpg, see #346386 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile)) @@ -2288,12 +2391,23 @@ void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size, if(AuthPass == false) { - if(CheckDownloadDone(Message, Hashes) == true) - QueueForSignatureVerify(DestFile, DestFile); + if(CheckDownloadDone(this, Message, Hashes) == true) + QueueForSignatureVerify(this, DestFile, DestFile); return; } else if(CheckAuthDone(Message) == true) - TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + { + if (TransactionManager->IMSHit == false) + TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + else if (RealFileExists(GetFinalFilename()) == false) + { + // We got an InRelease file IMSHit, but we haven't one, which means + // we had a valid Release/Release.gpg combo stepping in, which we have + // to 'acquire' now to ensure list cleanup isn't removing them + new DummyItem(Owner, MetaIndexURI); + new DummyItem(Owner, MetaSigURI); + } + } } /*}}}*/ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ @@ -2318,7 +2432,7 @@ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /* } else { - if(CheckStopAuthentication(Message)) + if(CheckStopAuthentication(this, Message)) return; _error->Warning(_("The data from '%s' is not signed. Packages " diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 646de8416..07c86f31b 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -394,6 +394,7 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ /** \brief A package-system-specific parser for the meta-index file. */ indexRecords *MetaIndexParser; + indexRecords *LastMetaIndexParser; /** \brief The index files which should be looked up in the meta-index * and then downloaded. @@ -429,11 +430,10 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ * \param Message The message block received from the fetch * subprocess. */ - bool CheckDownloadDone(const std::string &Message, HashStringList const &Hashes); + bool CheckDownloadDone(pkgAcquire::Item * const I, const std::string &Message, HashStringList const &Hashes) const; /** \brief Queue the downloaded Signature for verification */ - void QueueForSignatureVerify(const std::string &MetaIndexFile, - const std::string &MetaIndexFileSignature); + void QueueForSignatureVerify(pkgAcquire::Item * const I, std::string const &File, std::string const &Signature); #if APT_PKG_ABI >= 413 virtual std::string Custom600Headers() const; @@ -453,7 +453,7 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ bool CheckAuthDone(std::string Message); /** Check if the current item should fail at this point */ - bool CheckStopAuthentication(const std::string &Message); + bool CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message); /** \brief Check that the release file is a release file for the * correct distribution. @@ -462,8 +462,7 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ */ bool VerifyVendor(std::string Message); - /** \brief Get the full pathname of the final file for the current URI */ - virtual std::string GetFinalFilename() const; + virtual bool TransactionState(TransactionStates const state); public: // This refers more to the Transaction-Manager than the actual file @@ -487,6 +486,9 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ */ void TransactionStageRemoval(Item *I, const std::string &FinalFile); + /** \brief Get the full pathname of the final file for the current URI */ + virtual std::string GetFinalFilename() const; + pkgAcqMetaBase(pkgAcquire *Owner, const std::vector* IndexTargets, indexRecords* MetaIndexParser, @@ -495,50 +497,6 @@ class pkgAcqMetaBase : public pkgAcquire::Item /*{{{*/ pkgAcqMetaBase *TransactionManager=NULL); }; /*}}}*/ -/** \brief An acquire item that downloads the detached signature {{{ - * of a meta-index (Release) file, then queues up the release - * file itself. - * - * \todo Why protected members? - * - * \sa pkgAcqMetaIndex - */ -class APT_HIDDEN pkgAcqMetaSig : public pkgAcqMetaBase -{ - void *d; - - protected: - - /** \brief The file we need to verify */ - std::string MetaIndexFile; - - /** \brief The file we use to verify the MetaIndexFile with */ - std::string MetaIndexFileSignature; - - /** \brief Long URI description used in the acquire system */ - std::string URIDesc; - - /** \brief Short URI description used in the acquire system */ - std::string ShortDesc; - - public: - - // Specialized action members - virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf); - virtual void Done(std::string Message,unsigned long long Size, - HashStringList const &Hashes, - pkgAcquire::MethodConfig *Cnf); - - /** \brief Create a new pkgAcqMetaSig. */ - pkgAcqMetaSig(pkgAcquire *Owner, - pkgAcqMetaBase *TransactionManager, - std::string URI,std::string URIDesc, std::string ShortDesc, - std::string MetaIndexFile, - const std::vector* IndexTargets, - indexRecords* MetaIndexParser); - virtual ~pkgAcqMetaSig(); -}; - /*}}}*/ /** \brief An item that is responsible for downloading the meta-index {{{ * file (i.e., Release) itself and verifying its signature. * @@ -584,6 +542,53 @@ class APT_HIDDEN pkgAcqMetaIndex : public pkgAcqMetaBase std::string MetaIndexSigURI, std::string MetaIndexSigURIDesc, std::string MetaIndexSigShortDesc, const std::vector* IndexTargets, indexRecords* MetaIndexParser); + + friend class pkgAcqMetaSig; +}; + /*}}}*/ +/** \brief An acquire item that downloads the detached signature {{{ + * of a meta-index (Release) file, then queues up the release + * file itself. + * + * \todo Why protected members? + * + * \sa pkgAcqMetaIndex + */ +class APT_HIDDEN pkgAcqMetaSig : public pkgAcquire::Item +{ + void *d; + + pkgAcqMetaIndex * const MetaIndex; + + /** \brief The file we use to verify the MetaIndexFile with (not always set!) */ + std::string MetaIndexFileSignature; + + protected: + + /** \brief Long URI description used in the acquire system */ + std::string URIDesc; + + /** \brief URI used to get the file */ + std::string RealURI; + + /** \brief Get the full pathname of the final file for the current URI */ + virtual std::string GetFinalFilename() const; + + public: + virtual std::string DescURI() {return RealURI;}; + + // Specialized action members + virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf); + virtual void Done(std::string Message,unsigned long long Size, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cnf); + + /** \brief Create a new pkgAcqMetaSig. */ + pkgAcqMetaSig(pkgAcquire *Owner, + pkgAcqMetaBase *TransactionManager, + std::string const &URI,std::string const &URIDesc, + std::string const &ShortDesc, pkgAcqMetaIndex * const MetaIndex); + virtual ~pkgAcqMetaSig(); }; /*}}}*/ /** \brief An item repsonsible for downloading clearsigned metaindexes {{{*/ diff --git a/apt-pkg/indexrecords.cc b/apt-pkg/indexrecords.cc index d65266f64..de2617833 100644 --- a/apt-pkg/indexrecords.cc +++ b/apt-pkg/indexrecords.cc @@ -58,6 +58,11 @@ APT_PURE time_t indexRecords::GetValidUntil() const return this->ValidUntil; } +APT_PURE time_t indexRecords::GetDate() const +{ + return this->Date; +} + APT_PURE indexRecords::checkSum *indexRecords::Lookup(const string MetaKey) { std::map::const_iterator sum = Entries.find(MetaKey); @@ -133,9 +138,15 @@ bool indexRecords::Load(const string Filename) /*{{{*/ return false; } - string Label = Section.FindS("Label"); - string StrDate = Section.FindS("Date"); - string StrValidUntil = Section.FindS("Valid-Until"); + string const StrDate = Section.FindS("Date"); + if (RFC1123StrToTime(StrDate.c_str(), Date) == false) + { + strprintf(ErrorText, _("Invalid 'Date' entry in Release file %s"), Filename.c_str()); + return false; + } + + string const Label = Section.FindS("Label"); + string const StrValidUntil = Section.FindS("Valid-Until"); // if we have a Valid-Until header in the Release file, use it as default if (StrValidUntil.empty() == false) @@ -158,20 +169,13 @@ bool indexRecords::Load(const string Filename) /*{{{*/ (MinAge == 0 || ValidUntil == 0)) // No user settings, use the one from the Release file return true; - time_t date; - if (RFC1123StrToTime(StrDate.c_str(), date) == false) - { - strprintf(ErrorText, _("Invalid 'Date' entry in Release file %s"), Filename.c_str()); - return false; - } - if (MinAge != 0 && ValidUntil != 0) { - time_t const min_date = date + MinAge; + time_t const min_date = Date + MinAge; if (ValidUntil < min_date) ValidUntil = min_date; } if (MaxAge != 0) { - time_t const max_date = date + MaxAge; + time_t const max_date = Date + MaxAge; if (ValidUntil == 0 || ValidUntil > max_date) ValidUntil = max_date; } diff --git a/apt-pkg/indexrecords.h b/apt-pkg/indexrecords.h index 35e534c12..6ed5f0c2b 100644 --- a/apt-pkg/indexrecords.h +++ b/apt-pkg/indexrecords.h @@ -36,6 +36,7 @@ class indexRecords std::string Dist; std::string Suite; std::string ExpectedDist; + time_t Date; time_t ValidUntil; bool SupportsAcquireByHash; @@ -62,6 +63,7 @@ class indexRecords std::string GetSuite() const; bool GetSupportsAcquireByHash() const; time_t GetValidUntil() const; + time_t GetDate() const; std::string GetExpectedDist() const; /** \brief check if source is marked as always trusted */ diff --git a/test/integration/framework b/test/integration/framework index 8c8936ead..b253deb91 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -1164,9 +1164,9 @@ testfileequal() { shift msgtest "Test for correctness of file" "$FILE" if [ -z "$*" ]; then - echo -n "" | checkdiff $FILE - && msgpass || msgfail + echo -n "" | checkdiff - $FILE && msgpass || msgfail else - echo "$*" | checkdiff $FILE - && msgpass || msgfail + echo "$*" | checkdiff - $FILE && msgpass || msgfail fi } @@ -1547,7 +1547,8 @@ aptautotest_aptcdrom_add() { aptautotest_aptget_update "$@"; } testaptautotestnodpkgwarning() { local TESTCALL="$1" while [ -n "$2" ]; do - if expr match "$2" '^-[a-z]*s' >/dev/null 2>&1; then return; fi + if expr match "$2" '^-[a-z]*s' >/dev/null 2>&1; then return; fi # simulation mode + if expr match "$2" '^-dy\?' >/dev/null 2>&1; then return; fi # download-only mode shift done testfailure grep '^dpkg: warning:.*ignor.*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output" diff --git a/test/integration/test-apt-update-ims b/test/integration/test-apt-update-ims index f091bffaa..7385e701a 100755 --- a/test/integration/test-apt-update-ims +++ b/test/integration/test-apt-update-ims @@ -43,7 +43,7 @@ runtest() { testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" # ensure that we still do a hash check for other files on ims hit of Release - if grep -q '^Hit .* \(InRelease\|Release.gpg\)$' expected.output ; then + if grep -q '^Hit .* InRelease$' expected.output || ! grep -q '^Ign .* Release\(\.gpg\)\?$' expected.output; then $TEST aptget update -o Debug::Acquire::gpgv=1 cp rootdir/tmp/${TEST}.output goodsign.output testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" @@ -66,7 +66,6 @@ msgmsg 'Release/Release.gpg' EXPECT='Ign http://localhost:8080 unstable InRelease 404 Not Found Hit http://localhost:8080 unstable Release -Hit http://localhost:8080 unstable Release.gpg Reading package lists...' find aptarchive -name 'InRelease' -delete echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex @@ -81,7 +80,7 @@ Hit http://localhost:8080 unstable Release Ign http://localhost:8080 unstable Release.gpg 404 Not Found Reading package lists... -W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated." +W: The data from 'http://localhost:8080 unstable Release' is not signed. Packages from that repository can not be authenticated." find aptarchive -name 'Release.gpg' -delete echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex runtest 'warning' @@ -108,8 +107,7 @@ msgmsg 'expired Release/Release.gpg' EXPECT='Ign http://localhost:8080 unstable InRelease 404 Not Found Hit http://localhost:8080 unstable Release -Hit http://localhost:8080 unstable Release.gpg -E: Release file for http://localhost:8080/dists/unstable/Release.gpg is expired (invalid since). Updates for this repository will not be applied.' +E: Release file for http://localhost:8080/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied.' find aptarchive -name 'InRelease' -delete echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex runtest 'failure' @@ -122,8 +120,8 @@ EXPECT="Ign http://localhost:8080 unstable InRelease Hit http://localhost:8080 unstable Release Ign http://localhost:8080 unstable Release.gpg 404 Not Found -W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated. -E: Release file for http://localhost:8080/dists/unstable/InRelease is expired (invalid since). Updates for this repository will not be applied." +W: The data from 'http://localhost:8080 unstable Release' is not signed. Packages from that repository can not be authenticated. +E: Release file for http://localhost:8080/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied." find aptarchive -name 'Release.gpg' -delete echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex runtest 'failure' 'warning' diff --git a/test/integration/test-apt-update-nofallback b/test/integration/test-apt-update-nofallback index 71576de81..db4430ea3 100755 --- a/test/integration/test-apt-update-nofallback +++ b/test/integration/test-apt-update-nofallback @@ -8,6 +8,7 @@ set -e simulate_mitm_and_inject_evil_package() { + redatereleasefiles '+1 hour' rm -f $APTARCHIVE/dists/unstable/InRelease rm -f $APTARCHIVE/dists/unstable/Release.gpg inject_evil_package @@ -31,7 +32,7 @@ EOF assert_update_is_refused_and_last_good_state_used() { - testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq + testfailuremsg "E: The repository 'file: unstable Release' is no longer signed." aptget update assert_repo_is_intact } @@ -193,7 +194,7 @@ test_release_gpg_to_invalid_release_release_gpg() 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: unstable Release.gpg: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) + 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: unstable Release: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) W: Failed to fetch file:${APTARCHIVE}/dists/unstable/Release.gpg The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) diff --git a/test/integration/test-apt-update-not-modified b/test/integration/test-apt-update-not-modified index a67ecb760..b1d55c156 100755 --- a/test/integration/test-apt-update-not-modified +++ b/test/integration/test-apt-update-not-modified @@ -56,7 +56,6 @@ Reading package lists..." aptget update testsuccessequal "Ign $1 unstable InRelease 404 Not Found Hit $1 unstable Release -Hit $1 unstable Release.gpg Reading package lists..." aptget update testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" @@ -66,7 +65,6 @@ Reading package lists..." aptget update testsuccessequal "Ign $1 unstable InRelease 404 Not Found Hit $1 unstable Release -Hit $1 unstable Release.gpg Reading package lists..." aptget update testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)" @@ -75,7 +73,6 @@ Reading package lists..." aptget update testsuccessequal "Ign $1 unstable InRelease 404 Not Found Hit $1 unstable Release -Hit $1 unstable Release.gpg Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B] Reading package lists..." aptget update testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" @@ -85,7 +82,6 @@ Reading package lists..." aptget update testsuccessequal "Ign $1 unstable InRelease 404 Not Found Get:1 $1 unstable Release [$(stat -c '%s' 'aptarchive/dists/unstable/Release') B] -Get:2 $1 unstable Release.gpg [$(stat -c '%s' 'aptarchive/dists/unstable/Release.gpg') B] Reading package lists..." aptget update webserverconfig 'aptwebserver::support::modified-since' 'true' webserverconfig 'aptwebserver::support::last-modified' 'true' diff --git a/test/integration/test-apt-update-rollback b/test/integration/test-apt-update-rollback index 29fe1ab56..b464a04a1 100755 --- a/test/integration/test-apt-update-rollback +++ b/test/integration/test-apt-update-rollback @@ -78,7 +78,7 @@ test_inrelease_to_valid_release() { rm $APTARCHIVE/dists/unstable/Release.gpg # update fails - testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq + testfailureequal "E: The repository 'file: unstable Release' is no longer signed." aptget update -qq # test that security downgrade was not successful testfileequal lists.before "$(listcurrentlistsdirectory)" @@ -101,7 +101,7 @@ test_inrelease_to_release_reverts_all() { break_repository_sources_index '+1hour' # ensure error - testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq # -o Debug::acquire::transaction=1 + testfailureequal "E: The repository 'file: unstable Release' is no longer signed." aptget update -qq # -o Debug::acquire::transaction=1 # ensure that the Packages file is also rolled back testfileequal lists.before "$(listcurrentlistsdirectory)" diff --git a/test/integration/test-releasefile-date-older b/test/integration/test-releasefile-date-older new file mode 100755 index 000000000..5cdc34fac --- /dev/null +++ b/test/integration/test-releasefile-date-older @@ -0,0 +1,62 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'i386' + +insertpackage 'wheezy' 'apt' 'all' '0.8.15' + +setupaptarchive --no-update + +# we don't complain as the server could have just sent a 'Hit' here and this +# 'downgrade attack' is usually performed by out-of-sync mirrors. Valid-Until +# catches the 'real' downgrade attacks (expect that it finds stale mirrors). +# Scaring users with an error here serves hence no point. + +msgmsg 'InRelease file is silently rejected if' 'new Date is before old Date' +rm -rf rootdir/var/lib/apt/lists +generatereleasefiles 'now' 'now + 7 days' +signreleasefiles +testsuccess aptget update +listcurrentlistsdirectory > listsdir.lst +redatereleasefiles 'now - 2 days' +testsuccess aptget update +testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" + +msgmsg 'Release.gpg file is silently rejected if' 'new Date is before old Date' +rm -rf rootdir/var/lib/apt/lists +generatereleasefiles 'now' 'now + 7 days' +signreleasefiles +find aptarchive -name 'InRelease' -delete +testsuccess aptget update +listcurrentlistsdirectory > listsdir.lst +redatereleasefiles 'now - 2 days' +find aptarchive -name 'InRelease' -delete +testsuccess aptget update +testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" + +msgmsg 'Crisscross InRelease/Release.gpg file is silently rejected if' 'new Date is before old Date' +rm -rf rootdir/var/lib/apt/lists +generatereleasefiles 'now' 'now + 7 days' +signreleasefiles +find aptarchive -name 'Release.gpg' -delete +testsuccess aptget update +listcurrentlistsdirectory > listsdir.lst +redatereleasefiles 'now - 2 days' +find aptarchive -name 'InRelease' -delete +testsuccess aptget update +testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" + +msgmsg 'Crisscross Release.gpg/InRelease file is silently rejected if' 'new Date is before old Date' +rm -rf rootdir/var/lib/apt/lists +generatereleasefiles 'now' 'now + 7 days' +signreleasefiles +find aptarchive -name 'InRelease' -delete +testsuccess aptget update +listcurrentlistsdirectory > listsdir.lst +redatereleasefiles 'now - 2 days' +find aptarchive -name 'Release.gpg' -delete +testsuccess aptget update +testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)" diff --git a/test/integration/test-releasefile-valid-until b/test/integration/test-releasefile-valid-until index 0d9a91254..e000abf5d 100755 --- a/test/integration/test-releasefile-valid-until +++ b/test/integration/test-releasefile-valid-until @@ -16,13 +16,12 @@ setupaptarchive --no-update runtest() { local MSG="$1" - msgtest "$1" "$2" + msgtest "Release file is $MSG as it has" "$2" rm -rf rootdir/var/lib/apt/lists - aptget clean generatereleasefiles "$3" "$4" signreleasefiles shift 4 - if expr match "$MSG" '.*accepted.*' >/dev/null; then + if [ "$MSG" = 'accepted' ]; then testsuccess --nomsg aptget update "$@" testfailure grep -q 'is expired' rootdir/tmp/testsuccess.output else @@ -31,19 +30,19 @@ runtest() { fi } -runtest 'Release file is accepted as it has' 'no Until' '' '' -runtest 'Release file is accepted as it has' 'no Until and good Max-Valid' '' '' -o Acquire::Max-ValidTime=3600 -runtest 'Release file is rejected as it has' 'no Until, but bad Max-Valid' 'now - 2 days' '' -o Acquire::Max-ValidTime=3600 -runtest 'Release file is accepted as it has' 'good Until' 'now - 3 days' 'now + 1 day' -runtest 'Release file is rejected as it has' 'bad Until' 'now - 7 days' 'now - 4 days' -runtest 'Release file is rejected as it has' 'bad Until (ignore good Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=1209600 -runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=86400 -runtest 'Release file is rejected as it has' 'bad Max-Valid (good Until)' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 -runtest 'Release file is accepted as it has' 'good labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 -o Acquire::Max-ValidTime::Testcases=1209600 -runtest 'Release file is rejected as it has' 'bad labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=1209600 -o Acquire::Max-ValidTime::Testcases=86400 -runtest 'Release file is accepted as it has' 'good Until (good Min-Valid, no Max-Valid)' 'now - 7 days' 'now + 1 days' -o Acquire::Min-ValidTime=1209600 -runtest 'Release file is accepted as it has' 'good Min-Valid (bad Until, no Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Min-ValidTime=1209600 -runtest 'Release file is accepted as it has' 'good Min-Valid (bad Until, good Max-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=1209600 -o Acquire::Max-ValidTime=2419200 -runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, good Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=2419200 -runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, bad Min-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=12096 -o Acquire::Max-ValidTime=241920 -runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, bad Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=241920 +runtest 'accepted' 'no Until' '' '' +runtest 'accepted' 'no Until and good Max-Valid' '' '' -o Acquire::Max-ValidTime=3600 +runtest 'rejected' 'no Until, but bad Max-Valid' 'now - 2 days' '' -o Acquire::Max-ValidTime=3600 +runtest 'accepted' 'good Until' 'now - 3 days' 'now + 1 day' +runtest 'rejected' 'bad Until' 'now - 7 days' 'now - 4 days' +runtest 'rejected' 'bad Until (ignore good Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=1209600 +runtest 'rejected' 'bad Max-Valid (bad Until)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=86400 +runtest 'rejected' 'bad Max-Valid (good Until)' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 +runtest 'accepted' 'good labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 -o Acquire::Max-ValidTime::Testcases=1209600 +runtest 'rejected' 'bad labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=1209600 -o Acquire::Max-ValidTime::Testcases=86400 +runtest 'accepted' 'good Until (good Min-Valid, no Max-Valid)' 'now - 7 days' 'now + 1 days' -o Acquire::Min-ValidTime=1209600 +runtest 'accepted' 'good Min-Valid (bad Until, no Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Min-ValidTime=1209600 +runtest 'accepted' 'good Min-Valid (bad Until, good Max-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=1209600 -o Acquire::Max-ValidTime=2419200 +runtest 'rejected' 'bad Max-Valid (bad Until, good Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=2419200 +runtest 'rejected' 'bad Max-Valid (bad Until, bad Min-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=12096 -o Acquire::Max-ValidTime=241920 +runtest 'rejected' 'bad Max-Valid (bad Until, bad Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=241920 diff --git a/test/integration/test-releasefile-verification b/test/integration/test-releasefile-verification index 363b7fe5b..469ed34d2 100755 --- a/test/integration/test-releasefile-verification +++ b/test/integration/test-releasefile-verification @@ -91,25 +91,9 @@ touch aptarchive/apt.deb PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')" -updatesuccess() { - local LOG='update.log' - if aptget update >$LOG 2>&1 || grep -q -E '^(W|E): ' $LOG; then - msgpass - else - cat $LOG - msgfail - fi -} - -updatefailure() { - local LOG='update.log' - aptget update >$LOG 2>&1 || true - if grep -q -E "$1" $LOG; then - msgpass - else - cat $LOG - msgfail - fi +updatewithwarnings() { + testwarning aptget update + testsuccess grep -E "$1" rootdir/tmp/testwarning.output } runtest() { @@ -117,8 +101,8 @@ runtest() { rm -rf rootdir/var/lib/apt/lists signreleasefiles 'Joe Sixpack' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Cold archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Cold archive signed by' 'Joe Sixpack' + testsuccess aptget update testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt installaptold @@ -126,8 +110,8 @@ runtest() { prepare ${PKGFILE}-new signreleasefiles 'Joe Sixpack' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Good warm archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Good warm archive signed by' 'Joe Sixpack' + testsuccess aptget update testsuccessequal "$(cat ${PKGFILE}-new) " aptcache show apt installaptnew @@ -137,8 +121,8 @@ runtest() { cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg signreleasefiles 'Rex Expired' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Cold archive signed by' 'Rex Expired' - updatefailure '^W: .* KEYEXPIRED' + msgmsg 'Cold archive signed by' 'Rex Expired' + updatewithwarnings '^W: .* KEYEXPIRED' testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt failaptold @@ -148,8 +132,8 @@ runtest() { rm -rf rootdir/var/lib/apt/lists signreleasefiles 'Marvin Paranoid' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Cold archive signed by' 'Marvin Paranoid' - updatefailure '^W: .* NO_PUBKEY' + msgmsg 'Cold archive signed by' 'Marvin Paranoid' + updatewithwarnings '^W: .* NO_PUBKEY' testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt failaptold @@ -162,8 +146,8 @@ runtest() { done signreleasefiles 'Joe Sixpack' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Bad warm archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Bad warm archive signed by' 'Joe Sixpack' + testsuccess aptget update testsuccessequal "$(cat ${PKGFILE}-new) " aptcache show apt installaptnew @@ -173,8 +157,8 @@ runtest() { rm -rf rootdir/var/lib/apt/lists signreleasefiles 'Joe Sixpack' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Cold archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Cold archive signed by' 'Joe Sixpack' + testsuccess aptget update testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt installaptold @@ -182,8 +166,8 @@ runtest() { prepare ${PKGFILE}-new signreleasefiles 'Marvin Paranoid' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Good warm archive signed by' 'Marvin Paranoid' - updatefailure '^W: .* NO_PUBKEY' + msgmsg 'Good warm archive signed by' 'Marvin Paranoid' + updatewithwarnings '^W: .* NO_PUBKEY' testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt installaptold @@ -192,8 +176,8 @@ runtest() { cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg signreleasefiles 'Rex Expired' find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Good warm archive signed by' 'Rex Expired' - updatefailure '^W: .* KEYEXPIRED' + msgmsg 'Good warm archive signed by' 'Rex Expired' + updatewithwarnings '^W: .* KEYEXPIRED' testsuccessequal "$(cat ${PKGFILE}) " aptcache show apt installaptold @@ -202,8 +186,8 @@ runtest() { prepare ${PKGFILE}-new signreleasefiles find aptarchive/ -name "$DELETEFILE" -delete - msgtest 'Good warm archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Good warm archive signed by' 'Joe Sixpack' + testsuccess aptget update testsuccessequal "$(cat ${PKGFILE}-new) " aptcache show apt installaptnew @@ -213,24 +197,24 @@ runtest2() { prepare ${PKGFILE} rm -rf rootdir/var/lib/apt/lists signreleasefiles 'Joe Sixpack' - msgtest 'Cold archive signed by' 'Joe Sixpack' - updatesuccess + msgmsg 'Cold archive signed by' 'Joe Sixpack' + testsuccess aptget update # New .deb but now an unsigned archive. For example MITM to circumvent # package verification. prepare ${PKGFILE}-new find aptarchive/ -name InRelease -delete find aptarchive/ -name Release.gpg -delete - msgtest 'Warm archive signed by' 'nobody' - updatesuccess + msgmsg 'Warm archive signed by' 'nobody' + updatewithwarnings 'W: .* no longer signed.' testsuccessequal "$(cat ${PKGFILE}-new) " aptcache show apt failaptnew # Unsigned archive from the beginning must also be detected. rm -rf rootdir/var/lib/apt/lists - msgtest 'Cold archive signed by' 'nobody' - updatesuccess + msgmsg 'Cold archive signed by' 'nobody' + updatewithwarnings 'W: .* is not signed.' testsuccessequal "$(cat ${PKGFILE}-new) " aptcache show apt failaptnew -- 2.45.2