#define GNUPGPREFIX "[GNUPG:]"
#define GNUPGBADSIG "[GNUPG:] BADSIG"
+#define GNUPGERRSIG "[GNUPG:] ERRSIG"
#define GNUPGNOPUBKEY "[GNUPG:] NO_PUBKEY"
#define GNUPGVALIDSIG "[GNUPG:] VALIDSIG"
#define GNUPGGOODSIG "[GNUPG:] GOODSIG"
-#define GNUPGKEYEXPIRED "[GNUPG:] KEYEXPIRED"
+#define GNUPGEXPKEYSIG "[GNUPG:] EXPKEYSIG"
+#define GNUPGEXPSIG "[GNUPG:] EXPSIG"
#define GNUPGREVKEYSIG "[GNUPG:] REVKEYSIG"
#define GNUPGNODATA "[GNUPG:] NODATA"
Trusted,
} state;
char name[32];
+
+ State getState() const {
+ std::string optionUntrusted;
+ std::string optionWeak;
+ strprintf(optionUntrusted, "APT::Hashes::%s::Untrusted", name);
+ strprintf(optionWeak, "APT::Hashes::%s::Weak", name);
+ if (_config->FindB(optionUntrusted, state == State::Untrusted) == true)
+ return State::Untrusted;
+ if (_config->FindB(optionWeak, state == State::Weak) == true)
+ return State::Weak;
+
+ return state;
+ }
};
static constexpr Digest Digests[] = {
std::string key;
std::string note;
};
+static bool IsTheSameKey(std::string const &validsig, std::string const &goodsig) {
+ // VALIDSIG reports a keyid (40 = 24 + 16), GOODSIG is a longid (16) only
+ return validsig.compare(24, 16, goodsig, strlen("GOODSIG "), 16) == 0;
+}
class GPGVMethod : public aptMethod
{
protected:
virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE;
public:
-
GPGVMethod() : aptMethod("gpgv","1.0",SingleInstance | SendConfig) {};
};
-
+static void PushEntryWithKeyID(std::vector<std::string> &Signers, char * const buffer, bool const Debug)
+{
+ char * const msg = buffer + sizeof(GNUPGPREFIX);
+ char *p = msg;
+ // skip the message
+ while (*p && !isspace(*p))
+ ++p;
+ // skip the seperator whitespace
+ ++p;
+ // skip the hexdigit fingerprint
+ while (*p && isxdigit(*p))
+ ++p;
+ // cut the rest from the message
+ *p = '\0';
+ if (Debug == true)
+ std::clog << "Got " << msg << " !" << std::endl;
+ Signers.push_back(msg);
+}
+static void PushEntryWithUID(std::vector<std::string> &Signers, char * const buffer, bool const Debug)
+{
+ std::string msg = buffer + sizeof(GNUPGPREFIX);
+ auto const nuke = msg.find_last_not_of("\n\t\r");
+ if (nuke != std::string::npos)
+ msg.erase(nuke + 1);
+ if (Debug == true)
+ std::clog << "Got " << msg << " !" << std::endl;
+ Signers.push_back(msg);
+}
string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
std::string const &key,
vector<string> &GoodSigners,
// Loop over the output of apt-key (which really is gnupg), and check the signatures.
std::vector<std::string> ValidSigners;
+ std::vector<std::string> ErrSigners;
size_t buffersize = 0;
char *buffer = NULL;
while (1)
// if we improve the apt method communication stuff later
// it will be better.
if (strncmp(buffer, GNUPGBADSIG, sizeof(GNUPGBADSIG)-1) == 0)
- {
- if (Debug == true)
- std::clog << "Got BADSIG! " << std::endl;
- BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
- }
+ PushEntryWithUID(BadSigners, buffer, Debug);
+ else if (strncmp(buffer, GNUPGERRSIG, sizeof(GNUPGERRSIG)-1) == 0)
+ PushEntryWithKeyID(ErrSigners, buffer, Debug);
else if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0)
{
- if (Debug == true)
- std::clog << "Got NO_PUBKEY " << std::endl;
- NoPubKeySigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
+ PushEntryWithKeyID(NoPubKeySigners, buffer, Debug);
+ ErrSigners.erase(std::remove_if(ErrSigners.begin(), ErrSigners.end(), [&](std::string const &errsig) {
+ return errsig.compare(strlen("ERRSIG "), 16, buffer, sizeof(GNUPGNOPUBKEY), 16) == 0; }), ErrSigners.end());
}
else if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0)
- {
- if (Debug == true)
- std::clog << "Got NODATA! " << std::endl;
- BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
- }
- else if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0)
- {
- if (Debug == true)
- std::clog << "Got KEYEXPIRED! " << std::endl;
- WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
- }
+ PushEntryWithUID(BadSigners, buffer, Debug);
+ else if (strncmp(buffer, GNUPGEXPKEYSIG, sizeof(GNUPGEXPKEYSIG)-1) == 0)
+ PushEntryWithUID(WorthlessSigners, buffer, Debug);
+ else if (strncmp(buffer, GNUPGEXPSIG, sizeof(GNUPGEXPSIG)-1) == 0)
+ PushEntryWithUID(WorthlessSigners, buffer, Debug);
else if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0)
- {
- if (Debug == true)
- std::clog << "Got REVKEYSIG! " << std::endl;
- WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
- }
+ PushEntryWithUID(WorthlessSigners, buffer, Debug);
else if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0)
- {
- char *sig = buffer + sizeof(GNUPGPREFIX);
- char *p = sig + sizeof("GOODSIG");
- while (*p && isxdigit(*p))
- p++;
- *p = 0;
- if (Debug == true)
- std::clog << "Got GOODSIG, key ID:" << sig << std::endl;
- GoodSigners.push_back(string(sig));
- }
+ PushEntryWithKeyID(GoodSigners, buffer, Debug);
else if (strncmp(buffer, GNUPGVALIDSIG, sizeof(GNUPGVALIDSIG)-1) == 0)
{
- char *sig = buffer + sizeof(GNUPGVALIDSIG);
- std::istringstream iss((string(sig)));
+ std::istringstream iss(buffer + sizeof(GNUPGVALIDSIG));
vector<string> tokens{std::istream_iterator<string>{iss},
std::istream_iterator<string>{}};
- char *p = sig;
- while (*p && isxdigit(*p))
- p++;
- *p = 0;
+ auto const sig = tokens[0];
// Reject weak digest algorithms
Digest digest = FindDigest(tokens[7]);
- switch (digest.state) {
+ switch (digest.getState()) {
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});
+ SoonWorthlessSigners.push_back({sig, digest.name});
if (Debug == true)
std::clog << "Got weak VALIDSIG, key ID: " << sig << std::endl;
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)));
+ WorthlessSigners.push_back(sig);
+ GoodSigners.erase(std::remove_if(GoodSigners.begin(), GoodSigners.end(), [&](std::string const &goodsig) {
+ return IsTheSameKey(sig, goodsig); }), GoodSigners.end());
if (Debug == true)
std::clog << "Got untrusted VALIDSIG, key ID: " << sig << std::endl;
break;
- case Digest::State::Trusted:
+
+ case Digest::State::Trusted:
if (Debug == true)
std::clog << "Got trusted VALIDSIG, key ID: " << sig << std::endl;
break;
}
- ValidSigners.push_back(string(sig));
+ ValidSigners.push_back(sig);
}
}
fclose(pipein);
free(buffer);
+ std::move(ErrSigners.begin(), ErrSigners.end(), std::back_inserter(WorthlessSigners));
// apt-key has a --keyid parameter, but this requires gpg, so we call it without it
// and instead check after the fact which keyids where used for verification
{
ioprintf(std::clog, "gpgv exited with status %i\n", WEXITSTATUS(status));
}
-
+
+ if (Debug)
+ {
+ std::cerr << "Summary:" << std::endl << " Good: ";
+ std::copy(GoodSigners.begin(), GoodSigners.end(), std::ostream_iterator<std::string>(std::cerr, ", "));
+ std::cerr << std::endl << " Bad: ";
+ std::copy(BadSigners.begin(), BadSigners.end(), std::ostream_iterator<std::string>(std::cerr, ", "));
+ std::cerr << std::endl << " Worthless: ";
+ std::copy(WorthlessSigners.begin(), WorthlessSigners.end(), std::ostream_iterator<std::string>(std::cerr, ", "));
+ std::cerr << std::endl << " SoonWorthless: ";
+ std::for_each(SoonWorthlessSigners.begin(), SoonWorthlessSigners.end(), [](Signer const &sig) { std::cerr << sig.key << ", "; });
+ std::cerr << std::endl << " NoPubKey: ";
+ std::copy(NoPubKeySigners.begin(), NoPubKeySigners.end(), std::ostream_iterator<std::string>(std::cerr, ", "));
+ std::cerr << std::endl;
+ }
+
if (WEXITSTATUS(status) == 0)
{
if (keyIsID)
// Check if all good signers are soon worthless and warn in that case
if (std::all_of(GoodSigners.begin(), GoodSigners.end(), [&](std::string const &good) {
return std::any_of(SoonWorthlessSigners.begin(), SoonWorthlessSigners.end(), [&](Signer const &weak) {
- // VALIDSIG reports a keyid (40 = 24 + 16), GOODSIG is a longid (16) only
- return weak.key.compare(24, 16, good, strlen("GOODSIG "), 16) == 0;
+ return IsTheSameKey(weak.key, good);
});
}))
{
// structure is too difficult with the method stuff. We keep it
// as three separate vectors for future extensibility.
Res.GPGVOutput = GoodSigners;
- Res.GPGVOutput.insert(Res.GPGVOutput.end(),BadSigners.begin(),BadSigners.end());
- Res.GPGVOutput.insert(Res.GPGVOutput.end(),NoPubKeySigners.begin(),NoPubKeySigners.end());
+ std::move(BadSigners.begin(), BadSigners.end(), std::back_inserter(Res.GPGVOutput));
+ std::move(NoPubKeySigners.begin(), NoPubKeySigners.end(), std::back_inserter(Res.GPGVOutput));
URIDone(Res);
if (_config->FindB("Debug::Acquire::gpgv", false))