gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/asserts/database_test.go (about)

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