nix verify-paths: Add ‘--sigs-needed <N>’ flag

This specifies the number of distinct signatures required to consider
each path "trusted".

Also renamed ‘--no-sigs’ to ‘--no-trust’ for the flag that disables
verifying whether a path is trusted (since a path can also be trusted
if it has no signatures, but was built locally).
This commit is contained in:
Eelco Dolstra 2016-04-07 15:14:12 +02:00
parent 6b2ae52808
commit 05fbc606fc
3 changed files with 41 additions and 16 deletions

View file

@ -333,12 +333,18 @@ unsigned int ValidPathInfo::checkSignatures(const PublicKeys & publicKeys) const
{ {
unsigned int good = 0; unsigned int good = 0;
for (auto & sig : sigs) for (auto & sig : sigs)
if (verifyDetached(fingerprint(), sig, publicKeys)) if (checkSignature(publicKeys, sig))
good++; good++;
return good; return good;
} }
bool ValidPathInfo::checkSignature(const PublicKeys & publicKeys, const std::string & sig) const
{
return verifyDetached(fingerprint(), sig, publicKeys);
}
} }

View file

@ -127,6 +127,9 @@ struct ValidPathInfo
/* Return the number of signatures on this .narinfo that were /* Return the number of signatures on this .narinfo that were
produced by one of the specified keys. */ produced by one of the specified keys. */
unsigned int checkSignatures(const PublicKeys & publicKeys) const; unsigned int checkSignatures(const PublicKeys & publicKeys) const;
/* Verify a single signature. */
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
}; };
typedef list<ValidPathInfo> ValidPathInfos; typedef list<ValidPathInfo> ValidPathInfos;

View file

@ -13,15 +13,17 @@ using namespace nix;
struct MixVerify : virtual Args struct MixVerify : virtual Args
{ {
bool noContents = false; bool noContents = false;
bool noSigs = false; bool noTrust = false;
Strings substituterUris; Strings substituterUris;
size_t sigsNeeded;
MixVerify() MixVerify()
{ {
mkFlag(0, "no-contents", "do not verify the contents of each store path", &noContents); mkFlag(0, "no-contents", "do not verify the contents of each store path", &noContents);
mkFlag(0, "no-sigs", "do not verify whether each store path has a valid signature", &noSigs); mkFlag(0, "no-trust", "do not verify whether each store path is trusted", &noTrust);
mkFlag('s', "substituter", {"store-uri"}, "use signatures from specified store", 1, mkFlag('s', "substituter", {"store-uri"}, "use signatures from specified store", 1,
[&](Strings ss) { substituterUris.push_back(ss.front()); }); [&](Strings ss) { substituterUris.push_back(ss.front()); });
mkIntFlag('n', "sigs-needed", "require that each path has at least N valid signatures", &sigsNeeded);
} }
void verifyPaths(ref<Store> store, const Paths & storePaths) void verifyPaths(ref<Store> store, const Paths & storePaths)
@ -85,28 +87,42 @@ struct MixVerify : virtual Args
} }
if (!noSigs) { if (!noTrust) {
bool good = false; bool good = false;
if (info.ultimate) if (info.ultimate && !sigsNeeded)
good = true; good = true;
if (!good && info.checkSignatures(publicKeys)) else {
good = true;
StringSet sigsSeen;
size_t actualSigsNeeded = sigsNeeded ? sigsNeeded : 1;
size_t validSigs = 0;
auto doSigs = [&](StringSet sigs) {
for (auto sig : sigs) {
if (sigsSeen.count(sig)) continue;
sigsSeen.insert(sig);
if (info.checkSignature(publicKeys, sig))
validSigs++;
}
};
doSigs(info.sigs);
if (!good) {
for (auto & store2 : substituters) { for (auto & store2 : substituters) {
// FIXME: catch errors? if (validSigs >= actualSigsNeeded) break;
if (!store2->isValidPath(storePath)) continue; try {
auto info2 = store2->queryPathInfo(storePath); if (!store2->isValidPath(storePath)) continue;
auto info3(info); doSigs(store2->queryPathInfo(storePath).sigs);
info3.sigs = info2.sigs; } catch (Error & e) {
if (info3.checkSignatures(publicKeys)) { printMsg(lvlError, format(ANSI_RED "error:" ANSI_NORMAL " %s") % e.what());
good = true;
break;
} }
} }
if (validSigs >= actualSigsNeeded)
good = true;
} }
if (!good) { if (!good) {