]> git.saurik.com Git - apt.git/commitdiff
implement Signed-By option for sources.list
authorDavid Kalnischkies <david@kalnischkies.de>
Wed, 24 Jun 2015 17:31:22 +0000 (19:31 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Mon, 10 Aug 2015 15:25:26 +0000 (17:25 +0200)
Limits which key(s) can be used to sign a repository. Not immensely useful
from a security perspective all by itself, but if the user has
additional measures in place to confine a repository (like pinning) an
attacker who gets the key for such a repository is limited to its
potential and can't use the key to sign its attacks for an other (maybe
less limited) repository… (yes, this is as weak as it sounds, but having
the capability might come in handy for implementing other stuff later).

15 files changed:
apt-pkg/acquire-item.cc
apt-pkg/acquire-item.h
apt-pkg/contrib/gpgv.cc
apt-pkg/contrib/gpgv.h
apt-pkg/deb/debmetaindex.cc
apt-pkg/deb/debmetaindex.h
apt-pkg/metaindex.cc
apt-pkg/metaindex.h
apt-pkg/sourcelist.cc
cmdline/apt-key.in
doc/sources.list.5.xml
methods/gpgv.cc
test/integration/framework
test/integration/test-apt-key
test/integration/test-releasefile-verification

index a30a5d1548d5e2829219fb89f20efbbd1802fb23..01a679fe01c92d425ee0e17f2936b6c190c88be6 100644 (file)
@@ -808,7 +808,6 @@ string pkgAcqMetaBase::Custom600Headers() const
    Header += MaximumSize;
 
    string const FinalFile = GetFinalFilename();
-
    struct stat Buf;
    if (stat(FinalFile.c_str(),&Buf) == 0)
       Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
@@ -1132,6 +1131,10 @@ string pkgAcqMetaClearSig::Custom600Headers() const
 {
    string Header = pkgAcqMetaBase::Custom600Headers();
    Header += "\nFail-Ignore: true";
+   std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
+   if (key.empty() == false)
+      Header += "\nSigned-By: " + key;
+
    return Header;
 }
                                                                        /*}}}*/
@@ -1372,6 +1375,16 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire * const Owner,
                                                                        /*}}}*/
 pkgAcqMetaSig::~pkgAcqMetaSig()                                                /*{{{*/
 {
+}
+                                                                       /*}}}*/
+// pkgAcqMetaSig::Custom600Headers - Insert custom request headers     /*{{{*/
+std::string pkgAcqMetaSig::Custom600Headers() const
+{
+   std::string Header = pkgAcqTransactionItem::Custom600Headers();
+   std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
+   if (key.empty() == false)
+      Header += "\nSigned-By: " + key;
+   return Header;
 }
                                                                        /*}}}*/
 // AcqMetaSig::Done - The signature was downloaded/verified            /*{{{*/
index 10ece76c9ac6f173d8817b3be58fda1ee349d56c..1cd2a6d035740f6d53643f3698f798b9d8c9b816 100644 (file)
@@ -541,6 +541,7 @@ class APT_HIDDEN pkgAcqMetaSig : public pkgAcqTransactionItem
    virtual void Failed(std::string const &Message,pkgAcquire::MethodConfig const * const Cnf);
    virtual void Done(std::string const &Message, HashStringList const &Hashes,
                     pkgAcquire::MethodConfig const * const Cnf);
+   virtual std::string Custom600Headers() const;
 
    /** \brief Create a new pkgAcqMetaSig. */
    pkgAcqMetaSig(pkgAcquire * const Owner, pkgAcqMetaClearSig * const TransactionManager,
index a01e319eb3e8ea0b5a03be6c4f9f10110e1398af..ef84da0d82936b938a1d6bf35ec21c10bae45302 100644 (file)
@@ -16,6 +16,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <stddef.h>
+
+#include <algorithm>
 #include <iostream>
 #include <string>
 #include <vector>
@@ -42,7 +44,7 @@ static char * GenerateTemporaryFileTemplate(const char *basename)     /*{{{*/
    of the lifting in regards to merging keyrings. Fun for the whole family.
 */
 void ExecGPGV(std::string const &File, std::string const &FileGPG,
-             int const &statusfd, int fd[2])
+             int const &statusfd, int fd[2], std::string const &key)
 {
    #define EINTERNAL 111
    std::string const aptkey = _config->FindFile("Dir::Bin::apt-key", "/usr/bin/apt-key");
@@ -55,6 +57,19 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
    Args.push_back(aptkey.c_str());
    Args.push_back("--quiet");
    Args.push_back("--readonly");
+   if (key.empty() == false)
+   {
+      if (key[0] == '/')
+      {
+        Args.push_back("--keyring");
+        Args.push_back(key.c_str());
+      }
+      else
+      {
+        Args.push_back("--keyid");
+        Args.push_back(key.c_str());
+      }
+   }
    Args.push_back("verify");
 
    char statusfdstr[10];
index f018893fdbac998da44eddc222a0d27b530d3bdc..2a4cdad72f7a6aa4372c252559dd66b94d725194 100644 (file)
@@ -38,9 +38,12 @@ class FileFd;
  *
  * @param File is the message (unsigned or clear-signed)
  * @param FileSig is the signature (detached or clear-signed)
+ * @param statusfd is the fd given to gpgv as --status-fd
+ * @param fd is used as a pipe for the standard output of gpgv
+ * @param key is the specific one to be used instead of using all
  */
 void ExecGPGV(std::string const &File, std::string const &FileSig,
-      int const &statusfd, int fd[2]) APT_NORETURN;
+      int const &statusfd, int fd[2], std::string const &Key = "") APT_NORETURN;
 inline APT_NORETURN void ExecGPGV(std::string const &File, std::string const &FileSig,
       int const &statusfd = -1) {
    int fd[2];
index 5d7e539c7cbd5f7d9310246ce54d2b353d6dc2d6..4bb03a9420a502c09cd63221a7951d5c4d8982c7 100644 (file)
@@ -461,6 +461,29 @@ bool debReleaseIndex::SetValidUntilMax(time_t const Valid)
    else if (d->ValidUntilMax != Valid)
       return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Max-ValidTime", URI.c_str(), Dist.c_str());
    return true;
+}
+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
+        ; // 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.
+        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 concerning source %s %s (%s)"), "Signed-By", URI.c_str(), Dist.c_str(), "not a fingerprint");
+      }
+      SignedBy = pSignedBy;
+   }
+   else if (SignedBy != pSignedBy)
+      return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Signed-By", URI.c_str(), Dist.c_str());
+   return true;
 }
                                                                        /*}}}*/
 // ReleaseIndex::IsTrusted                                             /*{{{*/
@@ -706,6 +729,18 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type              /*{{{*/
         Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false)
         return false;
 
+      std::map<std::string, std::string>::const_iterator const signedby = Options.find("signed-by");
+      if (signedby == Options.end())
+      {
+        if (Deb->SetSignedBy("") == false)
+           return false;
+      }
+      else
+      {
+        if (Deb->SetSignedBy(signedby->second) == false)
+           return false;
+      }
+
       return true;
    }
 
index 879eb3bfca827ab348bf85d14b8d4e8136a25d45..bf5b7c1cecf7aa2e7dd4ef69ff6045907b73b09c 100644 (file)
@@ -56,6 +56,7 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
    bool SetCheckValidUntil(TriState const Trusted);
    bool SetValidUntilMin(time_t const Valid);
    bool SetValidUntilMax(time_t const Valid);
+   bool SetSignedBy(std::string const &SignedBy);
 
    virtual bool IsTrusted() const;
 
index 8bd13bb18866c3ffdc7efbaa385c6b83b6abfbd2..baf695f164e05ccfdbf1ceb1ae8d7e4e081153f1 100644 (file)
@@ -27,8 +27,7 @@ bool metaIndex::Merge(pkgCacheGenerator &Gen,OpProgress *) const
 metaIndex::metaIndex(std::string const &URI, std::string const &Dist,
       char const * const Type)
 : d(NULL), Indexes(NULL), Type(Type), URI(URI), Dist(Dist), Trusted(TRI_UNSET),
-   LoadedSuccessfully(TRI_UNSET),
-   Date(0), ValidUntil(0), SupportsAcquireByHash(false)
+   Date(0), ValidUntil(0), SupportsAcquireByHash(false), LoadedSuccessfully(TRI_UNSET)
 {
    /* nothing */
 }
@@ -48,6 +47,7 @@ APT_PURE std::string metaIndex::GetURI() const { return URI; }
 APT_PURE std::string metaIndex::GetDist() const { return Dist; }
 APT_PURE const char* metaIndex::GetType() const { return Type; }
 APT_PURE metaIndex::TriState metaIndex::GetTrusted() const { return Trusted; }
+APT_PURE std::string metaIndex::GetSignedBy() const { return SignedBy; }
 APT_PURE std::string metaIndex::GetCodename() const { return Codename; }
 APT_PURE std::string metaIndex::GetSuite() const { return Suite; }
 APT_PURE bool metaIndex::GetSupportsAcquireByHash() const { return SupportsAcquireByHash; }
index 5be7397ae768fe6274036472f0d62930fc2e924c..d284655bfb5cf586ea353c6141050c8707610608 100644 (file)
@@ -52,7 +52,7 @@ protected:
    std::string URI;
    std::string Dist;
    TriState Trusted;
-   TriState LoadedSuccessfully;
+   std::string SignedBy;
 
    // parsed from a file
    std::string Suite;
@@ -61,6 +61,7 @@ protected:
    time_t ValidUntil;
    bool SupportsAcquireByHash;
    std::map<std::string, checkSum *> Entries;
+   TriState LoadedSuccessfully;
 
 public:
    // Various accessors
@@ -68,6 +69,7 @@ public:
    std::string GetDist() const;
    const char* GetType() const;
    TriState GetTrusted() const;
+   std::string GetSignedBy() const;
 
    std::string GetCodename() const;
    std::string GetSuite() const;
index 0d65558edcbf45a7840a752e28cdd1247c8125bd..eef0ee709cf76c8795210afe520008c9faebe42a 100644 (file)
@@ -93,27 +93,29 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List,    /*{{{*/
    if (Enabled.empty() == false && StringToBool(Enabled) == false)
       return true;
 
-   std::map<char const * const, char const * const> mapping;
+   std::map<char const * const, std::pair<char const * const, bool> > mapping;
 #define APT_PLUSMINUS(X, Y) \
-   mapping.insert(std::make_pair(X, Y)); \
-   mapping.insert(std::make_pair(X "Add", Y "+")); \
-   mapping.insert(std::make_pair(X "Remove", Y "-"))
+   mapping.insert(std::make_pair(X, std::make_pair(Y, true))); \
+   mapping.insert(std::make_pair(X "Add", std::make_pair(Y "+", true))); \
+   mapping.insert(std::make_pair(X "Remove", std::make_pair(Y "-", true)))
    APT_PLUSMINUS("Architectures", "arch");
    APT_PLUSMINUS("Languages", "lang");
    APT_PLUSMINUS("Targets", "target");
 #undef APT_PLUSMINUS
-   mapping.insert(std::make_pair("Trusted", "trusted"));
-   mapping.insert(std::make_pair("Check-Valid-Until", "check-valid-until"));
-   mapping.insert(std::make_pair("Valid-Until-Min", "valid-until-min"));
-   mapping.insert(std::make_pair("Valid-Until-Max", "valid-until-max"));
+   mapping.insert(std::make_pair("Trusted", std::make_pair("trusted", false)));
+   mapping.insert(std::make_pair("Check-Valid-Until", std::make_pair("check-valid-until", false)));
+   mapping.insert(std::make_pair("Valid-Until-Min", std::make_pair("valid-until-min", false)));
+   mapping.insert(std::make_pair("Valid-Until-Max", std::make_pair("valid-until-max", false)));
+   mapping.insert(std::make_pair("Signed-By", std::make_pair("signed-by", false)));
 
-   for (std::map<char const * const, char const * const>::const_iterator m = mapping.begin(); m != mapping.end(); ++m)
+   for (std::map<char const * const, std::pair<char const * const, bool> >::const_iterator m = mapping.begin(); m != mapping.end(); ++m)
       if (Tags.Exists(m->first))
       {
-         // for deb822 the " " is the delimiter, but the backend expects ","
-         std::string option = Tags.FindS(m->first);
-         std::replace(option.begin(), option.end(), ' ', ',');
-         Options[m->second] = option;
+        std::string option = Tags.FindS(m->first);
+        // for deb822 the " " is the delimiter, but the backend expects ","
+        if (m->second.second == true)
+           std::replace(option.begin(), option.end(), ' ', ',');
+        Options[m->second.first] = option;
       }
 
    // now create one item per suite/section
index 2a66ad74d182a805c5a62f410ab2a3857fc67ba8..16887bd50a55b99ea2cd3dd546d126c82d616bd2 100644 (file)
@@ -199,7 +199,7 @@ remove_key_from_keyring() {
 foreach_keyring_do() {
    local ACTION="$1"
    shift
-   # if a --keyring was given, just remove from there
+   # if a --keyring was given, just work on this one
    if [ -n "$FORCED_KEYRING" ]; then
        $ACTION "$FORCED_KEYRING" "$@"
    else
@@ -279,7 +279,14 @@ merge_back_changes() {
 }
 
 setup_merged_keyring() {
-    if [ -z "$FORCED_KEYRING" ]; then
+    if [ -n "$FORCED_KEYID" ]; then
+       foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/allrings.gpg"
+       FORCED_KEYRING="${GPGHOMEDIR}/forcedkeyid.gpg"
+       TRUSTEDFILE="${FORCED_KEYRING}"
+       GPG="$GPG --keyring $TRUSTEDFILE"
+       # ignore error as this "just" means we haven't found the forced keyid and the keyring will be empty
+       $GPG_CMD --batch --yes --keyring "${GPGHOMEDIR}/allrings.gpg" --export "$FORCED_KEYID" | $GPG --batch --yes --import || true
+    elif [ -z "$FORCED_KEYRING" ]; then
        foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
        if [ -r "${GPGHOMEDIR}/pubring.gpg" ]; then
            cp -a "${GPGHOMEDIR}/pubring.gpg" "${GPGHOMEDIR}/pubring.orig.gpg"
@@ -328,12 +335,17 @@ while [ -n "$1" ]; do
         TRUSTEDFILE="$1"
         FORCED_KEYRING="$1"
         ;;
+      --keyid)
+        shift
+        FORCED_KEYID="$1"
+        ;;
       --secret-keyring)
         shift
         FORCED_SECRET_KEYRING="$1"
         ;;
       --readonly)
         merge_back_changes() { true; }
+        create_new_keyring() { true; }
         ;;
       --fakeroot)
         requires_root() { true; }
@@ -460,7 +472,11 @@ case "$command" in
     verify)
        setup_merged_keyring
        if which gpgv >/dev/null 2>&1; then
-           gpgv --homedir "${GPGHOMEDIR}" --keyring "${GPGHOMEDIR}/pubring.gpg" --ignore-time-conflict "$@"
+           if [ -n "$FORCED_KEYRING" ]; then
+               gpgv --homedir "${GPGHOMEDIR}" --keyring "${FORCED_KEYRING}" --ignore-time-conflict "$@"
+           else
+               gpgv --homedir "${GPGHOMEDIR}" --keyring "${GPGHOMEDIR}/pubring.gpg" --ignore-time-conflict "$@"
+           fi
        else
            $GPG --verify "$@"
        fi
index aded8ecefcf7adefbf1743a1abd5c452dc4e78c3..12a7773f54e74922ee8f7c54870131fe758d8b5b 100644 (file)
@@ -232,18 +232,18 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [.
        anomalies.
 
        <itemizedlist>
-         <listitem><para><option>Trusted</option> (<option>trusted</option>)
-               is a tri-state value which defaults to APT deciding if a source
-               is considered trusted or if warnings should be raised before e.g.
-               packages are installed from this source. This option can be used
-               to override this decision either with the value <literal>yes</literal>,
-               which lets APT consider this source always as a trusted source
-               even if it has no or fails authentication checks by disabling parts
-               of &apt-secure; and should therefore only be used in a local and trusted
-               context (if at all) as otherwise security is breached. The opposite
-               can be achieved with the value no, which causes the source to be handled
-               as untrusted even if the authentication checks passed successfully.
-               The default value can't be set explicitly.
+         <listitem><para><option>Signed-By</option> (<option>signed-by</option>)
+               is either an absolute path to a keyring file (has to be
+               accessible and readable for the <literal>_apt</literal> user,
+               so ensure everyone has read-permissions on the file) or a
+               fingerprint of a key in either the
+               <filename>trusted.gpg</filename> keyring or in one of the
+               keyrings in the <filename>trusted.gpg.d/</filename> directory
+               (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
+               repository. Otherwise all keys in the trusted keyrings are
+               considered valid signers for this repository.
          </para></listitem>
 
          <listitem><para><option>Check-Valid-Until</option> (<option>check-valid-until</option>)
index 41f138be64d12b663896aca6129aad3b68d2498c..014430041a19feb9fe8faf1d91c87dbae220684b 100644 (file)
@@ -37,13 +37,14 @@ class GPGVMethod : public pkgAcqMethod
 {
    private:
    string VerifyGetSigners(const char *file, const char *outfile,
-                               vector<string> &GoodSigners, 
+                               std::string const &key,
+                               vector<string> &GoodSigners,
                                 vector<string> &BadSigners,
                                 vector<string> &WorthlessSigners,
                                vector<string> &NoPubKeySigners);
    
    protected:
-   virtual bool Fetch(FetchItem *Itm);
+   virtual bool URIAcquire(std::string const &Message, FetchItem *Itm);
    virtual bool Configuration(string Message);
    public:
    
@@ -61,6 +62,7 @@ bool GPGVMethod::Configuration(string Message)
 }
 
 string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
+                                        std::string const &key,
                                         vector<string> &GoodSigners,
                                         vector<string> &BadSigners,
                                         vector<string> &WorthlessSigners,
@@ -80,7 +82,7 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
    if (pid < 0)
       return string("Couldn't spawn new process") + strerror(errno);
    else if (pid == 0)
-      ExecGPGV(outfile, file, 3, fd);
+      ExecGPGV(outfile, file, 3, fd, key);
    close(fd[1]);
 
    FILE *pipein = fdopen(fd[0], "r");
@@ -174,11 +176,11 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
       return _("Unknown error executing apt-key");
 }
 
-bool GPGVMethod::Fetch(FetchItem *Itm)
+bool GPGVMethod::URIAcquire(std::string const &Message, FetchItem *Itm)
 {
-   URI Get = Itm->Uri;
-   string Path = Get.Host + Get.Path; // To account for relative paths
-   string keyID;
+   URI const Get = Itm->Uri;
+   string const Path = Get.Host + Get.Path; // To account for relative paths
+   std::string const key = LookupTag(Message, "Signed-By");
    vector<string> GoodSigners;
    vector<string> BadSigners;
    // a worthless signature is a expired or revoked one
@@ -190,7 +192,7 @@ bool GPGVMethod::Fetch(FetchItem *Itm)
    URIStart(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(),
+   string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), key,
                                  GoodSigners, BadSigners, WorthlessSigners,
                                  NoPubKeySigners);
    if (GoodSigners.empty() || !BadSigners.empty() || !NoPubKeySigners.empty())
index 059cba9fb54ffd6d2b5a2e9b100c62be31be7bf2..6ae5003f7b23deae28e3069ec50c31a8151d539f 100644 (file)
@@ -1414,14 +1414,23 @@ testfailure() {
        else
                local EXITCODE=$?
                if expr match "$1" '^apt.*' >/dev/null; then
-                       if grep -q -E ' runtime error: ' "$OUTPUT"; then
-                               msgfailoutput 'compiler detected undefined behavior' "$OUTPUT" "$@"
-                       elif grep -q -E '==ERROR' "$OUTPUT"; then
-                               msgfailoutput 'compiler sanitizers reported errors' "$OUTPUT" "$@"
-                       elif ! grep -q -E '^E: ' "$OUTPUT"; then
-                               msgfailoutput "run failed with exitcode ${EXITCODE}, but with no errors" "$OUTPUT" "$@"
+                       if [ "$1" = 'aptkey' ]; then
+                               if grep -q -E " Can't check signature: " "$OUTPUT" || \
+                                       grep -q -E " BAD signature from " "$OUTPUT"; then
+                                       msgpass
+                               else
+                                       msgfailoutput "run failed with exitcode ${EXITCODE}, but no signature error" "$OUTPUT" "$@"
+                               fi
                        else
-                               msgpass
+                               if grep -q -E ' runtime error: ' "$OUTPUT"; then
+                                       msgfailoutput 'compiler detected undefined behavior' "$OUTPUT" "$@"
+                               elif grep -q -E '==ERROR' "$OUTPUT"; then
+                                       msgfailoutput 'compiler sanitizers reported errors' "$OUTPUT" "$@"
+                               elif ! grep -q -E '^E: ' "$OUTPUT"; then
+                                       msgfailoutput "run failed with exitcode ${EXITCODE}, but with no errors" "$OUTPUT" "$@"
+                               else
+                                       msgpass
+                               fi
                        fi
                else
                        msgpass
index 486acccc80c406c002789135b4119a333fe741aa..e1be08c65150f2026317d8237a938c253cd6335e 100755 (executable)
@@ -73,7 +73,7 @@ pub   2048R/DBAC8DAE 2010-08-18'
        testsuccess aptkey --fakeroot del DBAC8DAE
        testempty aptkey list
 
-       msgtest 'Test key removal with' 'lowercase key ID' #keylength somewher between 8byte and short
+       msgtest 'Test key removal with' 'lowercase key ID' #keylength somewhere between 8byte and short
        cleanplate
        cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
        testsuccess --nomsg aptkey --fakeroot del d141dbac8dae
@@ -166,6 +166,40 @@ pub   2048R/528144E2 2011-01-16'
        msgtest 'Test merge-back of' 'removed duplicate keys'
        testsuccess --nomsg aptkey adv --batch --yes --delete-keys DBAC8DAE
        testaptkeys 'pub   2048R/528144E2 2011-01-16'
+
+       cleanplate
+       cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
+       cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
+       msgtest 'Test signing a file' 'with a key'
+       echo 'Verify me. This is my signature.' > signature
+       testsuccess --nomsg aptkey --quiet --keyring keys/marvinparanoid.pub --secret-keyring keys/marvinparanoid.sec --readonly \
+               adv --batch --yes --default-key 'Marvin' --armor --detach-sign --sign --output signature.gpg signature
+
+       msgtest 'Test verify a file' 'with all keys'
+       testsuccess --nomsg aptkey --quiet --readonly verify signature.gpg signature
+
+       msgtest 'Test verify a file' 'with good keyring'
+       testsuccess --nomsg aptkey --quiet --readonly --keyring keys/testcase-multikey.pub verify signature.gpg signature
+
+       msgtest 'Test fail verify a file' 'with bad keyring'
+       testfailure --nomsg aptkey --quiet --readonly --keyring keys/joesixpack.pub verify signature.gpg signature
+
+       msgtest 'Test fail verify a file' 'with non-existing keyring'
+       testfailure --nomsg aptkey --quiet --readonly --keyring keys/does-not-exist.pub verify signature.gpg signature
+       testfailure test -e keys/does-not-exist.pub
+
+       msgtest 'Test verify a file' 'with good keyid'
+       testsuccess --nomsg aptkey --quiet --readonly --keyid 'Paranoid' verify signature.gpg signature
+
+       msgtest 'Test fail verify a file' 'with bad keyid'
+       testfailure --nomsg aptkey --quiet --readonly --keyid 'Sixpack' verify signature.gpg signature
+
+       msgtest 'Test fail verify a file' 'with non-existing keyid'
+       testfailure --nomsg aptkey --quiet --readonly --keyid 'Kalnischkies' verify signature.gpg signature
+
+       msgtest 'Test verify fails on' 'bad file'
+       echo 'lalalalala' > signature
+       testfailure --nomsg aptkey --quiet --readonly verify signature.gpg signature
 }
 
 setupgpgcommand() {
@@ -187,4 +221,3 @@ setupgpgcommand 'gpg'
 testrun
 setupgpgcommand 'gpg2'
 testrun
-
index e8419524ce23fad929feb526d5ad9e47dedce34f..1c3953c8b38302c5748471984689628fbc9f95b0 100755 (executable)
@@ -139,11 +139,6 @@ runtest() {
        failaptold
 
        prepare ${PKGFILE}-new
-       # weborf doesn't support If-Range
-       for release in $(find rootdir/var/lib/apt/lists/partial/ -name '*Release'); do
-               rm $release
-               touch $release
-       done
        signreleasefiles 'Joe Sixpack'
        find aptarchive/ -name "$DELETEFILE" -delete
        msgmsg 'Bad warm archive signed by' 'Joe Sixpack'
@@ -191,6 +186,48 @@ runtest() {
        testsuccessequal "$(cat ${PKGFILE}-new)
 " aptcache show apt
        installaptnew
+
+       prepare ${PKGFILE}
+       rm -rf rootdir/var/lib/apt/lists
+       signreleasefiles 'Marvin Paranoid'
+       find aptarchive/ -name "$DELETEFILE" -delete
+       msgmsg 'Cold archive signed by good keyring' 'Marvin Paranoid'
+       local MARVIN="$(readlink -f keys/marvinparanoid.pub)"
+       sed -i "s#^\(deb\(-src\)\?\) #\1 [signed-by=$MARVIN] #" rootdir/etc/apt/sources.list.d/*
+       testsuccess aptget update -o Debug::pkgAcquire::Worker=1
+       testsuccessequal "$(cat ${PKGFILE})
+" aptcache show apt
+       installaptold
+
+       rm -rf rootdir/var/lib/apt/lists
+       signreleasefiles 'Joe Sixpack'
+       find aptarchive/ -name "$DELETEFILE" -delete
+       msgmsg 'Cold archive signed by bad keyring' 'Joe Sixpack'
+       updatewithwarnings '^W: .* NO_PUBKEY'
+
+       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 ' ')"
+
+       prepare ${PKGFILE}
+       rm -rf rootdir/var/lib/apt/lists
+       signreleasefiles 'Marvin Paranoid'
+       find aptarchive/ -name "$DELETEFILE" -delete
+       msgmsg 'Cold archive signed by good keyid' 'Marvin Paranoid'
+       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
+       testsuccess aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+       testsuccessequal "$(cat ${PKGFILE})
+" aptcache show apt
+       installaptold
+       rm -f rootdir/etc/apt/trusted.gpg.d/marvinparanoid.gpg
+
+       rm -rf rootdir/var/lib/apt/lists
+       signreleasefiles 'Joe Sixpack'
+       find aptarchive/ -name "$DELETEFILE" -delete
+       msgmsg 'Cold archive signed by bad keyid' 'Joe Sixpack'
+       updatewithwarnings '^W: .* NO_PUBKEY'
+
+       sed -i "s#^\(deb\(-src\)\?\) \[signed-by=$MARVIN\] #\1 #" rootdir/etc/apt/sources.list.d/*
 }
 
 runtest2() {