#include <apt-pkg/gpgv.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/fileutl.h>
+#include "aptmethod.h"
#include <ctype.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <array>
#include <algorithm>
+#include <sstream>
+#include <iterator>
#include <iostream>
#include <string>
#include <vector>
#define GNUPGREVKEYSIG "[GNUPG:] REVKEYSIG"
#define GNUPGNODATA "[GNUPG:] NODATA"
-class GPGVMethod : public pkgAcqMethod
+struct Digest {
+ enum class State {
+ Untrusted,
+ Weak,
+ Trusted,
+ } state;
+ char name[32];
+};
+
+static constexpr Digest Digests[] = {
+ {Digest::State::Untrusted, "Invalid digest"},
+ {Digest::State::Untrusted, "MD5"},
+ {Digest::State::Weak, "SHA1"},
+ {Digest::State::Weak, "RIPE-MD/160"},
+ {Digest::State::Trusted, "Reserved digest"},
+ {Digest::State::Trusted, "Reserved digest"},
+ {Digest::State::Trusted, "Reserved digest"},
+ {Digest::State::Trusted, "Reserved digest"},
+ {Digest::State::Trusted, "SHA256"},
+ {Digest::State::Trusted, "SHA384"},
+ {Digest::State::Trusted, "SHA512"},
+ {Digest::State::Trusted, "SHA224"},
+};
+
+static Digest FindDigest(std::string const & Digest)
+{
+ int id = atoi(Digest.c_str());
+ if (id >= 0 && static_cast<unsigned>(id) < _count(Digests)) {
+ return Digests[id];
+ } else {
+ return Digests[0];
+ }
+}
+
+struct Signer {
+ std::string key;
+ std::string note;
+};
+
+class GPGVMethod : public aptMethod
{
private:
string VerifyGetSigners(const char *file, const char *outfile,
vector<string> &GoodSigners,
vector<string> &BadSigners,
vector<string> &WorthlessSigners,
+ vector<Signer> &SoonWorthlessSigners,
vector<string> &NoPubKeySigners);
-
protected:
virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE;
- virtual bool Configuration(string Message) APT_OVERRIDE;
public:
- GPGVMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {};
+ GPGVMethod() : aptMethod("gpgv","1.0",SingleInstance | SendConfig) {};
};
-bool GPGVMethod::Configuration(string Message)
-{
- if (pkgAcqMethod::Configuration(Message) == false)
- return false;
-
- DropPrivsOrDie();
-
- return true;
-}
-
string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
std::string const &key,
vector<string> &GoodSigners,
vector<string> &BadSigners,
vector<string> &WorthlessSigners,
+ vector<Signer> &SoonWorthlessSigners,
vector<string> &NoPubKeySigners)
{
bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
else if (strncmp(buffer, GNUPGVALIDSIG, sizeof(GNUPGVALIDSIG)-1) == 0)
{
char *sig = buffer + sizeof(GNUPGVALIDSIG);
+ std::istringstream iss((string(sig)));
+ vector<string> tokens{std::istream_iterator<string>{iss},
+ std::istream_iterator<string>{}};
char *p = sig;
while (*p && isxdigit(*p))
p++;
*p = 0;
if (Debug == true)
std::clog << "Got VALIDSIG, key ID: " << sig << std::endl;
+ // Reject weak digest algorithms
+ Digest digest = FindDigest(tokens[7]);
+ switch (digest.state) {
+ case Digest::State::Weak:
+ // Treat them like an expired key: For that a message about expiry
+ // is emitted, a VALIDSIG, but no GOODSIG.
+ SoonWorthlessSigners.push_back({string(sig), digest.name});
+ break;
+ case Digest::State::Untrusted:
+ // Treat them like an expired key: For that a message about expiry
+ // is emitted, a VALIDSIG, but no GOODSIG.
+ WorthlessSigners.push_back(string(sig));
+ GoodSigners.erase(std::remove(GoodSigners.begin(), GoodSigners.end(), string(sig)));
+ break;
+ case Digest::State::Trusted:
+ break;
+ }
+
ValidSigners.push_back(string(sig));
}
}
vector<string> BadSigners;
// a worthless signature is a expired or revoked one
vector<string> WorthlessSigners;
+ vector<Signer> SoonWorthlessSigners;
vector<string> NoPubKeySigners;
FetchResult Res;
// Run apt-key on file, extract contents and get the key ID of the signer
string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), key,
GoodSigners, BadSigners, WorthlessSigners,
- NoPubKeySigners);
+ SoonWorthlessSigners, NoPubKeySigners);
+
+
+ // Check if there are any good signers that are not soon worthless
+ std::vector<std::string> NotWarnAboutSigners(GoodSigners);
+ for (auto const & Signer : SoonWorthlessSigners)
+ NotWarnAboutSigners.erase(std::remove(NotWarnAboutSigners.begin(), NotWarnAboutSigners.end(), "GOODSIG " + Signer.key));
+ // If all signers are soon worthless, report them.
+ if (NotWarnAboutSigners.empty()) {
+ for (auto const & Signer : SoonWorthlessSigners)
+ // TRANSLATORS: The second %s is the reason and is untranslated for repository owners.
+ Warning(_("Weak signature from %s (%s)"), Signer.key.c_str(), Signer.note.c_str());
+ }
+
if (GoodSigners.empty() || !BadSigners.empty() || !NoPubKeySigners.empty())
{
string errmsg;