Просмотр исходного кода

support multiple fingerprints in signed-by

A keyring file can include multiple keys, so its only fair for
transitions and such to support multiple fingerprints as well.
David Kalnischkies лет назад: 10
Родитель
Сommit
46e00c9062
4 измененных файлов с 71 добавлено и 32 удалено
  1. 14 7
      apt-pkg/deb/debmetaindex.cc
  2. 5 5
      doc/sources.list.5.xml
  3. 17 13
      methods/gpgv.cc
  4. 35 7
      test/integration/test-releasefile-verification

+ 14 - 7
apt-pkg/deb/debmetaindex.cc

@@ -627,19 +627,26 @@ bool debReleaseIndex::SetSignedBy(std::string const &pSignedBy)
    if (SignedBy.empty() == true && pSignedBy.empty() == false)
    if (SignedBy.empty() == true && pSignedBy.empty() == false)
    {
    {
       if (pSignedBy[0] == '/') // no check for existence as we could be chrooting later or such things
       if (pSignedBy[0] == '/') // no check for existence as we could be chrooting later or such things
-	 ; // absolute path to a keyring file
+	 SignedBy = pSignedBy; // absolute path to a keyring file
       else
       else
       {
       {
 	 // we could go all fancy and allow short/long/string matches as gpgv/apt-key does,
 	 // 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,
 	 // 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.
 	 // not interactively all the time so easy to type is not really a concern.
-	 std::string finger = pSignedBy;
-	 finger.erase(std::remove(finger.begin(), finger.end(), ' '), finger.end());
-	 std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
-	 if (finger.length() != 40 || finger.find_first_not_of("0123456789ABCDEF") != std::string::npos)
-	    return _error->Error(_("Invalid value set for option %s regarding source %s %s (%s)"), "Signed-By", URI.c_str(), Dist.c_str(), "not a fingerprint");
+	 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();
       }
       }
-      SignedBy = pSignedBy;
    }
    }
    else if (SignedBy != pSignedBy)
    else if (SignedBy != pSignedBy)
       return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Signed-By", URI.c_str(), Dist.c_str());
       return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Signed-By", URI.c_str(), Dist.c_str());

+ 5 - 5
doc/sources.list.5.xml

@@ -284,13 +284,13 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [.
 	  <listitem><para><option>Signed-By</option> (<option>signed-by</option>)
 	  <listitem><para><option>Signed-By</option> (<option>signed-by</option>)
 		is either an absolute path to a keyring file (has to be
 		is either an absolute path to a keyring file (has to be
 		accessible and readable for the <literal>_apt</literal> user,
 		accessible and readable for the <literal>_apt</literal> user,
-		so ensure everyone has read-permissions on the file) or a
-		fingerprint of a key either in the
-		<filename>trusted.gpg</filename> keyring or in one of the
+		so ensure everyone has read-permissions on the file) or one or
+		more fingerprints of keys either in the
+		<filename>trusted.gpg</filename> keyring or in the
 		keyrings in the <filename>trusted.gpg.d/</filename> directory
 		keyrings in the <filename>trusted.gpg.d/</filename> directory
 		(see <command>apt-key fingerprint</command>). If the option is
 		(see <command>apt-key fingerprint</command>). If the option is
-		set, only the key(s) in this keyring or only the key with this
-		fingerprint is used for the &apt-secure; verification of this
+		set, only the key(s) in this keyring or only the keys with these
+		fingerprints are used for the &apt-secure; verification of this
 		repository. Otherwise all keys in the trusted keyrings are
 		repository. Otherwise all keys in the trusted keyrings are
 		considered valid signers for this repository.
 		considered valid signers for this repository.
 	  </para></listitem>
 	  </para></listitem>

+ 17 - 13
methods/gpgv.cc

@@ -249,25 +249,29 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
    {
    {
       if (Debug == true)
       if (Debug == true)
 	 std::clog << "GoodSigs needs to be limited to keyid " << key << std::endl;
 	 std::clog << "GoodSigs needs to be limited to keyid " << key << std::endl;
-      std::vector<std::string>::iterator const foundItr = std::find(ValidSigners.begin(), ValidSigners.end(), key);
-      bool const found = (foundItr != ValidSigners.end());
-      std::copy(GoodSigners.begin(), GoodSigners.end(), std::back_insert_iterator<std::vector<std::string> >(NoPubKeySigners));
-      if (found)
+      bool foundGood = false;
+      for (auto const &k: VectorizeString(key, ','))
       {
       {
+	 if (std::find(ValidSigners.begin(), ValidSigners.end(), k) == ValidSigners.end())
+	    continue;
 	 // we look for GOODSIG here as well as an expired sig is a valid sig as well (but not a good one)
 	 // we look for GOODSIG here as well as an expired sig is a valid sig as well (but not a good one)
-	 std::string const goodlongkeyid = "GOODSIG " + key.substr(24, 16);
-	 bool const foundGood = std::find(GoodSigners.begin(), GoodSigners.end(), goodlongkeyid) != GoodSigners.end();
+	 std::string const goodlongkeyid = "GOODSIG " + k.substr(24, 16);
+	 foundGood = std::find(GoodSigners.begin(), GoodSigners.end(), goodlongkeyid) != GoodSigners.end();
 	 if (Debug == true)
 	 if (Debug == true)
-	    std::clog << "Key " << key << " is valid sig, is " << goodlongkeyid << " also a good one? " << (foundGood ? "yes" : "no") << std::endl;
+	    std::clog << "Key " << k << " is valid sig, is " << goodlongkeyid << " also a good one? " << (foundGood ? "yes" : "no") << std::endl;
+	 if (foundGood == false)
+	    continue;
+	 std::copy(GoodSigners.begin(), GoodSigners.end(), std::back_insert_iterator<std::vector<std::string> >(NoPubKeySigners));
 	 GoodSigners.clear();
 	 GoodSigners.clear();
-	 if (foundGood)
-	 {
-	    GoodSigners.push_back(goodlongkeyid);
-	    NoPubKeySigners.erase(std::remove(NoPubKeySigners.begin(), NoPubKeySigners.end(), goodlongkeyid), NoPubKeySigners.end());
-	 }
+	 GoodSigners.push_back(goodlongkeyid);
+	 NoPubKeySigners.erase(std::remove(NoPubKeySigners.begin(), NoPubKeySigners.end(), goodlongkeyid), NoPubKeySigners.end());
+	 break;
       }
       }
-      else
+      if (foundGood == false)
+      {
+	 std::copy(GoodSigners.begin(), GoodSigners.end(), std::back_insert_iterator<std::vector<std::string> >(NoPubKeySigners));
 	 GoodSigners.clear();
 	 GoodSigners.clear();
+      }
    }
    }
 
 
    int status;
    int status;

+ 35 - 7
test/integration/test-releasefile-verification

@@ -33,6 +33,7 @@ prepare() {
 }
 }
 
 
 installaptold() {
 installaptold() {
+	rm -rf rootdir/var/cache/apt/archives
 	testsuccessequal "Reading package lists...
 	testsuccessequal "Reading package lists...
 Building dependency tree...
 Building dependency tree...
 Suggested packages:
 Suggested packages:
@@ -249,30 +250,57 @@ runtest() {
 	signreleasefiles 'Joe Sixpack'
 	signreleasefiles 'Joe Sixpack'
 	find aptarchive/ -name "$DELETEFILE" -delete
 	find aptarchive/ -name "$DELETEFILE" -delete
 	updatewithwarnings '^W: .* NO_PUBKEY'
 	updatewithwarnings '^W: .* NO_PUBKEY'
-
 	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 #" rootdir/etc/apt/sources.list.d/*
 	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 #" rootdir/etc/apt/sources.list.d/*
+
 	local MARVIN="$(aptkey --keyring $MARVIN finger | grep 'Key fingerprint' | cut -d'=' -f 2 | tr -d ' ')"
 	local MARVIN="$(aptkey --keyring $MARVIN finger | grep 'Key fingerprint' | cut -d'=' -f 2 | tr -d ' ')"
+	msgmsg 'Cold archive signed by bad keyid' 'Joe Sixpack'
+	rm -rf rootdir/var/lib/apt/lists
+	signreleasefiles 'Joe Sixpack'
+	find aptarchive/ -name "$DELETEFILE" -delete
+	sed -i "s#^\(deb\(-src\)\?\) #\1 [signed-by=$MARVIN] #" rootdir/etc/apt/sources.list.d/*
+	updatewithwarnings '^W: .* be verified because the public key is not available: .*'
 
 
 	msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid'
 	msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid'
-	prepare "${PKGFILE}"
 	rm -rf rootdir/var/lib/apt/lists
 	rm -rf rootdir/var/lib/apt/lists
 	signreleasefiles 'Marvin Paranoid'
 	signreleasefiles 'Marvin Paranoid'
 	find aptarchive/ -name "$DELETEFILE" -delete
 	find aptarchive/ -name "$DELETEFILE" -delete
-	sed -i "s#^\(deb\(-src\)\?\) #\1 [signed-by=$MARVIN] #" rootdir/etc/apt/sources.list.d/*
 	cp keys/marvinparanoid.pub rootdir/etc/apt/trusted.gpg.d/marvinparanoid.gpg
 	cp keys/marvinparanoid.pub rootdir/etc/apt/trusted.gpg.d/marvinparanoid.gpg
 	successfulaptgetupdate
 	successfulaptgetupdate
 	testsuccessequal "$(cat "${PKGFILE}")
 	testsuccessequal "$(cat "${PKGFILE}")
 " aptcache show apt
 " aptcache show apt
 	installaptold
 	installaptold
-	rm -f rootdir/etc/apt/trusted.gpg.d/marvinparanoid.gpg
 
 
-	msgmsg 'Cold archive signed by bad keyid' 'Joe Sixpack'
+	msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid,Joe Sixpack'
+	rm -rf rootdir/var/lib/apt/lists
+	signreleasefiles 'Marvin Paranoid,Joe Sixpack'
+	find aptarchive/ -name "$DELETEFILE" -delete
+	successfulaptgetupdate 'NoPubKey: GOODSIG'
+	testsuccessequal "$(cat "${PKGFILE}")
+" aptcache show apt
+	installaptold
+
+	local SIXPACK="$(aptkey --keyring keys/joesixpack.pub finger | grep 'Key fingerprint' | cut -d'=' -f 2 | tr -d ' ')"
+	msgmsg 'Cold archive signed by good keyids' 'Joe Sixpack'
 	rm -rf rootdir/var/lib/apt/lists
 	rm -rf rootdir/var/lib/apt/lists
 	signreleasefiles 'Joe Sixpack'
 	signreleasefiles 'Joe Sixpack'
 	find aptarchive/ -name "$DELETEFILE" -delete
 	find aptarchive/ -name "$DELETEFILE" -delete
-	updatewithwarnings '^W: .* be verified because the public key is not available: .*'
+	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 [signed-by=${SIXPACK},${MARVIN}] #" rootdir/etc/apt/sources.list.d/*
+	successfulaptgetupdate
+	testsuccessequal "$(cat "${PKGFILE}")
+" aptcache show apt
+	installaptold
+
+	local SIXPACK="$(aptkey --keyring keys/joesixpack.pub finger | grep 'Key fingerprint' | cut -d'=' -f 2 | tr -d ' ')"
+	msgmsg 'Cold archive signed by good keyids' 'Joe Sixpack'
+	rm -rf rootdir/var/lib/apt/lists
+	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=${SIXPACK},${MARVIN}\] #\1 [signed-by=${MARVIN},${SIXPACK}] #" rootdir/etc/apt/sources.list.d/*
+	successfulaptgetupdate
+	testsuccessequal "$(cat "${PKGFILE}")
+" aptcache show apt
+	installaptold
+	rm -f rootdir/etc/apt/trusted.gpg.d/marvinparanoid.gpg
+	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=${MARVIN},${SIXPACK}\] #\1 #" rootdir/etc/apt/sources.list.d/*
 
 
-	sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 #" rootdir/etc/apt/sources.list.d/*
 }
 }
 
 
 runtest2() {
 runtest2() {