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