Browse Source

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.
tags/debian/1.1.exp9
David Kalnischkies 6 years ago
parent
commit
6bf93605fd
12 changed files with 383 additions and 217 deletions
  1. +189
    -75
      apt-pkg/acquire-item.cc
  2. +55
    -50
      apt-pkg/acquire-item.h
  3. +16
    -12
      apt-pkg/indexrecords.cc
  4. +2
    -0
      apt-pkg/indexrecords.h
  5. +4
    -3
      test/integration/framework
  6. +5
    -7
      test/integration/test-apt-update-ims
  7. +3
    -2
      test/integration/test-apt-update-nofallback
  8. +0
    -4
      test/integration/test-apt-update-not-modified
  9. +2
    -2
      test/integration/test-apt-update-rollback
  10. +62
    -0
      test/integration/test-releasefile-date-older
  11. +18
    -19
      test/integration/test-releasefile-valid-until
  12. +27
    -43
      test/integration/test-releasefile-verification

+ 189
- 75
apt-pkg/acquire-item.cc View File

@@ -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<IndexTarget*>* 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 "


+ 55
- 50
apt-pkg/acquire-item.h View File

@@ -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<IndexTarget*>* 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<IndexTarget*>* 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<IndexTarget*>* 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 {{{*/


+ 16
- 12
apt-pkg/indexrecords.cc View File

@@ -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<std::string, indexRecords::checkSum* >::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;
}


+ 2
- 0
apt-pkg/indexrecords.h View File

@@ -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 */


+ 4
- 3
test/integration/framework View File

@@ -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"


+ 5
- 7
test/integration/test-apt-update-ims View File

@@ -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'


+ 3
- 2
test/integration/test-apt-update-nofallback View File

@@ -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) <joe@example.org>
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) <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>



+ 0
- 4
test/integration/test-apt-update-not-modified View File

@@ -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'


+ 2
- 2
test/integration/test-apt-update-rollback View File

@@ -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)"


+ 62
- 0
test/integration/test-releasefile-date-older View File

@@ -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)"

+ 18
- 19
test/integration/test-releasefile-valid-until View File

@@ -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

+ 27
- 43
test/integration/test-releasefile-verification View File

@@ -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


Loading…
Cancel
Save