github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/asserts/database.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2015-2021 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 implements snappy assertions and a database
    21  // abstraction for managing and holding them.
    22  package asserts
    23  
    24  import (
    25  	"fmt"
    26  	"regexp"
    27  	"time"
    28  )
    29  
    30  // NotFoundError is returned when an assertion can not be found.
    31  type NotFoundError struct {
    32  	Type    *AssertionType
    33  	Headers map[string]string
    34  }
    35  
    36  func (e *NotFoundError) Error() string {
    37  	pk, err := PrimaryKeyFromHeaders(e.Type, e.Headers)
    38  	if err != nil || len(e.Headers) != len(pk) {
    39  		// TODO: worth conveying more information?
    40  		return fmt.Sprintf("%s assertion not found", e.Type.Name)
    41  	}
    42  
    43  	return fmt.Sprintf("%v not found", &Ref{Type: e.Type, PrimaryKey: pk})
    44  }
    45  
    46  // IsNotFound returns whether err is an assertion not found error.
    47  func IsNotFound(err error) bool {
    48  	_, ok := err.(*NotFoundError)
    49  	return ok
    50  }
    51  
    52  // A Backstore stores assertions. It can store and retrieve assertions
    53  // by type under unique primary key headers (whose names are available
    54  // from assertType.PrimaryKey). Plus it supports searching by headers.
    55  // Lookups can be limited to a maximum allowed format.
    56  type Backstore interface {
    57  	// Put stores an assertion.
    58  	// It is responsible for checking that assert is newer than a
    59  	// previously stored revision with the same primary key headers.
    60  	Put(assertType *AssertionType, assert Assertion) error
    61  	// Get returns the assertion with the given unique key for its
    62  	// primary key headers.  If none is present it returns a
    63  	// NotFoundError, usually with omitted Headers.
    64  	Get(assertType *AssertionType, key []string, maxFormat int) (Assertion, error)
    65  	// Search returns assertions matching the given headers.
    66  	// It invokes foundCb for each found assertion.
    67  	Search(assertType *AssertionType, headers map[string]string, foundCb func(Assertion), maxFormat int) error
    68  	// SequenceMemberAfter returns for a sequence-forming assertType the
    69  	// first assertion in the sequence under the given sequenceKey
    70  	// with sequence number larger than after. If after==-1 it
    71  	// returns the assertion with largest sequence number. If none
    72  	// exists it returns a NotFoundError, usually with omitted
    73  	// Headers. If assertType is not sequence-forming it can
    74  	// panic.
    75  	SequenceMemberAfter(assertType *AssertionType, sequenceKey []string, after, maxFormat int) (SequenceMember, error)
    76  }
    77  
    78  type nullBackstore struct{}
    79  
    80  func (nbs nullBackstore) Put(t *AssertionType, a Assertion) error {
    81  	return fmt.Errorf("cannot store assertions without setting a proper assertion backstore implementation")
    82  }
    83  
    84  func (nbs nullBackstore) Get(t *AssertionType, k []string, maxFormat int) (Assertion, error) {
    85  	return nil, &NotFoundError{Type: t}
    86  }
    87  
    88  func (nbs nullBackstore) Search(t *AssertionType, h map[string]string, f func(Assertion), maxFormat int) error {
    89  	return nil
    90  }
    91  
    92  func (nbs nullBackstore) SequenceMemberAfter(t *AssertionType, kp []string, after, maxFormat int) (SequenceMember, error) {
    93  	return nil, &NotFoundError{Type: t}
    94  }
    95  
    96  // A KeypairManager is a manager and backstore for private/public key pairs.
    97  type KeypairManager interface {
    98  	// Put stores the given private/public key pair,
    99  	// making sure it can be later retrieved by its unique key id with Get.
   100  	// Trying to store a key with an already present key id should
   101  	// result in an error.
   102  	Put(privKey PrivateKey) error
   103  	// Get returns the private/public key pair with the given key id.
   104  	Get(keyID string) (PrivateKey, error)
   105  }
   106  
   107  // DatabaseConfig for an assertion database.
   108  type DatabaseConfig struct {
   109  	// trusted set of assertions (account and account-key supported),
   110  	// used to establish root keys and trusted authorities
   111  	Trusted []Assertion
   112  	// predefined assertions but that do not establish foundational trust
   113  	OtherPredefined []Assertion
   114  	// backstore for assertions, left unset storing assertions will error
   115  	Backstore Backstore
   116  	// manager/backstore for keypairs, defaults to in-memory implementation
   117  	KeypairManager KeypairManager
   118  	// assertion checkers used by Database.Check, left unset DefaultCheckers will be used which is recommended
   119  	Checkers []Checker
   120  }
   121  
   122  // RevisionError indicates a revision improperly used for an operation.
   123  type RevisionError struct {
   124  	Used, Current int
   125  }
   126  
   127  func (e *RevisionError) Error() string {
   128  	if e.Used < 0 || e.Current < 0 {
   129  		// TODO: message may need tweaking once there's a use.
   130  		return "assertion revision is unknown"
   131  	}
   132  	if e.Used == e.Current {
   133  		return fmt.Sprintf("revision %d is already the current revision", e.Used)
   134  	}
   135  	if e.Used < e.Current {
   136  		return fmt.Sprintf("revision %d is older than current revision %d", e.Used, e.Current)
   137  	}
   138  	return fmt.Sprintf("revision %d is more recent than current revision %d", e.Used, e.Current)
   139  }
   140  
   141  // UnsupportedFormatError indicates an assertion with a format iteration not yet supported by the present version of asserts.
   142  type UnsupportedFormatError struct {
   143  	Ref    *Ref
   144  	Format int
   145  	// Update marks there was already a current revision of the assertion and it has been kept.
   146  	Update bool
   147  }
   148  
   149  func (e *UnsupportedFormatError) Error() string {
   150  	postfx := ""
   151  	if e.Update {
   152  		postfx = " (current not updated)"
   153  	}
   154  	return fmt.Sprintf("proposed %q assertion has format %d but %d is latest supported%s", e.Ref.Type.Name, e.Format, e.Ref.Type.MaxSupportedFormat(), postfx)
   155  }
   156  
   157  // IsUnaccceptedUpdate returns whether the error indicates that an
   158  // assertion revision was already present and has been kept because
   159  // the update was not accepted.
   160  func IsUnaccceptedUpdate(err error) bool {
   161  	switch x := err.(type) {
   162  	case *UnsupportedFormatError:
   163  		return x.Update
   164  	case *RevisionError:
   165  		return x.Used <= x.Current
   166  	}
   167  	return false
   168  }
   169  
   170  // A RODatabase exposes read-only access to an assertion database.
   171  type RODatabase interface {
   172  	// IsTrustedAccount returns whether the account is part of the trusted set.
   173  	IsTrustedAccount(accountID string) bool
   174  	// Find an assertion based on arbitrary headers.
   175  	// Provided headers must contain the primary key for the assertion type.
   176  	// It returns a NotFoundError if the assertion cannot be found.
   177  	Find(assertionType *AssertionType, headers map[string]string) (Assertion, error)
   178  	// FindPredefined finds an assertion in the predefined sets
   179  	// (trusted or not) based on arbitrary headers.  Provided
   180  	// headers must contain the primary key for the assertion
   181  	// type.  It returns a NotFoundError if the assertion cannot
   182  	// be found.
   183  	FindPredefined(assertionType *AssertionType, headers map[string]string) (Assertion, error)
   184  	// FindTrusted finds an assertion in the trusted set based on
   185  	// arbitrary headers.  Provided headers must contain the
   186  	// primary key for the assertion type.  It returns a
   187  	// NotFoundError if the assertion cannot be found.
   188  	FindTrusted(assertionType *AssertionType, headers map[string]string) (Assertion, error)
   189  	// FindMany finds assertions based on arbitrary headers.
   190  	// It returns a NotFoundError if no assertion can be found.
   191  	FindMany(assertionType *AssertionType, headers map[string]string) ([]Assertion, error)
   192  	// FindManyPredefined finds assertions in the predefined sets
   193  	// (trusted or not) based on arbitrary headers.  It returns a
   194  	// NotFoundError if no assertion can be found.
   195  	FindManyPredefined(assertionType *AssertionType, headers map[string]string) ([]Assertion, error)
   196  	// FindSequence finds an assertion for the given headers and after for
   197  	// a sequence-forming type.
   198  	// The provided headers must contain a sequence key, i.e. a prefix of
   199  	// the primary key for the assertion type except for the sequence
   200  	// number header.
   201  	// The assertion is the first in the sequence under the sequence key
   202  	// with sequence number > after.
   203  	// If after is -1 it returns instead the assertion with the largest
   204  	// sequence number.
   205  	// It will constraint itself to assertions with format <= maxFormat
   206  	// unless maxFormat is -1.
   207  	// It returns a NotFoundError if the assertion cannot be found.
   208  	FindSequence(assertType *AssertionType, sequenceHeaders map[string]string, after, maxFormat int) (SequenceMember, error)
   209  	// Check tests whether the assertion is properly signed and consistent with all the stored knowledge.
   210  	Check(assert Assertion) error
   211  }
   212  
   213  // A Checker defines a check on an assertion considering aspects such as
   214  // the signing key, and consistency with other
   215  // assertions in the database.
   216  type Checker func(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTimeEarliest, checkTimeLatest time.Time) error
   217  
   218  // Database holds assertions and can be used to sign or check
   219  // further assertions.
   220  type Database struct {
   221  	bs         Backstore
   222  	keypairMgr KeypairManager
   223  
   224  	trusted    Backstore
   225  	predefined Backstore
   226  	// all backstores to consider for find
   227  	backstores []Backstore
   228  	// backstores of dbs this was built on by stacking
   229  	stackedOn []Backstore
   230  
   231  	checkers     []Checker
   232  	earliestTime time.Time
   233  }
   234  
   235  // OpenDatabase opens the assertion database based on the configuration.
   236  func OpenDatabase(cfg *DatabaseConfig) (*Database, error) {
   237  	bs := cfg.Backstore
   238  	keypairMgr := cfg.KeypairManager
   239  
   240  	if bs == nil {
   241  		bs = nullBackstore{}
   242  	}
   243  	if keypairMgr == nil {
   244  		keypairMgr = NewMemoryKeypairManager()
   245  	}
   246  
   247  	trustedBackstore := NewMemoryBackstore()
   248  
   249  	for _, a := range cfg.Trusted {
   250  		switch accepted := a.(type) {
   251  		case *AccountKey:
   252  			accKey := accepted
   253  			err := trustedBackstore.Put(AccountKeyType, accKey)
   254  			if err != nil {
   255  				return nil, fmt.Errorf("cannot predefine trusted account key %q for %q: %v", accKey.PublicKeyID(), accKey.AccountID(), err)
   256  			}
   257  
   258  		case *Account:
   259  			acct := accepted
   260  			err := trustedBackstore.Put(AccountType, acct)
   261  			if err != nil {
   262  				return nil, fmt.Errorf("cannot predefine trusted account %q: %v", acct.DisplayName(), err)
   263  			}
   264  		default:
   265  			return nil, fmt.Errorf("cannot predefine trusted assertions that are not account-key or account: %s", a.Type().Name)
   266  		}
   267  	}
   268  
   269  	otherPredefinedBackstore := NewMemoryBackstore()
   270  
   271  	for _, a := range cfg.OtherPredefined {
   272  		err := otherPredefinedBackstore.Put(a.Type(), a)
   273  		if err != nil {
   274  			return nil, fmt.Errorf("cannot predefine assertion %v: %v", a.Ref(), err)
   275  		}
   276  	}
   277  
   278  	checkers := cfg.Checkers
   279  	if len(checkers) == 0 {
   280  		checkers = DefaultCheckers
   281  	}
   282  	dbCheckers := make([]Checker, len(checkers))
   283  	copy(dbCheckers, checkers)
   284  
   285  	return &Database{
   286  		bs:         bs,
   287  		keypairMgr: keypairMgr,
   288  		trusted:    trustedBackstore,
   289  		predefined: otherPredefinedBackstore,
   290  		// order here is relevant, Find* precedence and
   291  		// findAccountKey depend on it, trusted should win over the
   292  		// general backstore!
   293  		backstores: []Backstore{trustedBackstore, otherPredefinedBackstore, bs},
   294  		checkers:   dbCheckers,
   295  	}, nil
   296  }
   297  
   298  // WithStackedBackstore returns a new database that adds to the given backstore
   299  // only but finds in backstore and the base database backstores and
   300  // cross-checks against all of them.
   301  // This is useful to cross-check a set of assertions without adding
   302  // them to the database.
   303  func (db *Database) WithStackedBackstore(backstore Backstore) *Database {
   304  	// original bs goes in front of stacked-on ones
   305  	stackedOn := []Backstore{db.bs}
   306  	stackedOn = append(stackedOn, db.stackedOn...)
   307  	// find order: trusted, predefined, new backstore, stacked-on ones
   308  	backstores := []Backstore{db.trusted, db.predefined}
   309  	backstores = append(backstores, backstore)
   310  	backstores = append(backstores, stackedOn...)
   311  	return &Database{
   312  		bs:         backstore,
   313  		keypairMgr: db.keypairMgr,
   314  		trusted:    db.trusted,
   315  		predefined: db.predefined,
   316  		backstores: backstores,
   317  		stackedOn:  stackedOn,
   318  		checkers:   db.checkers,
   319  	}
   320  }
   321  
   322  // ImportKey stores the given private/public key pair.
   323  func (db *Database) ImportKey(privKey PrivateKey) error {
   324  	return db.keypairMgr.Put(privKey)
   325  }
   326  
   327  var (
   328  	// for sanity checking of base64 hash strings
   329  	base64HashLike = regexp.MustCompile("^[[:alnum:]_-]*$")
   330  )
   331  
   332  func (db *Database) safeGetPrivateKey(keyID string) (PrivateKey, error) {
   333  	if keyID == "" {
   334  		return nil, fmt.Errorf("key id is empty")
   335  	}
   336  	if !base64HashLike.MatchString(keyID) {
   337  		return nil, fmt.Errorf("key id contains unexpected chars: %q", keyID)
   338  	}
   339  	return db.keypairMgr.Get(keyID)
   340  }
   341  
   342  // PublicKey returns the public key part of the key pair that has the given key id.
   343  func (db *Database) PublicKey(keyID string) (PublicKey, error) {
   344  	privKey, err := db.safeGetPrivateKey(keyID)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	return privKey.PublicKey(), nil
   349  }
   350  
   351  // Sign assembles an assertion with the provided information and signs it
   352  // with the private key from `headers["authority-id"]` that has the provided key id.
   353  func (db *Database) Sign(assertType *AssertionType, headers map[string]interface{}, body []byte, keyID string) (Assertion, error) {
   354  	privKey, err := db.safeGetPrivateKey(keyID)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	return assembleAndSign(assertType, headers, body, privKey)
   359  }
   360  
   361  // findAccountKey finds an AccountKey exactly with account id and key id.
   362  func (db *Database) findAccountKey(authorityID, keyID string) (*AccountKey, error) {
   363  	key := []string{keyID}
   364  	// consider trusted account keys then disk stored account keys
   365  	for _, bs := range db.backstores {
   366  		a, err := bs.Get(AccountKeyType, key, AccountKeyType.MaxSupportedFormat())
   367  		if err == nil {
   368  			hit := a.(*AccountKey)
   369  			if hit.AccountID() != authorityID {
   370  				return nil, fmt.Errorf("found public key %q from %q but expected it from: %s", keyID, hit.AccountID(), authorityID)
   371  			}
   372  			return hit, nil
   373  		}
   374  		if !IsNotFound(err) {
   375  			return nil, err
   376  		}
   377  	}
   378  	return nil, &NotFoundError{Type: AccountKeyType}
   379  }
   380  
   381  // IsTrustedAccount returns whether the account is part of the trusted set.
   382  func (db *Database) IsTrustedAccount(accountID string) bool {
   383  	if accountID == "" {
   384  		return false
   385  	}
   386  	_, err := db.trusted.Get(AccountType, []string{accountID}, AccountType.MaxSupportedFormat())
   387  	return err == nil
   388  }
   389  
   390  var timeNow = time.Now
   391  
   392  // SetEarliestTime affects how key expiration is checked.
   393  // Instead of considering current system time, only assume that current time
   394  // is >= earliest. If earliest is zero reset to considering current system time.
   395  func (db *Database) SetEarliestTime(earliest time.Time) {
   396  	db.earliestTime = earliest
   397  }
   398  
   399  // Check tests whether the assertion is properly signed and consistent with all the stored knowledge.
   400  func (db *Database) Check(assert Assertion) error {
   401  	if !assert.SupportedFormat() {
   402  		return &UnsupportedFormatError{Ref: assert.Ref(), Format: assert.Format()}
   403  	}
   404  
   405  	typ := assert.Type()
   406  	// assume current time is >= earliestTime and <= latestTime
   407  	earliestTime := db.earliestTime
   408  	var latestTime time.Time
   409  	if earliestTime.IsZero() {
   410  		// use the current system time by setting both to it
   411  		earliestTime = timeNow()
   412  		latestTime = earliestTime
   413  	}
   414  
   415  	var accKey *AccountKey
   416  	var err error
   417  	if typ.flags&noAuthority == 0 {
   418  		// TODO: later may need to consider type of assert to find candidate keys
   419  		accKey, err = db.findAccountKey(assert.AuthorityID(), assert.SignKeyID())
   420  		if IsNotFound(err) {
   421  			return fmt.Errorf("no matching public key %q for signature by %q", assert.SignKeyID(), assert.AuthorityID())
   422  		}
   423  		if err != nil {
   424  			return fmt.Errorf("error finding matching public key for signature: %v", err)
   425  		}
   426  	} else {
   427  		if assert.AuthorityID() != "" {
   428  			return fmt.Errorf("internal error: %q assertion cannot have authority-id set", typ.Name)
   429  		}
   430  	}
   431  
   432  	for _, checker := range db.checkers {
   433  		err := checker(assert, accKey, db, earliestTime, latestTime)
   434  		if err != nil {
   435  			return err
   436  		}
   437  	}
   438  
   439  	return nil
   440  }
   441  
   442  // Add persists the assertion after ensuring it is properly signed and consistent with all the stored knowledge.
   443  // It will return an error when trying to add an older revision of the assertion than the one currently stored.
   444  func (db *Database) Add(assert Assertion) error {
   445  	ref := assert.Ref()
   446  
   447  	if len(ref.PrimaryKey) == 0 {
   448  		return fmt.Errorf("internal error: assertion type %q has no primary key", ref.Type.Name)
   449  	}
   450  
   451  	err := db.Check(assert)
   452  	if err != nil {
   453  		if ufe, ok := err.(*UnsupportedFormatError); ok {
   454  			_, err := ref.Resolve(db.Find)
   455  			if err != nil && !IsNotFound(err) {
   456  				return err
   457  			}
   458  			return &UnsupportedFormatError{Ref: ufe.Ref, Format: ufe.Format, Update: err == nil}
   459  		}
   460  		return err
   461  	}
   462  
   463  	for i, keyVal := range ref.PrimaryKey {
   464  		if keyVal == "" {
   465  			return fmt.Errorf("missing or non-string primary key header: %v", ref.Type.PrimaryKey[i])
   466  		}
   467  	}
   468  
   469  	// assuming trusted account keys/assertions will be managed
   470  	// through the os snap this seems the safest policy until we
   471  	// know more/better
   472  	_, err = db.trusted.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat())
   473  	if !IsNotFound(err) {
   474  		return fmt.Errorf("cannot add %q assertion with primary key clashing with a trusted assertion: %v", ref.Type.Name, ref.PrimaryKey)
   475  	}
   476  
   477  	_, err = db.predefined.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat())
   478  	if !IsNotFound(err) {
   479  		return fmt.Errorf("cannot add %q assertion with primary key clashing with a predefined assertion: %v", ref.Type.Name, ref.PrimaryKey)
   480  	}
   481  
   482  	// this is non empty only in the stacked case
   483  	if len(db.stackedOn) != 0 {
   484  		headers, err := HeadersFromPrimaryKey(ref.Type, ref.PrimaryKey)
   485  		if err != nil {
   486  			return fmt.Errorf("internal error: HeadersFromPrimaryKey for %q failed on prechecked data: %s", ref.Type.Name, ref.PrimaryKey)
   487  		}
   488  		cur, err := find(db.stackedOn, ref.Type, headers, -1)
   489  		if err == nil {
   490  			curRev := cur.Revision()
   491  			rev := assert.Revision()
   492  			if curRev >= rev {
   493  				return &RevisionError{Current: curRev, Used: rev}
   494  			}
   495  		} else if !IsNotFound(err) {
   496  			return err
   497  		}
   498  	}
   499  
   500  	return db.bs.Put(ref.Type, assert)
   501  }
   502  
   503  func searchMatch(assert Assertion, expectedHeaders map[string]string) bool {
   504  	// check non-primary-key headers as well
   505  	for expectedKey, expectedValue := range expectedHeaders {
   506  		if assert.Header(expectedKey) != expectedValue {
   507  			return false
   508  		}
   509  	}
   510  	return true
   511  }
   512  
   513  func find(backstores []Backstore, assertionType *AssertionType, headers map[string]string, maxFormat int) (Assertion, error) {
   514  	err := checkAssertType(assertionType)
   515  	if err != nil {
   516  		return nil, err
   517  	}
   518  	maxSupp := assertionType.MaxSupportedFormat()
   519  	if maxFormat == -1 {
   520  		maxFormat = maxSupp
   521  	} else {
   522  		if maxFormat > maxSupp {
   523  			return nil, fmt.Errorf("cannot find %q assertions for format %d higher than supported format %d", assertionType.Name, maxFormat, maxSupp)
   524  		}
   525  	}
   526  
   527  	keyValues, err := PrimaryKeyFromHeaders(assertionType, headers)
   528  	if err != nil {
   529  		return nil, err
   530  	}
   531  
   532  	var assert Assertion
   533  	for _, bs := range backstores {
   534  		a, err := bs.Get(assertionType, keyValues, maxFormat)
   535  		if err == nil {
   536  			assert = a
   537  			break
   538  		}
   539  		if !IsNotFound(err) {
   540  			return nil, err
   541  		}
   542  	}
   543  
   544  	if assert == nil || !searchMatch(assert, headers) {
   545  		return nil, &NotFoundError{Type: assertionType, Headers: headers}
   546  	}
   547  
   548  	return assert, nil
   549  }
   550  
   551  // Find an assertion based on arbitrary headers.
   552  // Provided headers must contain the primary key for the assertion type.
   553  // It returns a NotFoundError if the assertion cannot be found.
   554  func (db *Database) Find(assertionType *AssertionType, headers map[string]string) (Assertion, error) {
   555  	return find(db.backstores, assertionType, headers, -1)
   556  }
   557  
   558  // FindMaxFormat finds an assertion like Find but such that its
   559  // format is <= maxFormat by passing maxFormat along to the backend.
   560  // It returns a NotFoundError if such an assertion cannot be found.
   561  func (db *Database) FindMaxFormat(assertionType *AssertionType, headers map[string]string, maxFormat int) (Assertion, error) {
   562  	return find(db.backstores, assertionType, headers, maxFormat)
   563  }
   564  
   565  // FindPredefined finds an assertion in the predefined sets (trusted
   566  // or not) based on arbitrary headers.  Provided headers must contain
   567  // the primary key for the assertion type.  It returns a NotFoundError
   568  // if the assertion cannot be found.
   569  func (db *Database) FindPredefined(assertionType *AssertionType, headers map[string]string) (Assertion, error) {
   570  	return find([]Backstore{db.trusted, db.predefined}, assertionType, headers, -1)
   571  }
   572  
   573  // FindTrusted finds an assertion in the trusted set based on arbitrary headers.
   574  // Provided headers must contain the primary key for the assertion type.
   575  // It returns a NotFoundError if the assertion cannot be found.
   576  func (db *Database) FindTrusted(assertionType *AssertionType, headers map[string]string) (Assertion, error) {
   577  	return find([]Backstore{db.trusted}, assertionType, headers, -1)
   578  }
   579  
   580  func (db *Database) findMany(backstores []Backstore, assertionType *AssertionType, headers map[string]string) ([]Assertion, error) {
   581  	err := checkAssertType(assertionType)
   582  	if err != nil {
   583  		return nil, err
   584  	}
   585  	res := []Assertion{}
   586  
   587  	foundCb := func(assert Assertion) {
   588  		res = append(res, assert)
   589  	}
   590  
   591  	// TODO: Find variant taking this
   592  	maxFormat := assertionType.MaxSupportedFormat()
   593  	for _, bs := range backstores {
   594  		err = bs.Search(assertionType, headers, foundCb, maxFormat)
   595  		if err != nil {
   596  			return nil, err
   597  		}
   598  	}
   599  
   600  	if len(res) == 0 {
   601  		return nil, &NotFoundError{Type: assertionType, Headers: headers}
   602  	}
   603  	return res, nil
   604  }
   605  
   606  // FindMany finds assertions based on arbitrary headers.
   607  // It returns a NotFoundError if no assertion can be found.
   608  func (db *Database) FindMany(assertionType *AssertionType, headers map[string]string) ([]Assertion, error) {
   609  	return db.findMany(db.backstores, assertionType, headers)
   610  }
   611  
   612  // FindManyPrefined finds assertions in the predefined sets (trusted
   613  // or not) based on arbitrary headers.  It returns a NotFoundError if
   614  // no assertion can be found.
   615  func (db *Database) FindManyPredefined(assertionType *AssertionType, headers map[string]string) ([]Assertion, error) {
   616  	return db.findMany([]Backstore{db.trusted, db.predefined}, assertionType, headers)
   617  }
   618  
   619  // FindSequence finds an assertion for the given headers and after for
   620  // a sequence-forming type.
   621  // The provided headers must contain a sequence key, i.e. a prefix of
   622  // the primary key for the assertion type except for the sequence
   623  // number header.
   624  // The assertion is the first in the sequence under the sequence key
   625  // with sequence number > after.
   626  // If after is -1 it returns instead the assertion with the largest
   627  // sequence number.
   628  // It will constraint itself to assertions with format <= maxFormat
   629  // unless maxFormat is -1.
   630  // It returns a NotFoundError if the assertion cannot be found.
   631  func (db *Database) FindSequence(assertType *AssertionType, sequenceHeaders map[string]string, after, maxFormat int) (SequenceMember, error) {
   632  	err := checkAssertType(assertType)
   633  	if err != nil {
   634  		return nil, err
   635  	}
   636  	if !assertType.SequenceForming() {
   637  		return nil, fmt.Errorf("cannot use FindSequence with non sequence-forming assertion type %q", assertType.Name)
   638  	}
   639  	maxSupp := assertType.MaxSupportedFormat()
   640  	if maxFormat == -1 {
   641  		maxFormat = maxSupp
   642  	} else {
   643  		if maxFormat > maxSupp {
   644  			return nil, fmt.Errorf("cannot find %q assertions for format %d higher than supported format %d", assertType.Name, maxFormat, maxSupp)
   645  		}
   646  	}
   647  
   648  	// form the sequence key using all keys but the last one which
   649  	// is the sequence number
   650  	seqKey, err := keysFromHeaders(assertType.PrimaryKey[:len(assertType.PrimaryKey)-1], sequenceHeaders)
   651  	if err != nil {
   652  		return nil, err
   653  	}
   654  
   655  	// find the better result across backstores' results
   656  	better := func(cur, a SequenceMember) SequenceMember {
   657  		if cur == nil {
   658  			return a
   659  		}
   660  		curSeq := cur.Sequence()
   661  		aSeq := a.Sequence()
   662  		if after == -1 {
   663  			if aSeq > curSeq {
   664  				return a
   665  			}
   666  		} else {
   667  			if aSeq < curSeq {
   668  				return a
   669  			}
   670  		}
   671  		return cur
   672  	}
   673  
   674  	var assert SequenceMember
   675  	for _, bs := range db.backstores {
   676  		a, err := bs.SequenceMemberAfter(assertType, seqKey, after, maxFormat)
   677  		if err == nil {
   678  			assert = better(assert, a)
   679  			continue
   680  		}
   681  		if !IsNotFound(err) {
   682  			return nil, err
   683  		}
   684  	}
   685  
   686  	if assert != nil {
   687  		return assert, nil
   688  	}
   689  
   690  	return nil, &NotFoundError{Type: assertType, Headers: sequenceHeaders}
   691  }
   692  
   693  // assertion checkers
   694  
   695  // CheckSigningKeyIsNotExpired checks that the signing key is not expired.
   696  func CheckSigningKeyIsNotExpired(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTimeEarliest, checkTimeLatest time.Time) error {
   697  	if signingKey == nil {
   698  		// assert isn't signed with an account-key key, CheckSignature
   699  		// will fail anyway unless we teach it more stuff,
   700  		// Also this check isn't so relevant for self-signed asserts
   701  		// (e.g. account-key-request)
   702  		return nil
   703  	}
   704  	if !signingKey.isKeyValidAssumingCurTimeWithin(checkTimeEarliest, checkTimeLatest) {
   705  		return fmt.Errorf("assertion is signed with expired public key %q from %q", assert.SignKeyID(), assert.AuthorityID())
   706  	}
   707  	return nil
   708  }
   709  
   710  // CheckSignature checks that the signature is valid.
   711  func CheckSignature(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTimeEarliest, checkTimeLatest time.Time) error {
   712  	var pubKey PublicKey
   713  	if signingKey != nil {
   714  		pubKey = signingKey.publicKey()
   715  		if assert.AuthorityID() != signingKey.AccountID() {
   716  			return fmt.Errorf("assertion authority %q does not match public key from %q", assert.AuthorityID(), signingKey.AccountID())
   717  		}
   718  	} else {
   719  		custom, ok := assert.(customSigner)
   720  		if !ok {
   721  			return fmt.Errorf("cannot check no-authority assertion type %q", assert.Type().Name)
   722  		}
   723  		pubKey = custom.signKey()
   724  	}
   725  	content, encSig := assert.Signature()
   726  	signature, err := decodeSignature(encSig)
   727  	if err != nil {
   728  		return err
   729  	}
   730  	err = pubKey.verify(content, signature)
   731  	if err != nil {
   732  		return fmt.Errorf("failed signature verification: %v", err)
   733  	}
   734  	return nil
   735  }
   736  
   737  type timestamped interface {
   738  	Timestamp() time.Time
   739  }
   740  
   741  // CheckTimestampVsSigningKeyValidity verifies that the timestamp of
   742  // the assertion is within the signing key validity.
   743  func CheckTimestampVsSigningKeyValidity(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTimeEarliest, checkTimeLatest time.Time) error {
   744  	if signingKey == nil {
   745  		// assert isn't signed with an account-key key, CheckSignature
   746  		// will fail anyway unless we teach it more stuff.
   747  		// Also this check isn't so relevant for self-signed asserts
   748  		// (e.g. account-key-request)
   749  		return nil
   750  	}
   751  	if tstamped, ok := assert.(timestamped); ok {
   752  		checkTime := tstamped.Timestamp()
   753  		if !signingKey.isKeyValidAt(checkTime) {
   754  			until := ""
   755  			if !signingKey.Until().IsZero() {
   756  				until = fmt.Sprintf(" until %q", signingKey.Until())
   757  			}
   758  			return fmt.Errorf("%s assertion timestamp %q outside of signing key validity (key valid since %q%s)",
   759  				assert.Type().Name, checkTime, signingKey.Since(), until)
   760  		}
   761  	}
   762  	return nil
   763  }
   764  
   765  // XXX: keeping these in this form until we know better
   766  
   767  // A consistencyChecker performs further checks based on the full
   768  // assertion database knowledge and its own signing key.
   769  type consistencyChecker interface {
   770  	checkConsistency(roDB RODatabase, signingKey *AccountKey) error
   771  }
   772  
   773  // CheckCrossConsistency verifies that the assertion is consistent with the other statements in the database.
   774  func CheckCrossConsistency(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTimeEarliest, checkTimeLatest time.Time) error {
   775  	// see if the assertion requires further checks
   776  	if checker, ok := assert.(consistencyChecker); ok {
   777  		return checker.checkConsistency(roDB, signingKey)
   778  	}
   779  	return nil
   780  }
   781  
   782  // DefaultCheckers lists the default and recommended assertion
   783  // checkers used by Database if none are specified in the
   784  // DatabaseConfig.Checkers.
   785  var DefaultCheckers = []Checker{
   786  	CheckSigningKeyIsNotExpired,
   787  	CheckSignature,
   788  	CheckTimestampVsSigningKeyValidity,
   789  	CheckCrossConsistency,
   790  }