summaryrefslogtreecommitdiff
path: root/apt-pkg/deb
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2018-08-17 11:59:45 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2018-09-11 13:16:11 +0200
commitff8fa4ab4b80384a9240f0df63181f71077a8d83 (patch)
tree9e01aae054c99f8467dc5c2feb196378a33772ea /apt-pkg/deb
parenta5953d914488c80c28fba6b59d2f0be461cd9f03 (diff)
Support subkeys properly in Signed-By options
If we limit a file to be signed by a certain key it should usually accept also being signed by any of this keys subkeys instead of requiring each subkey to be listed explicitly. If the later is really wanted we support now also the same syntax as gpg does with appending an exclamation mark at the end of the fingerprint to force no mapping.
Diffstat (limited to 'apt-pkg/deb')
-rw-r--r--apt-pkg/deb/debmetaindex.cc113
1 files changed, 62 insertions, 51 deletions
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index 9c7c70784..1afcdf2c0 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -28,6 +28,57 @@
#include <apti18n.h>
+static std::string transformFingergrpints(std::string finger) /*{{{*/
+{
+ std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
+ if (finger.length() == 40)
+ {
+ if (finger.find_first_not_of("0123456789ABCDEF") == std::string::npos)
+ return finger;
+ }
+ else if (finger.length() == 41)
+ {
+ auto bang = finger.find_first_not_of("0123456789ABCDEF");
+ if (bang == 40 && finger[bang] == '!')
+ return finger;
+ }
+ return "";
+}
+ /*}}}*/
+static std::string transformFingergrpintsWithFilenames(std::string const &finger) /*{{{*/
+{
+ // no check for existence as we could be chrooting later or such things
+ if (finger.empty() == false && finger[0] == '/')
+ return finger;
+ return transformFingergrpints(finger);
+}
+ /*}}}*/
+static std::string NormalizeSignedBy(std::string SignedBy, bool const SupportFilenames) /*{{{*/
+{
+ // we could go all fancy and allow short/long/string matches as gpgv/apt-key does,
+ // but fingerprints are harder to fake than the others and this option is set once,
+ // not interactively all the time so easy to type is not really a concern.
+ std::transform(SignedBy.begin(), SignedBy.end(), SignedBy.begin(), [](char const c) {
+ return (isspace(c) == 0) ? c : ',';
+ });
+ auto fingers = VectorizeString(SignedBy, ',');
+ auto const isAnEmptyString = [](std::string const &s) { return s.empty(); };
+ fingers.erase(std::remove_if(fingers.begin(), fingers.end(), isAnEmptyString), fingers.end());
+ if (unlikely(fingers.empty()))
+ return "";
+ if (SupportFilenames)
+ std::transform(fingers.begin(), fingers.end(), fingers.begin(), transformFingergrpintsWithFilenames);
+ else
+ std::transform(fingers.begin(), fingers.end(), fingers.begin(), transformFingergrpints);
+ if (std::any_of(fingers.begin(), fingers.end(), isAnEmptyString))
+ return "";
+ std::stringstream os;
+ std::copy(fingers.begin(), fingers.end() - 1, std::ostream_iterator<std::string>(os, ","));
+ os << *fingers.rbegin();
+ return os.str();
+}
+ /*}}}*/
+
class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
{
public:
@@ -566,26 +617,9 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
auto Sign = Section.FindS("Signed-By");
if (Sign.empty() == false)
{
- std::transform(Sign.begin(), Sign.end(), Sign.begin(), [&](char const c) {
- return (isspace(c) == 0) ? c : ',';
- });
- auto fingers = VectorizeString(Sign, ',');
- std::transform(fingers.begin(), fingers.end(), fingers.begin(), [&](std::string finger) {
- std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
- if (finger.length() != 40 || finger.find_first_not_of("0123456789ABCDEF") != std::string::npos)
- {
- if (ErrorText != NULL)
- strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Signed-By", Filename.c_str());
- return std::string();
- }
- return finger;
- });
- if (fingers.empty() == false && std::find(fingers.begin(), fingers.end(), "") == fingers.end())
- {
- std::stringstream os;
- std::copy(fingers.begin(), fingers.end(), std::ostream_iterator<std::string>(os, ","));
- SignedBy = os.str();
- }
+ SignedBy = NormalizeSignedBy(Sign, false);
+ if (SignedBy.empty() && ErrorText != NULL)
+ strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Signed-By", Filename.c_str());
}
if (AuthPossible)
@@ -737,38 +771,15 @@ bool debReleaseIndex::SetSignedBy(std::string const &pSignedBy)
{
if (SignedBy.empty() == true && pSignedBy.empty() == false)
{
- if (pSignedBy[0] == '/') // no check for existence as we could be chrooting later or such things
- SignedBy = pSignedBy; // absolute path to a keyring file
- else
- {
- // we could go all fancy and allow short/long/string matches as gpgv/apt-key does,
- // but fingerprints are harder to fake than the others and this option is set once,
- // not interactively all the time so easy to type is not really a concern.
- auto fingers = VectorizeString(pSignedBy, ',');
- std::transform(fingers.begin(), fingers.end(), fingers.begin(), [&](std::string finger) {
- std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
- if (finger.length() != 40 || finger.find_first_not_of("0123456789ABCDEF") != std::string::npos)
- {
- _error->Error(_("Invalid value set for option %s regarding source %s %s (%s)"), "Signed-By", URI.c_str(), Dist.c_str(), "not a fingerprint");
- return std::string();
- }
- return finger;
- });
- std::stringstream os;
- std::copy(fingers.begin(), fingers.end(), std::ostream_iterator<std::string>(os, ","));
- SignedBy = os.str();
- }
- // Normalize the string: Remove trailing commas
- while (SignedBy[SignedBy.size() - 1] == ',')
- SignedBy.resize(SignedBy.size() - 1);
+ SignedBy = NormalizeSignedBy(pSignedBy, true);
+ if (SignedBy.empty())
+ _error->Error(_("Invalid value set for option %s regarding source %s %s (%s)"), "Signed-By", URI.c_str(), Dist.c_str(), "not a fingerprint");
}
- else {
- // Only compare normalized strings
- auto pSignedByView = APT::StringView(pSignedBy);
- while (pSignedByView[pSignedByView.size() - 1] == ',')
- pSignedByView = pSignedByView.substr(0, pSignedByView.size() - 1);
- if (pSignedByView != SignedBy)
- return _error->Error(_("Conflicting values set for option %s regarding source %s %s: %s != %s"), "Signed-By", URI.c_str(), Dist.c_str(), SignedBy.c_str(), pSignedByView.to_string().c_str());
+ else
+ {
+ auto const normalSignedBy = NormalizeSignedBy(pSignedBy, true);
+ if (normalSignedBy != SignedBy)
+ return _error->Error(_("Conflicting values set for option %s regarding source %s %s: %s != %s"), "Signed-By", URI.c_str(), Dist.c_str(), SignedBy.c_str(), normalSignedBy.c_str());
}
return true;
}