github.com/rigado/snapd@v2.42.5-go-mod+incompatible/asserts/database_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2015-2016 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  type signAddFindSuite struct {
   316  	signingDB    *asserts.Database
   317  	signingKeyID string
   318  	db           *asserts.Database
   319  }
   320  
   321  var _ = Suite(&signAddFindSuite{})
   322  
   323  func (safs *signAddFindSuite) SetUpTest(c *C) {
   324  	cfg0 := &asserts.DatabaseConfig{}
   325  	db0, err := asserts.OpenDatabase(cfg0)
   326  	c.Assert(err, IsNil)
   327  	safs.signingDB = db0
   328  
   329  	pk := testPrivKey0
   330  	err = db0.ImportKey(pk)
   331  	c.Assert(err, IsNil)
   332  	safs.signingKeyID = pk.PublicKey().ID()
   333  
   334  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   335  	bs, err := asserts.OpenFSBackstore(topDir)
   336  	c.Assert(err, IsNil)
   337  
   338  	headers := map[string]interface{}{
   339  		"type":         "account",
   340  		"authority-id": "canonical",
   341  		"account-id":   "predefined",
   342  		"validation":   "verified",
   343  		"display-name": "Predef",
   344  		"timestamp":    time.Now().Format(time.RFC3339),
   345  	}
   346  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
   347  	c.Assert(err, IsNil)
   348  
   349  	trustedKey := testPrivKey0
   350  	cfg := &asserts.DatabaseConfig{
   351  		Backstore: bs,
   352  		Trusted: []asserts.Assertion{
   353  			asserts.BootstrapAccountForTest("canonical"),
   354  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey()),
   355  		},
   356  		OtherPredefined: []asserts.Assertion{
   357  			predefAcct,
   358  		},
   359  	}
   360  	db, err := asserts.OpenDatabase(cfg)
   361  	c.Assert(err, IsNil)
   362  	safs.db = db
   363  }
   364  
   365  func (safs *signAddFindSuite) TestSign(c *C) {
   366  	headers := map[string]interface{}{
   367  		"authority-id": "canonical",
   368  		"primary-key":  "a",
   369  	}
   370  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   371  	c.Assert(err, IsNil)
   372  
   373  	err = safs.db.Check(a1)
   374  	c.Check(err, IsNil)
   375  }
   376  
   377  func (safs *signAddFindSuite) TestSignEmptyKeyID(c *C) {
   378  	headers := map[string]interface{}{
   379  		"authority-id": "canonical",
   380  		"primary-key":  "a",
   381  	}
   382  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "")
   383  	c.Assert(err, ErrorMatches, "key id is empty")
   384  	c.Check(a1, IsNil)
   385  }
   386  
   387  func (safs *signAddFindSuite) TestSignMissingAuthorityId(c *C) {
   388  	headers := map[string]interface{}{
   389  		"primary-key": "a",
   390  	}
   391  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   392  	c.Assert(err, ErrorMatches, `"authority-id" header is mandatory`)
   393  	c.Check(a1, IsNil)
   394  }
   395  
   396  func (safs *signAddFindSuite) TestSignMissingPrimaryKey(c *C) {
   397  	headers := map[string]interface{}{
   398  		"authority-id": "canonical",
   399  	}
   400  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   401  	c.Assert(err, ErrorMatches, `"primary-key" header is mandatory`)
   402  	c.Check(a1, IsNil)
   403  }
   404  
   405  func (safs *signAddFindSuite) TestSignPrimaryKeyWithSlash(c *C) {
   406  	headers := map[string]interface{}{
   407  		"authority-id": "canonical",
   408  		"primary-key":  "baz/9000",
   409  	}
   410  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   411  	c.Assert(err, ErrorMatches, `"primary-key" primary key header cannot contain '/'`)
   412  	c.Check(a1, IsNil)
   413  }
   414  
   415  func (safs *signAddFindSuite) TestSignNoPrivateKey(c *C) {
   416  	headers := map[string]interface{}{
   417  		"authority-id": "canonical",
   418  		"primary-key":  "a",
   419  	}
   420  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "abcd")
   421  	c.Assert(err, ErrorMatches, "cannot find key pair")
   422  	c.Check(a1, IsNil)
   423  }
   424  
   425  func (safs *signAddFindSuite) TestSignUnknownType(c *C) {
   426  	headers := map[string]interface{}{
   427  		"authority-id": "canonical",
   428  	}
   429  	a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "xyz", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
   430  	c.Assert(err, ErrorMatches, `internal error: unknown assertion type: "xyz"`)
   431  	c.Check(a1, IsNil)
   432  }
   433  
   434  func (safs *signAddFindSuite) TestSignNonPredefinedType(c *C) {
   435  	headers := map[string]interface{}{
   436  		"authority-id": "canonical",
   437  	}
   438  	a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "test-only", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
   439  	c.Assert(err, ErrorMatches, `internal error: unpredefined assertion type for name "test-only" used.*`)
   440  	c.Check(a1, IsNil)
   441  }
   442  
   443  func (safs *signAddFindSuite) TestSignBadRevision(c *C) {
   444  	headers := map[string]interface{}{
   445  		"authority-id": "canonical",
   446  		"primary-key":  "a",
   447  		"revision":     "zzz",
   448  	}
   449  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   450  	c.Assert(err, ErrorMatches, `"revision" header is not an integer: zzz`)
   451  	c.Check(a1, IsNil)
   452  }
   453  
   454  func (safs *signAddFindSuite) TestSignBadFormat(c *C) {
   455  	headers := map[string]interface{}{
   456  		"authority-id": "canonical",
   457  		"primary-key":  "a",
   458  		"format":       "zzz",
   459  	}
   460  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   461  	c.Assert(err, ErrorMatches, `"format" header is not an integer: zzz`)
   462  	c.Check(a1, IsNil)
   463  }
   464  
   465  func (safs *signAddFindSuite) TestSignHeadersCheck(c *C) {
   466  	headers := map[string]interface{}{
   467  		"authority-id": "canonical",
   468  		"primary-key":  "a",
   469  		"extra":        []interface{}{1, 2},
   470  	}
   471  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   472  	c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
   473  	c.Check(a1, IsNil)
   474  }
   475  
   476  func (safs *signAddFindSuite) TestSignHeadersCheckMap(c *C) {
   477  	headers := map[string]interface{}{
   478  		"authority-id": "canonical",
   479  		"primary-key":  "a",
   480  		"extra":        map[string]interface{}{"a": "a", "b": 1},
   481  	}
   482  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   483  	c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
   484  	c.Check(a1, IsNil)
   485  }
   486  
   487  func (safs *signAddFindSuite) TestSignAssemblerError(c *C) {
   488  	headers := map[string]interface{}{
   489  		"authority-id": "canonical",
   490  		"primary-key":  "a",
   491  		"count":        "zzz",
   492  	}
   493  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   494  	c.Assert(err, ErrorMatches, `cannot assemble assertion test-only: "count" header is not an integer: zzz`)
   495  	c.Check(a1, IsNil)
   496  }
   497  
   498  func (safs *signAddFindSuite) TestSignUnsupportedFormat(c *C) {
   499  	headers := map[string]interface{}{
   500  		"authority-id": "canonical",
   501  		"primary-key":  "a",
   502  		"format":       "77",
   503  	}
   504  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   505  	c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format 77 higher than max supported format 1`)
   506  	c.Check(a1, IsNil)
   507  }
   508  
   509  func (safs *signAddFindSuite) TestSignInadequateFormat(c *C) {
   510  	headers := map[string]interface{}{
   511  		"authority-id":     "canonical",
   512  		"primary-key":      "a",
   513  		"format-1-feature": "true",
   514  	}
   515  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   516  	c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format set to 0 lower than min format 1 covering included features`)
   517  	c.Check(a1, IsNil)
   518  }
   519  
   520  func (safs *signAddFindSuite) TestAddRefusesSelfSignedKey(c *C) {
   521  	aKey := testPrivKey2
   522  
   523  	aKeyEncoded, err := asserts.EncodePublicKey(aKey.PublicKey())
   524  	c.Assert(err, IsNil)
   525  
   526  	now := time.Now().UTC()
   527  	headers := map[string]interface{}{
   528  		"authority-id":        "canonical",
   529  		"account-id":          "canonical",
   530  		"public-key-sha3-384": aKey.PublicKey().ID(),
   531  		"name":                "default",
   532  		"since":               now.Format(time.RFC3339),
   533  	}
   534  	acctKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, aKeyEncoded, aKey)
   535  	c.Assert(err, IsNil)
   536  
   537  	// this must fail
   538  	err = safs.db.Add(acctKey)
   539  	c.Check(err, ErrorMatches, `no matching public key.*`)
   540  }
   541  
   542  func (safs *signAddFindSuite) TestAddSuperseding(c *C) {
   543  	headers := map[string]interface{}{
   544  		"authority-id": "canonical",
   545  		"primary-key":  "a",
   546  	}
   547  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   548  	c.Assert(err, IsNil)
   549  
   550  	err = safs.db.Add(a1)
   551  	c.Assert(err, IsNil)
   552  
   553  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
   554  		"primary-key": "a",
   555  	})
   556  	c.Assert(err, IsNil)
   557  	c.Check(retrieved1, NotNil)
   558  	c.Check(retrieved1.Revision(), Equals, 0)
   559  
   560  	headers["revision"] = "1"
   561  	a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   562  	c.Assert(err, IsNil)
   563  
   564  	err = safs.db.Add(a2)
   565  	c.Assert(err, IsNil)
   566  
   567  	retrieved2, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
   568  		"primary-key": "a",
   569  	})
   570  	c.Assert(err, IsNil)
   571  	c.Check(retrieved2, NotNil)
   572  	c.Check(retrieved2.Revision(), Equals, 1)
   573  
   574  	err = safs.db.Add(a1)
   575  	c.Check(err, ErrorMatches, "revision 0 is older than current revision 1")
   576  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
   577  }
   578  
   579  func (safs *signAddFindSuite) TestAddNoAuthorityNoPrimaryKey(c *C) {
   580  	headers := map[string]interface{}{
   581  		"hdr": "FOO",
   582  	}
   583  	a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityType, headers, nil, testPrivKey0)
   584  	c.Assert(err, IsNil)
   585  
   586  	err = safs.db.Add(a)
   587  	c.Assert(err, ErrorMatches, `internal error: assertion type "test-only-no-authority" has no primary key`)
   588  }
   589  
   590  func (safs *signAddFindSuite) TestAddNoAuthorityButPrimaryKey(c *C) {
   591  	headers := map[string]interface{}{
   592  		"pk": "primary",
   593  	}
   594  	a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityPKType, headers, nil, testPrivKey0)
   595  	c.Assert(err, IsNil)
   596  
   597  	err = safs.db.Add(a)
   598  	c.Assert(err, ErrorMatches, `cannot check no-authority assertion type "test-only-no-authority-pk"`)
   599  }
   600  
   601  func (safs *signAddFindSuite) TestAddUnsupportedFormat(c *C) {
   602  	const unsupported = "type: test-only\n" +
   603  		"format: 77\n" +
   604  		"authority-id: canonical\n" +
   605  		"primary-key: a\n" +
   606  		"payload: unsupported\n" +
   607  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   608  		"\n\n" +
   609  		"AXNpZw=="
   610  	aUnsupp, err := asserts.Decode([]byte(unsupported))
   611  	c.Assert(err, IsNil)
   612  	c.Assert(aUnsupp.SupportedFormat(), Equals, false)
   613  
   614  	err = safs.db.Add(aUnsupp)
   615  	c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
   616  	c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, false)
   617  	c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported`)
   618  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, false)
   619  
   620  	headers := map[string]interface{}{
   621  		"authority-id": "canonical",
   622  		"primary-key":  "a",
   623  		"format":       "1",
   624  		"payload":      "supported",
   625  	}
   626  	aSupp, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
   627  	c.Assert(err, IsNil)
   628  
   629  	err = safs.db.Add(aSupp)
   630  	c.Assert(err, IsNil)
   631  
   632  	err = safs.db.Add(aUnsupp)
   633  	c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
   634  	c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, true)
   635  	c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported \(current not updated\)`)
   636  	c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
   637  }
   638  
   639  func (safs *signAddFindSuite) TestNotFoundError(c *C) {
   640  	err1 := &asserts.NotFoundError{
   641  		Type: asserts.SnapDeclarationType,
   642  		Headers: map[string]string{
   643  			"series":  "16",
   644  			"snap-id": "snap-id",
   645  		},
   646  	}
   647  	c.Check(asserts.IsNotFound(err1), Equals, true)
   648  	c.Check(err1.Error(), Equals, "snap-declaration (snap-id; series:16) not found")
   649  
   650  	err2 := &asserts.NotFoundError{
   651  		Type: asserts.SnapRevisionType,
   652  	}
   653  	c.Check(asserts.IsNotFound(err1), Equals, true)
   654  	c.Check(err2.Error(), Equals, "snap-revision assertion not found")
   655  }
   656  
   657  func (safs *signAddFindSuite) TestFindNotFound(c *C) {
   658  	headers := map[string]interface{}{
   659  		"authority-id": "canonical",
   660  		"primary-key":  "a",
   661  	}
   662  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   663  	c.Assert(err, IsNil)
   664  
   665  	err = safs.db.Add(a1)
   666  	c.Assert(err, IsNil)
   667  
   668  	hdrs := map[string]string{
   669  		"primary-key": "b",
   670  	}
   671  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, hdrs)
   672  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   673  		Type:    asserts.TestOnlyType,
   674  		Headers: hdrs,
   675  	})
   676  	c.Check(retrieved1, IsNil)
   677  
   678  	// checking also extra headers
   679  	hdrs = map[string]string{
   680  		"primary-key":  "a",
   681  		"authority-id": "other-auth-id",
   682  	}
   683  	retrieved1, err = safs.db.Find(asserts.TestOnlyType, hdrs)
   684  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   685  		Type:    asserts.TestOnlyType,
   686  		Headers: hdrs,
   687  	})
   688  	c.Check(retrieved1, IsNil)
   689  }
   690  
   691  func (safs *signAddFindSuite) TestFindPrimaryLeftOut(c *C) {
   692  	retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{})
   693  	c.Assert(err, ErrorMatches, "must provide primary key: primary-key")
   694  	c.Check(retrieved1, IsNil)
   695  }
   696  
   697  func (safs *signAddFindSuite) TestFindMany(c *C) {
   698  	headers := map[string]interface{}{
   699  		"authority-id": "canonical",
   700  		"primary-key":  "a",
   701  		"other":        "other-x",
   702  	}
   703  	aa, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   704  	c.Assert(err, IsNil)
   705  	err = safs.db.Add(aa)
   706  	c.Assert(err, IsNil)
   707  
   708  	headers = map[string]interface{}{
   709  		"authority-id": "canonical",
   710  		"primary-key":  "b",
   711  		"other":        "other-y",
   712  	}
   713  	ab, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   714  	c.Assert(err, IsNil)
   715  	err = safs.db.Add(ab)
   716  	c.Assert(err, IsNil)
   717  
   718  	headers = map[string]interface{}{
   719  		"authority-id": "canonical",
   720  		"primary-key":  "c",
   721  		"other":        "other-x",
   722  	}
   723  	ac, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
   724  	c.Assert(err, IsNil)
   725  	err = safs.db.Add(ac)
   726  	c.Assert(err, IsNil)
   727  
   728  	res, err := safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   729  		"other": "other-x",
   730  	})
   731  	c.Assert(err, IsNil)
   732  	c.Assert(res, HasLen, 2)
   733  	primKeys := []string{res[0].HeaderString("primary-key"), res[1].HeaderString("primary-key")}
   734  	sort.Strings(primKeys)
   735  	c.Check(primKeys, DeepEquals, []string{"a", "c"})
   736  
   737  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   738  		"other": "other-y",
   739  	})
   740  	c.Assert(err, IsNil)
   741  	c.Assert(res, HasLen, 1)
   742  	c.Check(res[0].Header("primary-key"), Equals, "b")
   743  
   744  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{})
   745  	c.Assert(err, IsNil)
   746  	c.Assert(res, HasLen, 3)
   747  
   748  	res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
   749  		"primary-key": "b",
   750  		"other":       "other-y",
   751  	})
   752  	c.Assert(err, IsNil)
   753  	c.Assert(res, HasLen, 1)
   754  
   755  	hdrs := map[string]string{
   756  		"primary-key": "b",
   757  		"other":       "other-x",
   758  	}
   759  	res, err = safs.db.FindMany(asserts.TestOnlyType, hdrs)
   760  	c.Assert(res, HasLen, 0)
   761  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   762  		Type:    asserts.TestOnlyType,
   763  		Headers: hdrs,
   764  	})
   765  }
   766  
   767  func (safs *signAddFindSuite) TestFindFindsPredefined(c *C) {
   768  	pk1 := testPrivKey1
   769  
   770  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   771  		"authority-id": "canonical",
   772  	}, safs.signingKeyID)
   773  
   774  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   775  		"authority-id": "canonical",
   776  	}, pk1.PublicKey(), safs.signingKeyID)
   777  
   778  	err := safs.db.Add(acct1)
   779  	c.Assert(err, IsNil)
   780  	err = safs.db.Add(acct1Key)
   781  	c.Assert(err, IsNil)
   782  
   783  	// find the trusted key as well
   784  	tKey, err := safs.db.Find(asserts.AccountKeyType, map[string]string{
   785  		"account-id":          "canonical",
   786  		"public-key-sha3-384": safs.signingKeyID,
   787  	})
   788  	c.Assert(err, IsNil)
   789  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
   790  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
   791  
   792  	// find predefined account as well
   793  	predefAcct, err := safs.db.Find(asserts.AccountType, map[string]string{
   794  		"account-id": "predefined",
   795  	})
   796  	c.Assert(err, IsNil)
   797  	c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
   798  	c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
   799  
   800  	// find trusted and indirectly trusted
   801  	accKeys, err := safs.db.FindMany(asserts.AccountKeyType, nil)
   802  	c.Assert(err, IsNil)
   803  	c.Check(accKeys, HasLen, 2)
   804  
   805  	accts, err := safs.db.FindMany(asserts.AccountType, nil)
   806  	c.Assert(err, IsNil)
   807  	c.Check(accts, HasLen, 3)
   808  }
   809  
   810  func (safs *signAddFindSuite) TestFindTrusted(c *C) {
   811  	pk1 := testPrivKey1
   812  
   813  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   814  		"authority-id": "canonical",
   815  	}, safs.signingKeyID)
   816  
   817  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   818  		"authority-id": "canonical",
   819  	}, pk1.PublicKey(), safs.signingKeyID)
   820  
   821  	err := safs.db.Add(acct1)
   822  	c.Assert(err, IsNil)
   823  	err = safs.db.Add(acct1Key)
   824  	c.Assert(err, IsNil)
   825  
   826  	// find the trusted account
   827  	tAcct, err := safs.db.FindTrusted(asserts.AccountType, map[string]string{
   828  		"account-id": "canonical",
   829  	})
   830  	c.Assert(err, IsNil)
   831  	c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
   832  
   833  	// find the trusted key
   834  	tKey, err := safs.db.FindTrusted(asserts.AccountKeyType, map[string]string{
   835  		"account-id":          "canonical",
   836  		"public-key-sha3-384": safs.signingKeyID,
   837  	})
   838  	c.Assert(err, IsNil)
   839  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
   840  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
   841  
   842  	// doesn't find not trusted assertions
   843  	hdrs := map[string]string{
   844  		"account-id": acct1.AccountID(),
   845  	}
   846  	_, err = safs.db.FindTrusted(asserts.AccountType, hdrs)
   847  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   848  		Type:    asserts.AccountType,
   849  		Headers: hdrs,
   850  	})
   851  
   852  	hdrs = map[string]string{
   853  		"account-id":          acct1.AccountID(),
   854  		"public-key-sha3-384": acct1Key.PublicKeyID(),
   855  	}
   856  	_, err = safs.db.FindTrusted(asserts.AccountKeyType, hdrs)
   857  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   858  		Type:    asserts.AccountKeyType,
   859  		Headers: hdrs,
   860  	})
   861  
   862  	_, err = safs.db.FindTrusted(asserts.AccountType, map[string]string{
   863  		"account-id": "predefined",
   864  	})
   865  	c.Check(asserts.IsNotFound(err), Equals, true)
   866  }
   867  
   868  func (safs *signAddFindSuite) TestFindPredefined(c *C) {
   869  	pk1 := testPrivKey1
   870  
   871  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   872  		"authority-id": "canonical",
   873  	}, safs.signingKeyID)
   874  
   875  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   876  		"authority-id": "canonical",
   877  	}, pk1.PublicKey(), safs.signingKeyID)
   878  
   879  	err := safs.db.Add(acct1)
   880  	c.Assert(err, IsNil)
   881  	err = safs.db.Add(acct1Key)
   882  	c.Assert(err, IsNil)
   883  
   884  	// find the trusted account
   885  	tAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
   886  		"account-id": "canonical",
   887  	})
   888  	c.Assert(err, IsNil)
   889  	c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
   890  
   891  	// find the trusted key
   892  	tKey, err := safs.db.FindPredefined(asserts.AccountKeyType, map[string]string{
   893  		"account-id":          "canonical",
   894  		"public-key-sha3-384": safs.signingKeyID,
   895  	})
   896  	c.Assert(err, IsNil)
   897  	c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
   898  	c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
   899  
   900  	// find predefined account as well
   901  	predefAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
   902  		"account-id": "predefined",
   903  	})
   904  	c.Assert(err, IsNil)
   905  	c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
   906  	c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
   907  
   908  	// doesn't find not trusted or predefined assertions
   909  	hdrs := map[string]string{
   910  		"account-id": acct1.AccountID(),
   911  	}
   912  	_, err = safs.db.FindPredefined(asserts.AccountType, hdrs)
   913  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   914  		Type:    asserts.AccountType,
   915  		Headers: hdrs,
   916  	})
   917  
   918  	hdrs = map[string]string{
   919  		"account-id":          acct1.AccountID(),
   920  		"public-key-sha3-384": acct1Key.PublicKeyID(),
   921  	}
   922  	_, err = safs.db.FindPredefined(asserts.AccountKeyType, hdrs)
   923  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   924  		Type:    asserts.AccountKeyType,
   925  		Headers: hdrs,
   926  	})
   927  }
   928  
   929  func (safs *signAddFindSuite) TestFindManyPredefined(c *C) {
   930  	headers := map[string]interface{}{
   931  		"type":         "account",
   932  		"authority-id": "canonical",
   933  		"account-id":   "predefined",
   934  		"validation":   "verified",
   935  		"display-name": "Predef",
   936  		"timestamp":    time.Now().Format(time.RFC3339),
   937  	}
   938  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
   939  	c.Assert(err, IsNil)
   940  
   941  	trustedKey0 := testPrivKey0
   942  	trustedKey1 := testPrivKey1
   943  	cfg := &asserts.DatabaseConfig{
   944  		Backstore: asserts.NewMemoryBackstore(),
   945  		Trusted: []asserts.Assertion{
   946  			asserts.BootstrapAccountForTest("canonical"),
   947  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey0.PublicKey()),
   948  			asserts.BootstrapAccountKeyForTest("canonical", trustedKey1.PublicKey()),
   949  		},
   950  		OtherPredefined: []asserts.Assertion{
   951  			predefAcct,
   952  		},
   953  	}
   954  	db, err := asserts.OpenDatabase(cfg)
   955  	c.Assert(err, IsNil)
   956  
   957  	pk1 := testPrivKey2
   958  
   959  	acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
   960  		"authority-id": "canonical",
   961  	}, safs.signingKeyID)
   962  
   963  	acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
   964  		"authority-id": "canonical",
   965  	}, pk1.PublicKey(), safs.signingKeyID)
   966  
   967  	err = db.Add(acct1)
   968  	c.Assert(err, IsNil)
   969  	err = db.Add(acct1Key)
   970  	c.Assert(err, IsNil)
   971  
   972  	// find the trusted account
   973  	tAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
   974  		"account-id": "canonical",
   975  	})
   976  	c.Assert(err, IsNil)
   977  	c.Assert(tAccts, HasLen, 1)
   978  	c.Assert(tAccts[0].(*asserts.Account).AccountID(), Equals, "canonical")
   979  
   980  	// find the predefined account
   981  	pAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
   982  		"account-id": "predefined",
   983  	})
   984  	c.Assert(err, IsNil)
   985  	c.Assert(pAccts, HasLen, 1)
   986  	c.Assert(pAccts[0].(*asserts.Account).AccountID(), Equals, "predefined")
   987  
   988  	// find the multiple trusted keys
   989  	tKeys, err := db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
   990  		"account-id": "canonical",
   991  	})
   992  	c.Assert(err, IsNil)
   993  	c.Assert(tKeys, HasLen, 2)
   994  	got := make(map[string]string)
   995  	for _, a := range tKeys {
   996  		acctKey := a.(*asserts.AccountKey)
   997  		got[acctKey.PublicKeyID()] = acctKey.AccountID()
   998  	}
   999  	c.Check(got, DeepEquals, map[string]string{
  1000  		trustedKey0.PublicKey().ID(): "canonical",
  1001  		trustedKey1.PublicKey().ID(): "canonical",
  1002  	})
  1003  
  1004  	// doesn't find not predefined assertions
  1005  	hdrs := map[string]string{
  1006  		"account-id": acct1.AccountID(),
  1007  	}
  1008  	_, err = db.FindManyPredefined(asserts.AccountType, hdrs)
  1009  	c.Check(err, DeepEquals, &asserts.NotFoundError{
  1010  		Type:    asserts.AccountType,
  1011  		Headers: hdrs,
  1012  	})
  1013  
  1014  	_, err = db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
  1015  		"account-id":          acct1.AccountID(),
  1016  		"public-key-sha3-384": acct1Key.PublicKeyID(),
  1017  	})
  1018  	c.Check(asserts.IsNotFound(err), Equals, true)
  1019  }
  1020  
  1021  func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithTrustedOnes(c *C) {
  1022  	// trusted
  1023  	pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
  1024  	c.Assert(err, IsNil)
  1025  	pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
  1026  	c.Assert(err, IsNil)
  1027  
  1028  	now := time.Now().UTC()
  1029  	headers := map[string]interface{}{
  1030  		"authority-id":        "canonical",
  1031  		"account-id":          "canonical",
  1032  		"public-key-sha3-384": safs.signingKeyID,
  1033  		"name":                "default",
  1034  		"since":               now.Format(time.RFC3339),
  1035  		"until":               now.AddDate(1, 0, 0).Format(time.RFC3339),
  1036  	}
  1037  	tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
  1038  	c.Assert(err, IsNil)
  1039  
  1040  	err = safs.db.Add(tKey)
  1041  	c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
  1042  }
  1043  
  1044  func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithPredefinedOnes(c *C) {
  1045  	headers := map[string]interface{}{
  1046  		"type":         "account",
  1047  		"authority-id": "canonical",
  1048  		"account-id":   "predefined",
  1049  		"validation":   "verified",
  1050  		"display-name": "Predef",
  1051  		"timestamp":    time.Now().Format(time.RFC3339),
  1052  	}
  1053  	predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
  1054  	c.Assert(err, IsNil)
  1055  
  1056  	err = safs.db.Add(predefAcct)
  1057  	c.Check(err, ErrorMatches, `cannot add "account" assertion with primary key clashing with a predefined assertion: .*`)
  1058  }
  1059  
  1060  func (safs *signAddFindSuite) TestFindAndRefResolve(c *C) {
  1061  	headers := map[string]interface{}{
  1062  		"authority-id": "canonical",
  1063  		"pk1":          "ka",
  1064  		"pk2":          "kb",
  1065  	}
  1066  	a1, err := safs.signingDB.Sign(asserts.TestOnly2Type, headers, nil, safs.signingKeyID)
  1067  	c.Assert(err, IsNil)
  1068  
  1069  	err = safs.db.Add(a1)
  1070  	c.Assert(err, IsNil)
  1071  
  1072  	ref := &asserts.Ref{
  1073  		Type:       asserts.TestOnly2Type,
  1074  		PrimaryKey: []string{"ka", "kb"},
  1075  	}
  1076  
  1077  	resolved, err := ref.Resolve(safs.db.Find)
  1078  	c.Assert(err, IsNil)
  1079  	c.Check(resolved.Headers(), DeepEquals, map[string]interface{}{
  1080  		"type":              "test-only-2",
  1081  		"authority-id":      "canonical",
  1082  		"pk1":               "ka",
  1083  		"pk2":               "kb",
  1084  		"sign-key-sha3-384": resolved.SignKeyID(),
  1085  	})
  1086  
  1087  	ref = &asserts.Ref{
  1088  		Type:       asserts.TestOnly2Type,
  1089  		PrimaryKey: []string{"kb", "ka"},
  1090  	}
  1091  	_, err = ref.Resolve(safs.db.Find)
  1092  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
  1093  		Type: ref.Type,
  1094  		Headers: map[string]string{
  1095  			"pk1": "kb",
  1096  			"pk2": "ka",
  1097  		},
  1098  	})
  1099  }
  1100  
  1101  func (safs *signAddFindSuite) TestFindMaxFormat(c *C) {
  1102  	headers := map[string]interface{}{
  1103  		"authority-id": "canonical",
  1104  		"primary-key":  "foo",
  1105  	}
  1106  	af0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1107  	c.Assert(err, IsNil)
  1108  
  1109  	err = safs.db.Add(af0)
  1110  	c.Assert(err, IsNil)
  1111  
  1112  	headers = map[string]interface{}{
  1113  		"authority-id": "canonical",
  1114  		"primary-key":  "foo",
  1115  		"format":       "1",
  1116  		"revision":     "1",
  1117  	}
  1118  	af1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1119  	c.Assert(err, IsNil)
  1120  
  1121  	err = safs.db.Add(af1)
  1122  	c.Assert(err, IsNil)
  1123  
  1124  	a, err := safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1125  		"primary-key": "foo",
  1126  	}, 1)
  1127  	c.Assert(err, IsNil)
  1128  	c.Check(a.Revision(), Equals, 1)
  1129  
  1130  	a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1131  		"primary-key": "foo",
  1132  	}, 0)
  1133  	c.Assert(err, IsNil)
  1134  	c.Check(a.Revision(), Equals, 0)
  1135  
  1136  	a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
  1137  		"primary-key": "foo",
  1138  	}, 3)
  1139  	c.Check(err, ErrorMatches, `cannot find "test-only" assertions for format 3 higher than supported format 1`)
  1140  }
  1141  
  1142  func (safs *signAddFindSuite) TestWithStackedBackstore(c *C) {
  1143  	headers := map[string]interface{}{
  1144  		"authority-id": "canonical",
  1145  		"primary-key":  "one",
  1146  	}
  1147  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1148  	c.Assert(err, IsNil)
  1149  
  1150  	err = safs.db.Add(a1)
  1151  	c.Assert(err, IsNil)
  1152  
  1153  	headers = map[string]interface{}{
  1154  		"authority-id": "canonical",
  1155  		"primary-key":  "two",
  1156  	}
  1157  	a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1158  	c.Assert(err, IsNil)
  1159  
  1160  	bs := asserts.NewMemoryBackstore()
  1161  	stacked := safs.db.WithStackedBackstore(bs)
  1162  
  1163  	err = stacked.Add(a2)
  1164  	c.Assert(err, IsNil)
  1165  
  1166  	_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
  1167  		"primary-key": "one",
  1168  	})
  1169  	c.Check(err, IsNil)
  1170  
  1171  	_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
  1172  		"primary-key": "two",
  1173  	})
  1174  	c.Check(err, IsNil)
  1175  
  1176  	_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
  1177  		"primary-key": "two",
  1178  	})
  1179  	c.Check(asserts.IsNotFound(err), Equals, true)
  1180  
  1181  	_, err = stacked.Find(asserts.AccountKeyType, map[string]string{
  1182  		"public-key-sha3-384": safs.signingKeyID,
  1183  	})
  1184  	c.Check(err, IsNil)
  1185  
  1186  	// stored in backstore
  1187  	_, err = bs.Get(asserts.TestOnlyType, []string{"two"}, 0)
  1188  	c.Check(err, IsNil)
  1189  }
  1190  
  1191  func (safs *signAddFindSuite) TestWithStackedBackstoreSafety(c *C) {
  1192  	stacked := safs.db.WithStackedBackstore(asserts.NewMemoryBackstore())
  1193  
  1194  	// usual add safety
  1195  	pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
  1196  	c.Assert(err, IsNil)
  1197  	pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
  1198  	c.Assert(err, IsNil)
  1199  
  1200  	now := time.Now().UTC()
  1201  	headers := map[string]interface{}{
  1202  		"authority-id":        "canonical",
  1203  		"account-id":          "canonical",
  1204  		"public-key-sha3-384": safs.signingKeyID,
  1205  		"name":                "default",
  1206  		"since":               now.Format(time.RFC3339),
  1207  		"until":               now.AddDate(1, 0, 0).Format(time.RFC3339),
  1208  	}
  1209  	tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
  1210  	c.Assert(err, IsNil)
  1211  
  1212  	err = stacked.Add(tKey)
  1213  	c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
  1214  
  1215  	// cannot go back to old revisions
  1216  	headers = map[string]interface{}{
  1217  		"authority-id": "canonical",
  1218  		"primary-key":  "one",
  1219  	}
  1220  	a0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1221  	c.Assert(err, IsNil)
  1222  
  1223  	headers = map[string]interface{}{
  1224  		"authority-id": "canonical",
  1225  		"primary-key":  "one",
  1226  		"revision":     "1",
  1227  	}
  1228  	a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
  1229  	c.Assert(err, IsNil)
  1230  
  1231  	err = safs.db.Add(a1)
  1232  	c.Assert(err, IsNil)
  1233  
  1234  	err = stacked.Add(a0)
  1235  	c.Assert(err, DeepEquals, &asserts.RevisionError{
  1236  		Used:    0,
  1237  		Current: 1,
  1238  	})
  1239  }
  1240  
  1241  type revisionErrorSuite struct{}
  1242  
  1243  func (res *revisionErrorSuite) TestErrorText(c *C) {
  1244  	tests := []struct {
  1245  		err      error
  1246  		expected string
  1247  	}{
  1248  		// Invalid revisions.
  1249  		{&asserts.RevisionError{Used: -1}, "assertion revision is unknown"},
  1250  		{&asserts.RevisionError{Used: -100}, "assertion revision is unknown"},
  1251  		{&asserts.RevisionError{Current: -1}, "assertion revision is unknown"},
  1252  		{&asserts.RevisionError{Current: -100}, "assertion revision is unknown"},
  1253  		{&asserts.RevisionError{Used: -1, Current: -1}, "assertion revision is unknown"},
  1254  		// Used == Current.
  1255  		{&asserts.RevisionError{}, "revision 0 is already the current revision"},
  1256  		{&asserts.RevisionError{Used: 100, Current: 100}, "revision 100 is already the current revision"},
  1257  		// Used < Current.
  1258  		{&asserts.RevisionError{Used: 1, Current: 2}, "revision 1 is older than current revision 2"},
  1259  		{&asserts.RevisionError{Used: 2, Current: 100}, "revision 2 is older than current revision 100"},
  1260  		// Used > Current.
  1261  		{&asserts.RevisionError{Current: 1, Used: 2}, "revision 2 is more recent than current revision 1"},
  1262  		{&asserts.RevisionError{Current: 2, Used: 100}, "revision 100 is more recent than current revision 2"},
  1263  	}
  1264  
  1265  	for _, test := range tests {
  1266  		c.Check(test.err, ErrorMatches, test.expected)
  1267  	}
  1268  }
  1269  
  1270  type isUnacceptedUpdateSuite struct{}
  1271  
  1272  func (s *isUnacceptedUpdateSuite) TestIsUnacceptedUpdate(c *C) {
  1273  	tests := []struct {
  1274  		err         error
  1275  		keptCurrent bool
  1276  	}{
  1277  		{&asserts.UnsupportedFormatError{}, false},
  1278  		{&asserts.UnsupportedFormatError{Update: true}, true},
  1279  		{&asserts.RevisionError{Used: 1, Current: 1}, true},
  1280  		{&asserts.RevisionError{Used: 1, Current: 5}, true},
  1281  		{&asserts.RevisionError{Used: 3, Current: 1}, false},
  1282  		{errors.New("other error"), false},
  1283  		{&asserts.NotFoundError{Type: asserts.TestOnlyType}, false},
  1284  	}
  1285  
  1286  	for _, t := range tests {
  1287  		c.Check(asserts.IsUnaccceptedUpdate(t.err), Equals, t.keptCurrent, Commentf("%v", t.err))
  1288  	}
  1289  }