gitee.com/mysnapcore/mysnapd@v0.1.0/asserts/database_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2015-2022 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package asserts_test
    21  
    22  import (
    23  	"bytes"
    24  	"crypto"
    25  	"encoding/base64"
    26  	"errors"
    27  	"fmt"
    28  	"io/ioutil"
    29  	"os"
    30  	"path/filepath"
    31  	"regexp"
    32  	"sort"
    33  	"testing"
    34  	"time"
    35  
    36  	"golang.org/x/crypto/openpgp/packet"
    37  	"golang.org/x/crypto/sha3"
    38  	. "gopkg.in/check.v1"
    39  
    40  	"gitee.com/mysnapcore/mysnapd/asserts"
    41  	"gitee.com/mysnapcore/mysnapd/asserts/assertstest"
    42  	"gitee.com/mysnapcore/mysnapd/testutil"
    43  )
    44  
    45  func Test(t *testing.T) { TestingT(t) }
    46  
    47  var _ = Suite(&openSuite{})
    48  var _ = Suite(&revisionErrorSuite{})
    49  var _ = Suite(&isUnacceptedUpdateSuite{})
    50  
    51  type openSuite struct{}
    52  
    53  func (opens *openSuite) TestOpenDatabaseOK(c *C) {
    54  	cfg := &asserts.DatabaseConfig{
    55  		Backstore: asserts.NewMemoryBackstore(),
    56  	}
    57  	db, err := asserts.OpenDatabase(cfg)
    58  	c.Assert(err, IsNil)
    59  	c.Assert(db, NotNil)
    60  }
    61  
    62  func (opens *openSuite) TestOpenDatabaseTrustedAccount(c *C) {
    63  	headers := map[string]interface{}{
    64  		"authority-id": "canonical",
    65  		"account-id":   "trusted",
    66  		"display-name": "Trusted",
    67  		"validation":   "verified",
    68  		"timestamp":    "2015-01-01T14:00:00Z",
    69  	}
    70  	acct, err := asserts.AssembleAndSignInTest(asserts.AccountType, headers, nil, testPrivKey0)
    71  	c.Assert(err, IsNil)
    72  
    73  	cfg := &asserts.DatabaseConfig{
    74  		Backstore: asserts.NewMemoryBackstore(),
    75  		Trusted:   []asserts.Assertion{acct},
    76  	}
    77  
    78  	db, err := asserts.OpenDatabase(cfg)
    79  	c.Assert(err, IsNil)
    80  
    81  	a, err := db.Find(asserts.AccountType, map[string]string{
    82  		"account-id": "trusted",
    83  	})
    84  	c.Assert(err, IsNil)
    85  	acct1 := a.(*asserts.Account)
    86  	c.Check(acct1.AccountID(), Equals, "trusted")
    87  	c.Check(acct1.DisplayName(), Equals, "Trusted")
    88  
    89  	c.Check(db.IsTrustedAccount("trusted"), Equals, true)
    90  
    91  	// empty account id (invalid) is not trusted
    92  	c.Check(db.IsTrustedAccount(""), Equals, false)
    93  }
    94  
    95  func (opens *openSuite) TestOpenDatabaseTrustedWrongType(c *C) {
    96  	headers := map[string]interface{}{
    97  		"authority-id": "canonical",
    98  		"primary-key":  "0",
    99  	}
   100  	a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
   101  	c.Assert(err, IsNil)
   102  
   103  	cfg := &asserts.DatabaseConfig{
   104  		Trusted: []asserts.Assertion{a},
   105  	}
   106  
   107  	_, err = asserts.OpenDatabase(cfg)
   108  	c.Assert(err, ErrorMatches, "cannot predefine trusted assertions that are not account-key or account: test-only")
   109  }
   110  
   111  type databaseSuite struct {
   112  	topDir string
   113  	db     *asserts.Database
   114  }
   115  
   116  var _ = Suite(&databaseSuite{})
   117  
   118  func (dbs *databaseSuite) SetUpTest(c *C) {
   119  	dbs.topDir = filepath.Join(c.MkDir(), "asserts-db")
   120  	fsKeypairMgr, err := asserts.OpenFSKeypairManager(dbs.topDir)
   121  	c.Assert(err, IsNil)
   122  	cfg := &asserts.DatabaseConfig{
   123  		KeypairManager: fsKeypairMgr,
   124  	}
   125  	db, err := asserts.OpenDatabase(cfg)
   126  	c.Assert(err, IsNil)
   127  	dbs.db = db
   128  }
   129  
   130  func (dbs *databaseSuite) TestImportKey(c *C) {
   131  	err := dbs.db.ImportKey(testPrivKey1)
   132  	c.Assert(err, IsNil)
   133  
   134  	keyPath := filepath.Join(dbs.topDir, "private-keys-v1", testPrivKey1SHA3_384)
   135  	info, err := os.Stat(keyPath)
   136  	c.Assert(err, IsNil)
   137  	c.Check(info.Mode().Perm(), Equals, os.FileMode(0600)) // secret
   138  	// too much "clear box" testing? ok at least until we have
   139  	// more functionality
   140  	privKey, err := ioutil.ReadFile(keyPath)
   141  	c.Assert(err, IsNil)
   142  
   143  	privKeyFromDisk, err := asserts.DecodePrivateKeyInTest(privKey)
   144  	c.Assert(err, IsNil)
   145  
   146  	c.Check(privKeyFromDisk.PublicKey().ID(), Equals, testPrivKey1SHA3_384)
   147  }
   148  
   149  func (dbs *databaseSuite) TestImportKeyAlreadyExists(c *C) {
   150  	err := dbs.db.ImportKey(testPrivKey1)
   151  	c.Assert(err, IsNil)
   152  
   153  	err = dbs.db.ImportKey(testPrivKey1)
   154  	c.Check(err, ErrorMatches, "key pair with given key id already exists")
   155  }
   156  
   157  func (dbs *databaseSuite) TestPublicKey(c *C) {
   158  	pk := testPrivKey1
   159  	keyID := pk.PublicKey().ID()
   160  	err := dbs.db.ImportKey(pk)
   161  	c.Assert(err, IsNil)
   162  
   163  	pubk, err := dbs.db.PublicKey(keyID)
   164  	c.Assert(err, IsNil)
   165  	c.Check(pubk.ID(), Equals, keyID)
   166  
   167  	// usual pattern is to then encode it
   168  	encoded, err := asserts.EncodePublicKey(pubk)
   169  	c.Assert(err, IsNil)
   170  	data, err := base64.StdEncoding.DecodeString(string(encoded))
   171  	c.Assert(err, IsNil)
   172  	c.Check(data[0], Equals, uint8(1)) // v1
   173  
   174  	// check details of packet
   175  	const newHeaderBits = 0x80 | 0x40
   176  	c.Check(data[1]&newHeaderBits, Equals, uint8(newHeaderBits))
   177  	c.Check(data[2] < 192, Equals, true) // small packet, 1 byte length
   178  	c.Check(data[3], Equals, uint8(4))   // openpgp v4
   179  	pkt, err := packet.Read(bytes.NewBuffer(data[1:]))
   180  	c.Assert(err, IsNil)
   181  	pubKey, ok := pkt.(*packet.PublicKey)
   182  	c.Assert(ok, Equals, true)
   183  	c.Check(pubKey.PubKeyAlgo, Equals, packet.PubKeyAlgoRSA)
   184  	c.Check(pubKey.IsSubkey, Equals, false)
   185  	fixedTimestamp := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC)
   186  	c.Check(pubKey.CreationTime.Equal(fixedTimestamp), Equals, true)
   187  	// hash of blob content == hash of key
   188  	h384 := sha3.Sum384(data)
   189  	encHash := base64.RawURLEncoding.EncodeToString(h384[:])
   190  	c.Check(encHash, DeepEquals, testPrivKey1SHA3_384)
   191  }
   192  
   193  func (dbs *databaseSuite) TestPublicKeyNotFound(c *C) {
   194  	pk := testPrivKey1
   195  	keyID := pk.PublicKey().ID()
   196  
   197  	_, err := dbs.db.PublicKey(keyID)
   198  	c.Check(err, ErrorMatches, "cannot find key pair")
   199  
   200  	err = dbs.db.ImportKey(pk)
   201  	c.Assert(err, IsNil)
   202  
   203  	_, err = dbs.db.PublicKey("ff" + keyID)
   204  	c.Check(err, ErrorMatches, "cannot find key pair")
   205  }
   206  
   207  func (dbs *databaseSuite) TestNotFoundErrorIs(c *C) {
   208  	this := &asserts.NotFoundError{
   209  		Headers: map[string]string{"a": "a"},
   210  		Type:    asserts.ValidationSetType,
   211  	}
   212  	that := &asserts.NotFoundError{
   213  		Headers: map[string]string{"b": "b"},
   214  		Type:    asserts.RepairType,
   215  	}
   216  	c.Check(this, testutil.ErrorIs, that)
   217  }
   218  
   219  type checkSuite struct {
   220  	bs asserts.Backstore
   221  	a  asserts.Assertion
   222  }
   223  
   224  var _ = Suite(&checkSuite{})
   225  
   226  func (chks *checkSuite) SetUpTest(c *C) {
   227  	var err error
   228  
   229  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   230  	chks.bs, err = asserts.OpenFSBackstore(topDir)
   231  	c.Assert(err, IsNil)
   232  
   233  	headers := map[string]interface{}{
   234  		"authority-id": "canonical",
   235  		"primary-key":  "0",
   236  	}
   237  	chks.a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
   238  	c.Assert(err, IsNil)
   239  }
   240  
   241  func (chks *checkSuite) TestCheckNoPubKey(c *C) {
   242  	cfg := &asserts.DatabaseConfig{
   243  		Backstore: chks.bs,
   244  	}
   245  	db, err := asserts.OpenDatabase(cfg)
   246  	c.Assert(err, IsNil)
   247  
   248  	err = db.Check(chks.a)
   249  	c.Assert(err, ErrorMatches, `no matching public key "[[:alnum:]_-]+" for signature by "canonical"`)
   250  }
   251  
   252  func (chks *checkSuite) TestCheckExpiredPubKey(c *C) {
   253  	fixedTimeStr := "0003-01-01T00:00:00Z"
   254  	fixedTime, err := time.Parse(time.RFC3339, fixedTimeStr)
   255  	c.Assert(err, IsNil)
   256  
   257  	restore := asserts.MockTimeNow(fixedTime)
   258  	defer restore()
   259  
   260  	trustedKey := testPrivKey0
   261  
   262  	expiredAccKey := asserts.ExpiredAccountKeyForTest("canonical", trustedKey.PublicKey())
   263  	cfg := &asserts.DatabaseConfig{
   264  		Backstore: chks.bs,
   265  		Trusted:   []asserts.Assertion{expiredAccKey},
   266  	}
   267  	db, err := asserts.OpenDatabase(cfg)
   268  	c.Assert(err, IsNil)
   269  
   270  	expSince := regexp.QuoteMeta(expiredAccKey.Since().Format(time.RFC3339))
   271  	expUntil := regexp.QuoteMeta(expiredAccKey.Until().Format(time.RFC3339))
   272  	curTime := regexp.QuoteMeta(fixedTimeStr)
   273  	err = db.Check(chks.a)
   274  	c.Assert(err, ErrorMatches, fmt.Sprintf(`assertion is signed with expired public key "[[:alnum:]_-]+" from "canonical": current time is %s but key is valid during \[%s, %s\)`, curTime, expSince, expUntil))
   275  }
   276  
   277  func (chks *checkSuite) TestCheckExpiredPubKeyNoUntil(c *C) {
   278  	curTimeStr := "0002-01-01T00:00:00Z"
   279  	curTime, err := time.Parse(time.RFC3339, curTimeStr)
   280  	c.Assert(err, IsNil)
   281  
   282  	restore := asserts.MockTimeNow(curTime)
   283  	defer restore()
   284  
   285  	trustedKey := testPrivKey0
   286  
   287  	keyTimeStr := "0003-01-01T00:00:00Z"
   288  	keyTime, err := time.Parse(time.RFC3339, keyTimeStr)
   289  	c.Assert(err, IsNil)
   290  	expiredAccKey := asserts.MakeAccountKeyForTestWithUntil("canonical", trustedKey.PublicKey(), keyTime, time.Time{}, 1)
   291  	cfg := &asserts.DatabaseConfig{
   292  		Backstore: chks.bs,
   293  		Trusted:   []asserts.Assertion{expiredAccKey},
   294  	}
   295  
   296  	db, err := asserts.OpenDatabase(cfg)
   297  	c.Assert(err, IsNil)
   298  
   299  	err = db.Check(chks.a)
   300  	c.Assert(err, ErrorMatches, fmt.Sprintf(`assertion is signed with expired public key "[[:alnum:]_-]+" from "canonical": current time is %s but key is valid from %s`, regexp.QuoteMeta(curTimeStr), regexp.QuoteMeta(keyTimeStr)))
   301  }
   302  
   303  func (chks *checkSuite) TestCheckForgery(c *C) {
   304  	trustedKey := testPrivKey0
   305  
   306  	cfg := &asserts.DatabaseConfig{
   307  		Backstore: chks.bs,
   308  		Trusted:   []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
   309  	}
   310  	db, err := asserts.OpenDatabase(cfg)
   311  	c.Assert(err, IsNil)
   312  
   313  	encoded := asserts.Encode(chks.a)
   314  	content, encodedSig := chks.a.Signature()
   315  	// forgery
   316  	forgedSig := new(packet.Signature)
   317  	forgedSig.PubKeyAlgo = packet.PubKeyAlgoRSA
   318  	forgedSig.Hash = crypto.SHA512
   319  	forgedSig.CreationTime = time.Now()
   320  	h := crypto.SHA512.New()
   321  	h.Write(content)
   322  	pk1 := packet.NewRSAPrivateKey(time.Unix(1, 0), testPrivKey1RSA)
   323  	err = forgedSig.Sign(h, pk1, &packet.Config{DefaultHash: crypto.SHA512})
   324  	c.Assert(err, IsNil)
   325  	buf := new(bytes.Buffer)
   326  	forgedSig.Serialize(buf)
   327  	b := append([]byte{0x1}, buf.Bytes()...)
   328  	forgedSigEncoded := base64.StdEncoding.EncodeToString(b)
   329  	forgedEncoded := bytes.Replace(encoded, encodedSig, []byte(forgedSigEncoded), 1)
   330  	c.Assert(forgedEncoded, Not(DeepEquals), encoded)
   331  
   332  	forgedAssert, err := asserts.Decode(forgedEncoded)
   333  	c.Assert(err, IsNil)
   334  
   335  	err = db.Check(forgedAssert)
   336  	c.Assert(err, ErrorMatches, "failed signature verification: .*")
   337  }
   338  
   339  func (chks *checkSuite) TestCheckUnsupportedFormat(c *C) {
   340  	trustedKey := testPrivKey0
   341  
   342  	cfg := &asserts.DatabaseConfig{
   343  		Backstore: chks.bs,
   344  		Trusted:   []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
   345  	}
   346  	db, err := asserts.OpenDatabase(cfg)
   347  	c.Assert(err, IsNil)
   348  
   349  	var a asserts.Assertion
   350  	(func() {
   351  		restore := asserts.MockMaxSupportedFormat(asserts.TestOnlyType, 77)
   352  		defer restore()
   353  		var err error
   354  
   355  		headers := map[string]interface{}{
   356  			"authority-id": "canonical",
   357  			"primary-key":  "0",
   358  			"format":       "77",
   359  		}
   360  		a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
   361  		c.Assert(err, IsNil)
   362  	})()
   363  
   364  	err = db.Check(a)
   365  	c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
   366  	c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported`)
   367  }
   368  
   369  func (chks *checkSuite) TestCheckMismatchedAccountIDandKey(c *C) {
   370  	trustedKey := testPrivKey0
   371  
   372  	cfg := &asserts.DatabaseConfig{
   373  		Backstore: chks.bs,
   374  		Trusted:   []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
   375  	}
   376  	db, err := asserts.OpenDatabase(cfg)
   377  	c.Assert(err, IsNil)
   378  
   379  	headers := map[string]interface{}{
   380  		"authority-id": "random",
   381  		"primary-key":  "0",
   382  	}
   383  	a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
   384  	c.Assert(err, IsNil)
   385  
   386  	err = db.Check(a)
   387  	c.Check(err, ErrorMatches, `error finding matching public key for signature: found public key ".*" from "canonical" but expected it from: random`)
   388  
   389  	err = asserts.CheckSignature(a, cfg.Trusted[0].(*asserts.AccountKey), db, time.Time{}, time.Time{})
   390  	c.Check(err, ErrorMatches, `assertion authority "random" does not match public key from "canonical"`)
   391  }
   392  
   393  func (chks *checkSuite) TestCheckAndSetEarliestTime(c *C) {
   394  	trustedKey := testPrivKey0
   395  
   396  	ak := asserts.MakeAccountKeyForTest("canonical", trustedKey.PublicKey(), time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC), 2)
   397  
   398  	cfg := &asserts.DatabaseConfig{
   399  		Backstore: chks.bs,
   400  		Trusted:   []asserts.Assertion{ak},
   401  	}
   402  	db, err := asserts.OpenDatabase(cfg)
   403  	c.Assert(err, IsNil)
   404  
   405  	headers := map[string]interface{}{
   406  		"authority-id": "canonical",
   407  		"primary-key":  "0",
   408  	}
   409  	a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
   410  	c.Assert(err, IsNil)
   411  
   412  	// now is since + 1 year, key is valid
   413  	r := asserts.MockTimeNow(ak.Since().AddDate(1, 0, 0))
   414  	defer r()
   415  
   416  	err = db.Check(a)
   417  	c.Check(err, IsNil)
   418  
   419  	// now is since - 1 year, key is invalid
   420  	pastTime := ak.Since().AddDate(-1, 0, 0)
   421  	asserts.MockTimeNow(pastTime)
   422  
   423  	err = db.Check(a)
   424  	c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
   425  
   426  	// now is ignored but known to be at least >= pastTime
   427  	// key is considered valid
   428  	db.SetEarliestTime(pastTime)
   429  	err = db.Check(a)
   430  	c.Check(err, IsNil)
   431  
   432  	// move earliest after until
   433  	db.SetEarliestTime(ak.Until().AddDate(0, 0, 1))
   434  	err = db.Check(a)
   435  	c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
   436  
   437  	// check using now = since - 1 year again
   438  	db.SetEarliestTime(time.Time{})
   439  	err = db.Check(a)
   440  	c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
   441  
   442  	// now is since + 1 month, key is valid
   443  	asserts.MockTimeNow(ak.Since().AddDate(0, 1, 0))
   444  	err = db.Check(a)
   445  	c.Check(err, IsNil)
   446  }
   447  
   448  type signAddFindSuite struct {
   449  	signingDB    *asserts.Database
   450  	signingKeyID string
   451  	db           *asserts.Database
   452  }
   453  
   454  var _ = Suite(&signAddFindSuite{})
   455  
   456  func (safs *signAddFindSuite) SetUpTest(c *C) {
   457  	cfg0 := &asserts.DatabaseConfig{}
   458  	db0, err := asserts.OpenDatabase(cfg0)
   459  	c.Assert(err, IsNil)
   460  	safs.signingDB = db0
   461  
   462  	pk := testPrivKey0
   463  	err = db0.ImportKey(pk)
   464  	c.Assert(err, IsNil)
   465  	safs.signingKeyID = pk.PublicKey().ID()
   466  
   467  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   468  	bs, err := asserts.OpenFSBackstore(topDir)
   469  	c.Assert(err, IsNil)
   470  
   471  	headers := map[string]interface{}{
   472  		"type":         "account",
   473  		"authority-id": "canonical",
   474  		"account-id":   "predefined",
   475  		"validation":   "verified",
   476  		"display-name": "Predef",
   477  		"timestamp":    time.Now().Format(time.RFC3339),
   478  	}
   479  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
   480  	c.Assert(err, IsNil)
   481  
   482  	trustedKey := testPrivKey0
   483  	cfg := &asserts.DatabaseConfig{
   484  		Backstore: bs,
   485  		Trusted: []asserts.Assertion{
   486  			asserts.BootstrapAccountForTest("canonical"),
   487  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey()),
   488  		},
   489  		OtherPredefined: []asserts.Assertion{
   490  			predefAcct,
   491  		},
   492  	}
   493  	db, err := asserts.OpenDatabase(cfg)
   494  	c.Assert(err, IsNil)
   495  	safs.db = db
   496  }
   497  
   498  func (safs *signAddFindSuite) TestSign(c *C) {
   499  	headers := map[string]interface{}{
   500  		"authority-id": "canonical",
   501  		"primary-key":  "a",
   502  	}
   503  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   504  	c.Assert(err, IsNil)
   505  
   506  	err = safs.db.Check(a1)
   507  	c.Check(err, IsNil)
   508  }
   509  
   510  func (safs *signAddFindSuite) TestSignEmptyKeyID(c *C) {
   511  	headers := map[string]interface{}{
   512  		"authority-id": "canonical",
   513  		"primary-key":  "a",
   514  	}
   515  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "")
   516  	c.Assert(err, ErrorMatches, "key id is empty")
   517  	c.Check(a1, IsNil)
   518  }
   519  
   520  func (safs *signAddFindSuite) TestSignMissingAuthorityId(c *C) {
   521  	headers := map[string]interface{}{
   522  		"primary-key": "a",
   523  	}
   524  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   525  	c.Assert(err, ErrorMatches, `"authority-id" header is mandatory`)
   526  	c.Check(a1, IsNil)
   527  }
   528  
   529  func (safs *signAddFindSuite) TestSignMissingPrimaryKey(c *C) {
   530  	headers := map[string]interface{}{
   531  		"authority-id": "canonical",
   532  	}
   533  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   534  	c.Assert(err, ErrorMatches, `"primary-key" header is mandatory`)
   535  	c.Check(a1, IsNil)
   536  }
   537  
   538  func (safs *signAddFindSuite) TestSignPrimaryKeyWithSlash(c *C) {
   539  	headers := map[string]interface{}{
   540  		"authority-id": "canonical",
   541  		"primary-key":  "baz/9000",
   542  	}
   543  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   544  	c.Assert(err, ErrorMatches, `"primary-key" primary key header cannot contain '/'`)
   545  	c.Check(a1, IsNil)
   546  }
   547  
   548  func (safs *signAddFindSuite) TestSignNoPrivateKey(c *C) {
   549  	headers := map[string]interface{}{
   550  		"authority-id": "canonical",
   551  		"primary-key":  "a",
   552  	}
   553  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "abcd")
   554  	c.Assert(err, ErrorMatches, "cannot find key pair")
   555  	c.Check(a1, IsNil)
   556  }
   557  
   558  func (safs *signAddFindSuite) TestSignUnknownType(c *C) {
   559  	headers := map[string]interface{}{
   560  		"authority-id": "canonical",
   561  	}
   562  	a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "xyz", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
   563  	c.Assert(err, ErrorMatches, `internal error: unknown assertion type: "xyz"`)
   564  	c.Check(a1, IsNil)
   565  }
   566  
   567  func (safs *signAddFindSuite) TestSignNonPredefinedType(c *C) {
   568  	headers := map[string]interface{}{
   569  		"authority-id": "canonical",
   570  	}
   571  	a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "test-only", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
   572  	c.Assert(err, ErrorMatches, `internal error: unpredefined assertion type for name "test-only" used.*`)
   573  	c.Check(a1, IsNil)
   574  }
   575  
   576  func (safs *signAddFindSuite) TestSignBadRevision(c *C) {
   577  	headers := map[string]interface{}{
   578  		"authority-id": "canonical",
   579  		"primary-key":  "a",
   580  		"revision":     "zzz",
   581  	}
   582  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   583  	c.Assert(err, ErrorMatches, `"revision" header is not an integer: zzz`)
   584  	c.Check(a1, IsNil)
   585  }
   586  
   587  func (safs *signAddFindSuite) TestSignBadFormat(c *C) {
   588  	headers := map[string]interface{}{
   589  		"authority-id": "canonical",
   590  		"primary-key":  "a",
   591  		"format":       "zzz",
   592  	}
   593  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   594  	c.Assert(err, ErrorMatches, `"format" header is not an integer: zzz`)
   595  	c.Check(a1, IsNil)
   596  }
   597  
   598  func (safs *signAddFindSuite) TestSignHeadersCheck(c *C) {
   599  	headers := map[string]interface{}{
   600  		"authority-id": "canonical",
   601  		"primary-key":  "a",
   602  		"extra":        []interface{}{1, 2},
   603  	}
   604  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   605  	c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
   606  	c.Check(a1, IsNil)
   607  }
   608  
   609  func (safs *signAddFindSuite) TestSignHeadersCheckMap(c *C) {
   610  	headers := map[string]interface{}{
   611  		"authority-id": "canonical",
   612  		"primary-key":  "a",
   613  		"extra":        map[string]interface{}{"a": "a", "b": 1},
   614  	}
   615  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   616  	c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
   617  	c.Check(a1, IsNil)
   618  }
   619  
   620  func (safs *signAddFindSuite) TestSignAssemblerError(c *C) {
   621  	headers := map[string]interface{}{
   622  		"authority-id": "canonical",
   623  		"primary-key":  "a",
   624  		"count":        "zzz",
   625  	}
   626  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   627  	c.Assert(err, ErrorMatches, `cannot assemble assertion test-only: "count" header is not an integer: zzz`)
   628  	c.Check(a1, IsNil)
   629  }
   630  
   631  func (safs *signAddFindSuite) TestSignUnsupportedFormat(c *C) {
   632  	headers := map[string]interface{}{
   633  		"authority-id": "canonical",
   634  		"primary-key":  "a",
   635  		"format":       "77",
   636  	}
   637  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   638  	c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format 77 higher than max supported format 1`)
   639  	c.Check(a1, IsNil)
   640  }
   641  
   642  func (safs *signAddFindSuite) TestSignInadequateFormat(c *C) {
   643  	headers := map[string]interface{}{
   644  		"authority-id":     "canonical",
   645  		"primary-key":      "a",
   646  		"format-1-feature": "true",
   647  	}
   648  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   649  	c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format set to 0 lower than min format 1 covering included features`)
   650  	c.Check(a1, IsNil)
   651  }
   652  
   653  func (safs *signAddFindSuite) TestAddRefusesSelfSignedKey(c *C) {
   654  	aKey := testPrivKey2
   655  
   656  	aKeyEncoded, err := asserts.EncodePublicKey(aKey.PublicKey())
   657  	c.Assert(err, IsNil)
   658  
   659  	now := time.Now().UTC()
   660  	headers := map[string]interface{}{
   661  		"authority-id":        "canonical",
   662  		"account-id":          "canonical",
   663  		"public-key-sha3-384": aKey.PublicKey().ID(),
   664  		"name":                "default",
   665  		"since":               now.Format(time.RFC3339),
   666  	}
   667  	acctKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, aKeyEncoded, aKey)
   668  	c.Assert(err, IsNil)
   669  
   670  	// this must fail
   671  	err = safs.db.Add(acctKey)
   672  	c.Check(err, ErrorMatches, `no matching public key.*`)
   673  }
   674  
   675  func (safs *signAddFindSuite) TestAddSuperseding(c *C) {
   676  	headers := map[string]interface{}{
   677  		"authority-id": "canonical",
   678  		"primary-key":  "a",
   679  	}
   680  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   681  	c.Assert(err, IsNil)
   682  
   683  	err = safs.db.Add(a1)
   684  	c.Assert(err, IsNil)
   685  
   686  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
   687  		"primary-key": "a",
   688  	})
   689  	c.Assert(err, IsNil)
   690  	c.Check(retrieved1, NotNil)
   691  	c.Check(retrieved1.Revision(), Equals, 0)
   692  
   693  	headers["revision"] = "1"
   694  	a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   695  	c.Assert(err, IsNil)
   696  
   697  	err = safs.db.Add(a2)
   698  	c.Assert(err, IsNil)
   699  
   700  	retrieved2, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
   701  		"primary-key": "a",
   702  	})
   703  	c.Assert(err, IsNil)
   704  	c.Check(retrieved2, NotNil)
   705  	c.Check(retrieved2.Revision(), Equals, 1)
   706  
   707  	err = safs.db.Add(a1)
   708  	c.Check(err, ErrorMatches, "revision 0 is older than current revision 1")
   709  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
   710  }
   711  
   712  func (safs *signAddFindSuite) TestAddNoAuthorityNoPrimaryKey(c *C) {
   713  	headers := map[string]interface{}{
   714  		"hdr": "FOO",
   715  	}
   716  	a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityType, headers, nil, testPrivKey0)
   717  	c.Assert(err, IsNil)
   718  
   719  	err = safs.db.Add(a)
   720  	c.Assert(err, ErrorMatches, `internal error: assertion type "test-only-no-authority" has no primary key`)
   721  }
   722  
   723  func (safs *signAddFindSuite) TestAddNoAuthorityButPrimaryKey(c *C) {
   724  	headers := map[string]interface{}{
   725  		"pk": "primary",
   726  	}
   727  	a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityPKType, headers, nil, testPrivKey0)
   728  	c.Assert(err, IsNil)
   729  
   730  	err = safs.db.Add(a)
   731  	c.Assert(err, ErrorMatches, `cannot check no-authority assertion type "test-only-no-authority-pk"`)
   732  }
   733  
   734  func (safs *signAddFindSuite) TestAddUnsupportedFormat(c *C) {
   735  	const unsupported = "type: test-only\n" +
   736  		"format: 77\n" +
   737  		"authority-id: canonical\n" +
   738  		"primary-key: a\n" +
   739  		"payload: unsupported\n" +
   740  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   741  		"\n\n" +
   742  		"AXNpZw=="
   743  	aUnsupp, err := asserts.Decode([]byte(unsupported))
   744  	c.Assert(err, IsNil)
   745  	c.Assert(aUnsupp.SupportedFormat(), Equals, false)
   746  
   747  	err = safs.db.Add(aUnsupp)
   748  	c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
   749  	c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, false)
   750  	c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported`)
   751  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, false)
   752  
   753  	headers := map[string]interface{}{
   754  		"authority-id": "canonical",
   755  		"primary-key":  "a",
   756  		"format":       "1",
   757  		"payload":      "supported",
   758  	}
   759  	aSupp, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
   760  	c.Assert(err, IsNil)
   761  
   762  	err = safs.db.Add(aSupp)
   763  	c.Assert(err, IsNil)
   764  
   765  	err = safs.db.Add(aUnsupp)
   766  	c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
   767  	c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, true)
   768  	c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported \(current not updated\)`)
   769  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
   770  }
   771  
   772  func (safs *signAddFindSuite) TestNotFoundError(c *C) {
   773  	err1 := &asserts.NotFoundError{
   774  		Type: asserts.SnapDeclarationType,
   775  		Headers: map[string]string{
   776  			"series":  "16",
   777  			"snap-id": "snap-id",
   778  		},
   779  	}
   780  	c.Check(asserts.IsNotFound(err1), Equals, true)
   781  	c.Check(err1.Error(), Equals, "snap-declaration (snap-id; series:16) not found")
   782  
   783  	err2 := &asserts.NotFoundError{
   784  		Type: asserts.SnapRevisionType,
   785  	}
   786  	c.Check(asserts.IsNotFound(err1), Equals, true)
   787  	c.Check(err2.Error(), Equals, "snap-revision assertion not found")
   788  }
   789  
   790  func (safs *signAddFindSuite) TestFindNotFound(c *C) {
   791  	headers := map[string]interface{}{
   792  		"authority-id": "canonical",
   793  		"primary-key":  "a",
   794  	}
   795  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   796  	c.Assert(err, IsNil)
   797  
   798  	err = safs.db.Add(a1)
   799  	c.Assert(err, IsNil)
   800  
   801  	hdrs := map[string]string{
   802  		"primary-key": "b",
   803  	}
   804  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, hdrs)
   805  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   806  		Type:    asserts.TestOnlyType,
   807  		Headers: hdrs,
   808  	})
   809  	c.Check(retrieved1, IsNil)
   810  
   811  	// checking also extra headers
   812  	hdrs = map[string]string{
   813  		"primary-key":  "a",
   814  		"authority-id": "other-auth-id",
   815  	}
   816  	retrieved1, err = safs.db.Find(asserts.TestOnlyType, hdrs)
   817  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   818  		Type:    asserts.TestOnlyType,
   819  		Headers: hdrs,
   820  	})
   821  	c.Check(retrieved1, IsNil)
   822  }
   823  
   824  func (safs *signAddFindSuite) TestFindPrimaryLeftOut(c *C) {
   825  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{})
   826  	c.Assert(err, ErrorMatches, "must provide primary key: primary-key")
   827  	c.Check(retrieved1, IsNil)
   828  }
   829  
   830  func (safs *signAddFindSuite) TestFindMany(c *C) {
   831  	headers := map[string]interface{}{
   832  		"authority-id": "canonical",
   833  		"primary-key":  "a",
   834  		"other":        "other-x",
   835  	}
   836  	aa, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   837  	c.Assert(err, IsNil)
   838  	err = safs.db.Add(aa)
   839  	c.Assert(err, IsNil)
   840  
   841  	headers = map[string]interface{}{
   842  		"authority-id": "canonical",
   843  		"primary-key":  "b",
   844  		"other":        "other-y",
   845  	}
   846  	ab, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   847  	c.Assert(err, IsNil)
   848  	err = safs.db.Add(ab)
   849  	c.Assert(err, IsNil)
   850  
   851  	headers = map[string]interface{}{
   852  		"authority-id": "canonical",
   853  		"primary-key":  "c",
   854  		"other":        "other-x",
   855  	}
   856  	ac, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   857  	c.Assert(err, IsNil)
   858  	err = safs.db.Add(ac)
   859  	c.Assert(err, IsNil)
   860  
   861  	res, err := safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   862  		"other": "other-x",
   863  	})
   864  	c.Assert(err, IsNil)
   865  	c.Assert(res, HasLen, 2)
   866  	primKeys := []string{res[0].HeaderString("primary-key"), res[1].HeaderString("primary-key")}
   867  	sort.Strings(primKeys)
   868  	c.Check(primKeys, DeepEquals, []string{"a", "c"})
   869  
   870  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   871  		"other": "other-y",
   872  	})
   873  	c.Assert(err, IsNil)
   874  	c.Assert(res, HasLen, 1)
   875  	c.Check(res[0].Header("primary-key"), Equals, "b")
   876  
   877  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{})
   878  	c.Assert(err, IsNil)
   879  	c.Assert(res, HasLen, 3)
   880  
   881  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   882  		"primary-key": "b",
   883  		"other":       "other-y",
   884  	})
   885  	c.Assert(err, IsNil)
   886  	c.Assert(res, HasLen, 1)
   887  
   888  	hdrs := map[string]string{
   889  		"primary-key": "b",
   890  		"other":       "other-x",
   891  	}
   892  	res, err = safs.db.FindMany(asserts.TestOnlyType, hdrs)
   893  	c.Assert(res, HasLen, 0)
   894  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   895  		Type:    asserts.TestOnlyType,
   896  		Headers: hdrs,
   897  	})
   898  }
   899  
   900  func (safs *signAddFindSuite) TestFindFindsPredefined(c *C) {
   901  	pk1 := testPrivKey1
   902  
   903  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   904  		"authority-id": "canonical",
   905  	}, safs.signingKeyID)
   906  
   907  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   908  		"authority-id": "canonical",
   909  	}, pk1.PublicKey(), safs.signingKeyID)
   910  
   911  	err := safs.db.Add(acct1)
   912  	c.Assert(err, IsNil)
   913  	err = safs.db.Add(acct1Key)
   914  	c.Assert(err, IsNil)
   915  
   916  	// find the trusted key as well
   917  	tKey, err := safs.db.Find(asserts.AccountKeyType, map[string]string{
   918  		"account-id":          "canonical",
   919  		"public-key-sha3-384": safs.signingKeyID,
   920  	})
   921  	c.Assert(err, IsNil)
   922  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
   923  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
   924  
   925  	// find predefined account as well
   926  	predefAcct, err := safs.db.Find(asserts.AccountType, map[string]string{
   927  		"account-id": "predefined",
   928  	})
   929  	c.Assert(err, IsNil)
   930  	c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
   931  	c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
   932  
   933  	// find trusted and indirectly trusted
   934  	accKeys, err := safs.db.FindMany(asserts.AccountKeyType, nil)
   935  	c.Assert(err, IsNil)
   936  	c.Check(accKeys, HasLen, 2)
   937  
   938  	accts, err := safs.db.FindMany(asserts.AccountType, nil)
   939  	c.Assert(err, IsNil)
   940  	c.Check(accts, HasLen, 3)
   941  }
   942  
   943  func (safs *signAddFindSuite) TestFindTrusted(c *C) {
   944  	pk1 := testPrivKey1
   945  
   946  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   947  		"authority-id": "canonical",
   948  	}, safs.signingKeyID)
   949  
   950  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   951  		"authority-id": "canonical",
   952  	}, pk1.PublicKey(), safs.signingKeyID)
   953  
   954  	err := safs.db.Add(acct1)
   955  	c.Assert(err, IsNil)
   956  	err = safs.db.Add(acct1Key)
   957  	c.Assert(err, IsNil)
   958  
   959  	// find the trusted account
   960  	tAcct, err := safs.db.FindTrusted(asserts.AccountType, map[string]string{
   961  		"account-id": "canonical",
   962  	})
   963  	c.Assert(err, IsNil)
   964  	c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
   965  
   966  	// find the trusted key
   967  	tKey, err := safs.db.FindTrusted(asserts.AccountKeyType, map[string]string{
   968  		"account-id":          "canonical",
   969  		"public-key-sha3-384": safs.signingKeyID,
   970  	})
   971  	c.Assert(err, IsNil)
   972  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
   973  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
   974  
   975  	// doesn't find not trusted assertions
   976  	hdrs := map[string]string{
   977  		"account-id": acct1.AccountID(),
   978  	}
   979  	_, err = safs.db.FindTrusted(asserts.AccountType, hdrs)
   980  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   981  		Type:    asserts.AccountType,
   982  		Headers: hdrs,
   983  	})
   984  
   985  	hdrs = map[string]string{
   986  		"account-id":          acct1.AccountID(),
   987  		"public-key-sha3-384": acct1Key.PublicKeyID(),
   988  	}
   989  	_, err = safs.db.FindTrusted(asserts.AccountKeyType, hdrs)
   990  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   991  		Type:    asserts.AccountKeyType,
   992  		Headers: hdrs,
   993  	})
   994  
   995  	_, err = safs.db.FindTrusted(asserts.AccountType, map[string]string{
   996  		"account-id": "predefined",
   997  	})
   998  	c.Check(asserts.IsNotFound(err), Equals, true)
   999  }
  1000  
  1001  func (safs *signAddFindSuite) TestFindPredefined(c *C) {
  1002  	pk1 := testPrivKey1
  1003  
  1004  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
  1005  		"authority-id": "canonical",
  1006  	}, safs.signingKeyID)
  1007  
  1008  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
  1009  		"authority-id": "canonical",
  1010  	}, pk1.PublicKey(), safs.signingKeyID)
  1011  
  1012  	err := safs.db.Add(acct1)
  1013  	c.Assert(err, IsNil)
  1014  	err = safs.db.Add(acct1Key)
  1015  	c.Assert(err, IsNil)
  1016  
  1017  	// find the trusted account
  1018  	tAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
  1019  		"account-id": "canonical",
  1020  	})
  1021  	c.Assert(err, IsNil)
  1022  	c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
  1023  
  1024  	// find the trusted key
  1025  	tKey, err := safs.db.FindPredefined(asserts.AccountKeyType, map[string]string{
  1026  		"account-id":          "canonical",
  1027  		"public-key-sha3-384": safs.signingKeyID,
  1028  	})
  1029  	c.Assert(err, IsNil)
  1030  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
  1031  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
  1032  
  1033  	// find predefined account as well
  1034  	predefAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
  1035  		"account-id": "predefined",
  1036  	})
  1037  	c.Assert(err, IsNil)
  1038  	c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
  1039  	c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
  1040  
  1041  	// doesn't find not trusted or predefined assertions
  1042  	hdrs := map[string]string{
  1043  		"account-id": acct1.AccountID(),
  1044  	}
  1045  	_, err = safs.db.FindPredefined(asserts.AccountType, hdrs)
  1046  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1047  		Type:    asserts.AccountType,
  1048  		Headers: hdrs,
  1049  	})
  1050  
  1051  	hdrs = map[string]string{
  1052  		"account-id":          acct1.AccountID(),
  1053  		"public-key-sha3-384": acct1Key.PublicKeyID(),
  1054  	}
  1055  	_, err = safs.db.FindPredefined(asserts.AccountKeyType, hdrs)
  1056  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1057  		Type:    asserts.AccountKeyType,
  1058  		Headers: hdrs,
  1059  	})
  1060  }
  1061  
  1062  func (safs *signAddFindSuite) TestFindManyPredefined(c *C) {
  1063  	headers := map[string]interface{}{
  1064  		"type":         "account",
  1065  		"authority-id": "canonical",
  1066  		"account-id":   "predefined",
  1067  		"validation":   "verified",
  1068  		"display-name": "Predef",
  1069  		"timestamp":    time.Now().Format(time.RFC3339),
  1070  	}
  1071  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
  1072  	c.Assert(err, IsNil)
  1073  
  1074  	trustedKey0 := testPrivKey0
  1075  	trustedKey1 := testPrivKey1
  1076  	cfg := &asserts.DatabaseConfig{
  1077  		Backstore: asserts.NewMemoryBackstore(),
  1078  		Trusted: []asserts.Assertion{
  1079  			asserts.BootstrapAccountForTest("canonical"),
  1080  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey0.PublicKey()),
  1081  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey1.PublicKey()),
  1082  		},
  1083  		OtherPredefined: []asserts.Assertion{
  1084  			predefAcct,
  1085  		},
  1086  	}
  1087  	db, err := asserts.OpenDatabase(cfg)
  1088  	c.Assert(err, IsNil)
  1089  
  1090  	pk1 := testPrivKey2
  1091  
  1092  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
  1093  		"authority-id": "canonical",
  1094  	}, safs.signingKeyID)
  1095  
  1096  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
  1097  		"authority-id": "canonical",
  1098  	}, pk1.PublicKey(), safs.signingKeyID)
  1099  
  1100  	err = db.Add(acct1)
  1101  	c.Assert(err, IsNil)
  1102  	err = db.Add(acct1Key)
  1103  	c.Assert(err, IsNil)
  1104  
  1105  	// find the trusted account
  1106  	tAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
  1107  		"account-id": "canonical",
  1108  	})
  1109  	c.Assert(err, IsNil)
  1110  	c.Assert(tAccts, HasLen, 1)
  1111  	c.Assert(tAccts[0].(*asserts.Account).AccountID(), Equals, "canonical")
  1112  
  1113  	// find the predefined account
  1114  	pAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
  1115  		"account-id": "predefined",
  1116  	})
  1117  	c.Assert(err, IsNil)
  1118  	c.Assert(pAccts, HasLen, 1)
  1119  	c.Assert(pAccts[0].(*asserts.Account).AccountID(), Equals, "predefined")
  1120  
  1121  	// find the multiple trusted keys
  1122  	tKeys, err := db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
  1123  		"account-id": "canonical",
  1124  	})
  1125  	c.Assert(err, IsNil)
  1126  	c.Assert(tKeys, HasLen, 2)
  1127  	got := make(map[string]string)
  1128  	for _, a := range tKeys {
  1129  		acctKey := a.(*asserts.AccountKey)
  1130  		got[acctKey.PublicKeyID()] = acctKey.AccountID()
  1131  	}
  1132  	c.Check(got, DeepEquals, map[string]string{
  1133  		trustedKey0.PublicKey().ID(): "canonical",
  1134  		trustedKey1.PublicKey().ID(): "canonical",
  1135  	})
  1136  
  1137  	// doesn't find not predefined assertions
  1138  	hdrs := map[string]string{
  1139  		"account-id": acct1.AccountID(),
  1140  	}
  1141  	_, err = db.FindManyPredefined(asserts.AccountType, hdrs)
  1142  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1143  		Type:    asserts.AccountType,
  1144  		Headers: hdrs,
  1145  	})
  1146  
  1147  	_, err = db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
  1148  		"account-id":          acct1.AccountID(),
  1149  		"public-key-sha3-384": acct1Key.PublicKeyID(),
  1150  	})
  1151  	c.Check(asserts.IsNotFound(err), Equals, true)
  1152  }
  1153  
  1154  func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithTrustedOnes(c *C) {
  1155  	// trusted
  1156  	pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
  1157  	c.Assert(err, IsNil)
  1158  	pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
  1159  	c.Assert(err, IsNil)
  1160  
  1161  	now := time.Now().UTC()
  1162  	headers := map[string]interface{}{
  1163  		"authority-id":        "canonical",
  1164  		"account-id":          "canonical",
  1165  		"public-key-sha3-384": safs.signingKeyID,
  1166  		"name":                "default",
  1167  		"since":               now.Format(time.RFC3339),
  1168  		"until":               now.AddDate(1, 0, 0).Format(time.RFC3339),
  1169  	}
  1170  	tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
  1171  	c.Assert(err, IsNil)
  1172  
  1173  	err = safs.db.Add(tKey)
  1174  	c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
  1175  }
  1176  
  1177  func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithPredefinedOnes(c *C) {
  1178  	headers := map[string]interface{}{
  1179  		"type":         "account",
  1180  		"authority-id": "canonical",
  1181  		"account-id":   "predefined",
  1182  		"validation":   "verified",
  1183  		"display-name": "Predef",
  1184  		"timestamp":    time.Now().Format(time.RFC3339),
  1185  	}
  1186  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
  1187  	c.Assert(err, IsNil)
  1188  
  1189  	err = safs.db.Add(predefAcct)
  1190  	c.Check(err, ErrorMatches, `cannot add "account" assertion with primary key clashing with a predefined assertion: .*`)
  1191  }
  1192  
  1193  func (safs *signAddFindSuite) TestFindAndRefResolve(c *C) {
  1194  	headers := map[string]interface{}{
  1195  		"authority-id": "canonical",
  1196  		"pk1":          "ka",
  1197  		"pk2":          "kb",
  1198  	}
  1199  	a1, err := safs.signingDB.Sign(asserts.TestOnly2Type, headers, nil, safs.signingKeyID)
  1200  	c.Assert(err, IsNil)
  1201  
  1202  	err = safs.db.Add(a1)
  1203  	c.Assert(err, IsNil)
  1204  
  1205  	ref := &asserts.Ref{
  1206  		Type:       asserts.TestOnly2Type,
  1207  		PrimaryKey: []string{"ka", "kb"},
  1208  	}
  1209  
  1210  	resolved, err := ref.Resolve(safs.db.Find)
  1211  	c.Assert(err, IsNil)
  1212  	c.Check(resolved.Headers(), DeepEquals, map[string]interface{}{
  1213  		"type":              "test-only-2",
  1214  		"authority-id":      "canonical",
  1215  		"pk1":               "ka",
  1216  		"pk2":               "kb",
  1217  		"sign-key-sha3-384": resolved.SignKeyID(),
  1218  	})
  1219  
  1220  	ref = &asserts.Ref{
  1221  		Type:       asserts.TestOnly2Type,
  1222  		PrimaryKey: []string{"kb", "ka"},
  1223  	}
  1224  	_, err = ref.Resolve(safs.db.Find)
  1225  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
  1226  		Type: ref.Type,
  1227  		Headers: map[string]string{
  1228  			"pk1": "kb",
  1229  			"pk2": "ka",
  1230  		},
  1231  	})
  1232  }
  1233  
  1234  func (safs *signAddFindSuite) TestFindMaxFormat(c *C) {
  1235  	headers := map[string]interface{}{
  1236  		"authority-id": "canonical",
  1237  		"primary-key":  "foo",
  1238  	}
  1239  	af0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1240  	c.Assert(err, IsNil)
  1241  
  1242  	err = safs.db.Add(af0)
  1243  	c.Assert(err, IsNil)
  1244  
  1245  	headers = map[string]interface{}{
  1246  		"authority-id": "canonical",
  1247  		"primary-key":  "foo",
  1248  		"format":       "1",
  1249  		"revision":     "1",
  1250  	}
  1251  	af1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1252  	c.Assert(err, IsNil)
  1253  
  1254  	err = safs.db.Add(af1)
  1255  	c.Assert(err, IsNil)
  1256  
  1257  	a, err := safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1258  		"primary-key": "foo",
  1259  	}, 1)
  1260  	c.Assert(err, IsNil)
  1261  	c.Check(a.Revision(), Equals, 1)
  1262  
  1263  	a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1264  		"primary-key": "foo",
  1265  	}, 0)
  1266  	c.Assert(err, IsNil)
  1267  	c.Check(a.Revision(), Equals, 0)
  1268  
  1269  	a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1270  		"primary-key": "foo",
  1271  	}, 3)
  1272  	c.Check(err, ErrorMatches, `cannot find "test-only" assertions for format 3 higher than supported format 1`)
  1273  	c.Check(a, IsNil)
  1274  }
  1275  
  1276  func (safs *signAddFindSuite) TestFindOptionalPrimaryKeys(c *C) {
  1277  	r := asserts.MockOptionalPrimaryKey(asserts.TestOnlyType, "opt1", "o1-defl")
  1278  	defer r()
  1279  
  1280  	headers := map[string]interface{}{
  1281  		"authority-id": "canonical",
  1282  		"primary-key":  "k1",
  1283  	}
  1284  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1285  	c.Assert(err, IsNil)
  1286  
  1287  	err = safs.db.Add(a1)
  1288  	c.Assert(err, IsNil)
  1289  
  1290  	headers = map[string]interface{}{
  1291  		"authority-id": "canonical",
  1292  		"primary-key":  "k2",
  1293  		"opt1":         "A",
  1294  	}
  1295  	a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1296  	c.Assert(err, IsNil)
  1297  
  1298  	err = safs.db.Add(a2)
  1299  	c.Assert(err, IsNil)
  1300  
  1301  	a, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
  1302  		"primary-key": "k1",
  1303  	})
  1304  	c.Assert(err, IsNil)
  1305  	c.Check(a.HeaderString("primary-key"), Equals, "k1")
  1306  	c.Check(a.HeaderString("opt1"), Equals, "o1-defl")
  1307  
  1308  	a, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1309  		"primary-key": "k1",
  1310  		"opt1":        "o1-defl",
  1311  	})
  1312  	c.Assert(err, IsNil)
  1313  	c.Check(a.HeaderString("primary-key"), Equals, "k1")
  1314  	c.Check(a.HeaderString("opt1"), Equals, "o1-defl")
  1315  
  1316  	a, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1317  		"primary-key": "k2",
  1318  		"opt1":        "A",
  1319  	})
  1320  	c.Assert(err, IsNil)
  1321  	c.Check(a.HeaderString("primary-key"), Equals, "k2")
  1322  	c.Check(a.HeaderString("opt1"), Equals, "A")
  1323  
  1324  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1325  		"primary-key": "k3",
  1326  	})
  1327  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1328  		Type: asserts.TestOnlyType,
  1329  		Headers: map[string]string{
  1330  			"primary-key": "k3",
  1331  		},
  1332  	})
  1333  
  1334  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1335  		"primary-key": "k2",
  1336  	})
  1337  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1338  		Type: asserts.TestOnlyType,
  1339  		Headers: map[string]string{
  1340  			"primary-key": "k2",
  1341  		},
  1342  	})
  1343  
  1344  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1345  		"primary-key": "k2",
  1346  		"opt1":        "B",
  1347  	})
  1348  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1349  		Type: asserts.TestOnlyType,
  1350  		Headers: map[string]string{
  1351  			"primary-key": "k2",
  1352  			"opt1":        "B",
  1353  		},
  1354  	})
  1355  
  1356  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1357  		"primary-key": "k1",
  1358  		"opt1":        "B",
  1359  	})
  1360  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1361  		Type: asserts.TestOnlyType,
  1362  		Headers: map[string]string{
  1363  			"primary-key": "k1",
  1364  			"opt1":        "B",
  1365  		},
  1366  	})
  1367  }
  1368  
  1369  func (safs *signAddFindSuite) TestWithStackedBackstore(c *C) {
  1370  	headers := map[string]interface{}{
  1371  		"authority-id": "canonical",
  1372  		"primary-key":  "one",
  1373  	}
  1374  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1375  	c.Assert(err, IsNil)
  1376  
  1377  	err = safs.db.Add(a1)
  1378  	c.Assert(err, IsNil)
  1379  
  1380  	headers = map[string]interface{}{
  1381  		"authority-id": "canonical",
  1382  		"primary-key":  "two",
  1383  	}
  1384  	a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1385  	c.Assert(err, IsNil)
  1386  
  1387  	bs := asserts.NewMemoryBackstore()
  1388  	stacked := safs.db.WithStackedBackstore(bs)
  1389  
  1390  	err = stacked.Add(a2)
  1391  	c.Assert(err, IsNil)
  1392  
  1393  	_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
  1394  		"primary-key": "one",
  1395  	})
  1396  	c.Check(err, IsNil)
  1397  
  1398  	_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
  1399  		"primary-key": "two",
  1400  	})
  1401  	c.Check(err, IsNil)
  1402  
  1403  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1404  		"primary-key": "two",
  1405  	})
  1406  	c.Check(asserts.IsNotFound(err), Equals, true)
  1407  
  1408  	_, err = stacked.Find(asserts.AccountKeyType, map[string]string{
  1409  		"public-key-sha3-384": safs.signingKeyID,
  1410  	})
  1411  	c.Check(err, IsNil)
  1412  
  1413  	// stored in backstore
  1414  	_, err = bs.Get(asserts.TestOnlyType, []string{"two"}, 0)
  1415  	c.Check(err, IsNil)
  1416  }
  1417  
  1418  func (safs *signAddFindSuite) TestWithStackedBackstoreSafety(c *C) {
  1419  	stacked := safs.db.WithStackedBackstore(asserts.NewMemoryBackstore())
  1420  
  1421  	// usual add safety
  1422  	pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
  1423  	c.Assert(err, IsNil)
  1424  	pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
  1425  	c.Assert(err, IsNil)
  1426  
  1427  	now := time.Now().UTC()
  1428  	headers := map[string]interface{}{
  1429  		"authority-id":        "canonical",
  1430  		"account-id":          "canonical",
  1431  		"public-key-sha3-384": safs.signingKeyID,
  1432  		"name":                "default",
  1433  		"since":               now.Format(time.RFC3339),
  1434  		"until":               now.AddDate(1, 0, 0).Format(time.RFC3339),
  1435  	}
  1436  	tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
  1437  	c.Assert(err, IsNil)
  1438  
  1439  	err = stacked.Add(tKey)
  1440  	c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
  1441  
  1442  	// cannot go back to old revisions
  1443  	headers = map[string]interface{}{
  1444  		"authority-id": "canonical",
  1445  		"primary-key":  "one",
  1446  	}
  1447  	a0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1448  	c.Assert(err, IsNil)
  1449  
  1450  	headers = map[string]interface{}{
  1451  		"authority-id": "canonical",
  1452  		"primary-key":  "one",
  1453  		"revision":     "1",
  1454  	}
  1455  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1456  	c.Assert(err, IsNil)
  1457  
  1458  	err = safs.db.Add(a1)
  1459  	c.Assert(err, IsNil)
  1460  
  1461  	err = stacked.Add(a0)
  1462  	c.Assert(err, DeepEquals, &asserts.RevisionError{
  1463  		Used:    0,
  1464  		Current: 1,
  1465  	})
  1466  }
  1467  
  1468  func (safs *signAddFindSuite) TestFindSequence(c *C) {
  1469  	headers := map[string]interface{}{
  1470  		"authority-id": "canonical",
  1471  		"n":            "s1",
  1472  		"sequence":     "1",
  1473  	}
  1474  	sq1f0, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
  1475  	c.Assert(err, IsNil)
  1476  
  1477  	headers = map[string]interface{}{
  1478  		"authority-id": "canonical",
  1479  		"n":            "s1",
  1480  		"sequence":     "2",
  1481  	}
  1482  	sq2f0, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
  1483  	c.Assert(err, IsNil)
  1484  
  1485  	headers = map[string]interface{}{
  1486  		"authority-id": "canonical",
  1487  		"format":       "1",
  1488  		"n":            "s1",
  1489  		"sequence":     "2",
  1490  		"revision":     "1",
  1491  	}
  1492  	sq2f1, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
  1493  	c.Assert(err, IsNil)
  1494  
  1495  	headers = map[string]interface{}{
  1496  		"authority-id": "canonical",
  1497  		"format":       "1",
  1498  		"n":            "s1",
  1499  		"sequence":     "3",
  1500  	}
  1501  	sq3f1, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
  1502  	c.Assert(err, IsNil)
  1503  
  1504  	headers = map[string]interface{}{
  1505  		"authority-id": "canonical",
  1506  		"format":       "2",
  1507  		"n":            "s1",
  1508  		"sequence":     "3",
  1509  		"revision":     "1",
  1510  	}
  1511  	sq3f2, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
  1512  	c.Assert(err, IsNil)
  1513  
  1514  	for _, a := range []asserts.Assertion{sq1f0, sq2f0, sq2f1, sq3f1} {
  1515  
  1516  		err = safs.db.Add(a)
  1517  		c.Assert(err, IsNil)
  1518  	}
  1519  
  1520  	// stack a backstore, for test completeness, this is an unlikely
  1521  	// scenario atm
  1522  	bs := asserts.NewMemoryBackstore()
  1523  	db := safs.db.WithStackedBackstore(bs)
  1524  	err = db.Add(sq3f2)
  1525  	c.Assert(err, IsNil)
  1526  
  1527  	seqHeaders := map[string]string{
  1528  		"n": "s1",
  1529  	}
  1530  	tests := []struct {
  1531  		after     int
  1532  		maxFormat int
  1533  		sequence  int
  1534  		format    int
  1535  		revision  int
  1536  	}{
  1537  		{after: 0, maxFormat: 0, sequence: 1, format: 0, revision: 0},
  1538  		{after: 0, maxFormat: 2, sequence: 1, format: 0, revision: 0},
  1539  		{after: 1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
  1540  		{after: 1, maxFormat: 1, sequence: 2, format: 1, revision: 1},
  1541  		{after: 1, maxFormat: 2, sequence: 2, format: 1, revision: 1},
  1542  		{after: 2, maxFormat: 0, sequence: -1},
  1543  		{after: 2, maxFormat: 1, sequence: 3, format: 1, revision: 0},
  1544  		{after: 2, maxFormat: 2, sequence: 3, format: 2, revision: 1},
  1545  		{after: 3, maxFormat: 0, sequence: -1},
  1546  		{after: 3, maxFormat: 2, sequence: -1},
  1547  		{after: 4, maxFormat: 2, sequence: -1},
  1548  		{after: -1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
  1549  		{after: -1, maxFormat: 1, sequence: 3, format: 1, revision: 0},
  1550  		{after: -1, maxFormat: 2, sequence: 3, format: 2, revision: 1},
  1551  	}
  1552  
  1553  	for _, t := range tests {
  1554  		a, err := db.FindSequence(asserts.TestOnlySeqType, seqHeaders, t.after, t.maxFormat)
  1555  		if t.sequence == -1 {
  1556  			c.Check(err, DeepEquals, &asserts.NotFoundError{
  1557  				Type:    asserts.TestOnlySeqType,
  1558  				Headers: seqHeaders,
  1559  			})
  1560  		} else {
  1561  			c.Assert(err, IsNil)
  1562  			c.Assert(a.HeaderString("n"), Equals, "s1")
  1563  			c.Check(a.Sequence(), Equals, t.sequence)
  1564  			c.Check(a.Format(), Equals, t.format)
  1565  			c.Check(a.Revision(), Equals, t.revision)
  1566  		}
  1567  	}
  1568  
  1569  	seqHeaders = map[string]string{
  1570  		"n": "s2",
  1571  	}
  1572  	_, err = db.FindSequence(asserts.TestOnlySeqType, seqHeaders, -1, 2)
  1573  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1574  		Type: asserts.TestOnlySeqType, Headers: seqHeaders,
  1575  	})
  1576  
  1577  }
  1578  
  1579  type revisionErrorSuite struct{}
  1580  
  1581  func (res *revisionErrorSuite) TestErrorText(c *C) {
  1582  	tests := []struct {
  1583  		err      error
  1584  		expected string
  1585  	}{
  1586  		// Invalid revisions.
  1587  		{&asserts.RevisionError{Used: -1}, "assertion revision is unknown"},
  1588  		{&asserts.RevisionError{Used: -100}, "assertion revision is unknown"},
  1589  		{&asserts.RevisionError{Current: -1}, "assertion revision is unknown"},
  1590  		{&asserts.RevisionError{Current: -100}, "assertion revision is unknown"},
  1591  		{&asserts.RevisionError{Used: -1, Current: -1}, "assertion revision is unknown"},
  1592  		// Used == Current.
  1593  		{&asserts.RevisionError{}, "revision 0 is already the current revision"},
  1594  		{&asserts.RevisionError{Used: 100, Current: 100}, "revision 100 is already the current revision"},
  1595  		// Used < Current.
  1596  		{&asserts.RevisionError{Used: 1, Current: 2}, "revision 1 is older than current revision 2"},
  1597  		{&asserts.RevisionError{Used: 2, Current: 100}, "revision 2 is older than current revision 100"},
  1598  		// Used > Current.
  1599  		{&asserts.RevisionError{Current: 1, Used: 2}, "revision 2 is more recent than current revision 1"},
  1600  		{&asserts.RevisionError{Current: 2, Used: 100}, "revision 100 is more recent than current revision 2"},
  1601  	}
  1602  
  1603  	for _, test := range tests {
  1604  		c.Check(test.err, ErrorMatches, test.expected)
  1605  	}
  1606  }
  1607  
  1608  type isUnacceptedUpdateSuite struct{}
  1609  
  1610  func (s *isUnacceptedUpdateSuite) TestIsUnacceptedUpdate(c *C) {
  1611  	tests := []struct {
  1612  		err         error
  1613  		keptCurrent bool
  1614  	}{
  1615  		{&asserts.UnsupportedFormatError{}, false},
  1616  		{&asserts.UnsupportedFormatError{Update: true}, true},
  1617  		{&asserts.RevisionError{Used: 1, Current: 1}, true},
  1618  		{&asserts.RevisionError{Used: 1, Current: 5}, true},
  1619  		{&asserts.RevisionError{Used: 3, Current: 1}, false},
  1620  		{errors.New("other error"), false},
  1621  		{&asserts.NotFoundError{Type: asserts.TestOnlyType}, false},
  1622  	}
  1623  
  1624  	for _, t := range tests {
  1625  		c.Check(asserts.IsUnaccceptedUpdate(t.err), Equals, t.keptCurrent, Commentf("%v", t.err))
  1626  	}
  1627  }