github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/asserts/database.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 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 fmt.Sprintf("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 // Check tests whether the assertion is properly signed and consistent with all the stored knowledge. 197 Check(assert Assertion) error 198 } 199 200 // A Checker defines a check on an assertion considering aspects such as 201 // the signing key, and consistency with other 202 // assertions in the database. 203 type Checker func(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTime time.Time) error 204 205 // Database holds assertions and can be used to sign or check 206 // further assertions. 207 type Database struct { 208 bs Backstore 209 keypairMgr KeypairManager 210 211 trusted Backstore 212 predefined Backstore 213 // all backstores to consider for find 214 backstores []Backstore 215 // backstores of dbs this was built on by stacking 216 stackedOn []Backstore 217 218 checkers []Checker 219 } 220 221 // OpenDatabase opens the assertion database based on the configuration. 222 func OpenDatabase(cfg *DatabaseConfig) (*Database, error) { 223 bs := cfg.Backstore 224 keypairMgr := cfg.KeypairManager 225 226 if bs == nil { 227 bs = nullBackstore{} 228 } 229 if keypairMgr == nil { 230 keypairMgr = NewMemoryKeypairManager() 231 } 232 233 trustedBackstore := NewMemoryBackstore() 234 235 for _, a := range cfg.Trusted { 236 switch accepted := a.(type) { 237 case *AccountKey: 238 accKey := accepted 239 err := trustedBackstore.Put(AccountKeyType, accKey) 240 if err != nil { 241 return nil, fmt.Errorf("cannot predefine trusted account key %q for %q: %v", accKey.PublicKeyID(), accKey.AccountID(), err) 242 } 243 244 case *Account: 245 acct := accepted 246 err := trustedBackstore.Put(AccountType, acct) 247 if err != nil { 248 return nil, fmt.Errorf("cannot predefine trusted account %q: %v", acct.DisplayName(), err) 249 } 250 default: 251 return nil, fmt.Errorf("cannot predefine trusted assertions that are not account-key or account: %s", a.Type().Name) 252 } 253 } 254 255 otherPredefinedBackstore := NewMemoryBackstore() 256 257 for _, a := range cfg.OtherPredefined { 258 err := otherPredefinedBackstore.Put(a.Type(), a) 259 if err != nil { 260 return nil, fmt.Errorf("cannot predefine assertion %v: %v", a.Ref(), err) 261 } 262 } 263 264 checkers := cfg.Checkers 265 if len(checkers) == 0 { 266 checkers = DefaultCheckers 267 } 268 dbCheckers := make([]Checker, len(checkers)) 269 copy(dbCheckers, checkers) 270 271 return &Database{ 272 bs: bs, 273 keypairMgr: keypairMgr, 274 trusted: trustedBackstore, 275 predefined: otherPredefinedBackstore, 276 // order here is relevant, Find* precedence and 277 // findAccountKey depend on it, trusted should win over the 278 // general backstore! 279 backstores: []Backstore{trustedBackstore, otherPredefinedBackstore, bs}, 280 checkers: dbCheckers, 281 }, nil 282 } 283 284 // WithStackedBackstore returns a new database that adds to the given backstore 285 // only but finds in backstore and the base database backstores and 286 // cross-checks against all of them. 287 // This is useful to cross-check a set of assertions without adding 288 // them to the database. 289 func (db *Database) WithStackedBackstore(backstore Backstore) *Database { 290 // original bs goes in front of stacked-on ones 291 stackedOn := []Backstore{db.bs} 292 stackedOn = append(stackedOn, db.stackedOn...) 293 // find order: trusted, predefined, new backstore, stacked-on ones 294 backstores := []Backstore{db.trusted, db.predefined} 295 backstores = append(backstores, backstore) 296 backstores = append(backstores, stackedOn...) 297 return &Database{ 298 bs: backstore, 299 keypairMgr: db.keypairMgr, 300 trusted: db.trusted, 301 predefined: db.predefined, 302 backstores: backstores, 303 stackedOn: stackedOn, 304 checkers: db.checkers, 305 } 306 } 307 308 // ImportKey stores the given private/public key pair. 309 func (db *Database) ImportKey(privKey PrivateKey) error { 310 return db.keypairMgr.Put(privKey) 311 } 312 313 var ( 314 // for sanity checking of base64 hash strings 315 base64HashLike = regexp.MustCompile("^[[:alnum:]_-]*$") 316 ) 317 318 func (db *Database) safeGetPrivateKey(keyID string) (PrivateKey, error) { 319 if keyID == "" { 320 return nil, fmt.Errorf("key id is empty") 321 } 322 if !base64HashLike.MatchString(keyID) { 323 return nil, fmt.Errorf("key id contains unexpected chars: %q", keyID) 324 } 325 return db.keypairMgr.Get(keyID) 326 } 327 328 // PublicKey returns the public key part of the key pair that has the given key id. 329 func (db *Database) PublicKey(keyID string) (PublicKey, error) { 330 privKey, err := db.safeGetPrivateKey(keyID) 331 if err != nil { 332 return nil, err 333 } 334 return privKey.PublicKey(), nil 335 } 336 337 // Sign assembles an assertion with the provided information and signs it 338 // with the private key from `headers["authority-id"]` that has the provided key id. 339 func (db *Database) Sign(assertType *AssertionType, headers map[string]interface{}, body []byte, keyID string) (Assertion, error) { 340 privKey, err := db.safeGetPrivateKey(keyID) 341 if err != nil { 342 return nil, err 343 } 344 return assembleAndSign(assertType, headers, body, privKey) 345 } 346 347 // findAccountKey finds an AccountKey exactly with account id and key id. 348 func (db *Database) findAccountKey(authorityID, keyID string) (*AccountKey, error) { 349 key := []string{keyID} 350 // consider trusted account keys then disk stored account keys 351 for _, bs := range db.backstores { 352 a, err := bs.Get(AccountKeyType, key, AccountKeyType.MaxSupportedFormat()) 353 if err == nil { 354 hit := a.(*AccountKey) 355 if hit.AccountID() != authorityID { 356 return nil, fmt.Errorf("found public key %q from %q but expected it from: %s", keyID, hit.AccountID(), authorityID) 357 } 358 return hit, nil 359 } 360 if !IsNotFound(err) { 361 return nil, err 362 } 363 } 364 return nil, &NotFoundError{Type: AccountKeyType} 365 } 366 367 // IsTrustedAccount returns whether the account is part of the trusted set. 368 func (db *Database) IsTrustedAccount(accountID string) bool { 369 if accountID == "" { 370 return false 371 } 372 _, err := db.trusted.Get(AccountType, []string{accountID}, AccountType.MaxSupportedFormat()) 373 return err == nil 374 } 375 376 // Check tests whether the assertion is properly signed and consistent with all the stored knowledge. 377 func (db *Database) Check(assert Assertion) error { 378 if !assert.SupportedFormat() { 379 return &UnsupportedFormatError{Ref: assert.Ref(), Format: assert.Format()} 380 } 381 382 typ := assert.Type() 383 now := time.Now() 384 385 var accKey *AccountKey 386 var err error 387 if typ.flags&noAuthority == 0 { 388 // TODO: later may need to consider type of assert to find candidate keys 389 accKey, err = db.findAccountKey(assert.AuthorityID(), assert.SignKeyID()) 390 if IsNotFound(err) { 391 return fmt.Errorf("no matching public key %q for signature by %q", assert.SignKeyID(), assert.AuthorityID()) 392 } 393 if err != nil { 394 return fmt.Errorf("error finding matching public key for signature: %v", err) 395 } 396 } else { 397 if assert.AuthorityID() != "" { 398 return fmt.Errorf("internal error: %q assertion cannot have authority-id set", typ.Name) 399 } 400 } 401 402 for _, checker := range db.checkers { 403 err := checker(assert, accKey, db, now) 404 if err != nil { 405 return err 406 } 407 } 408 409 return nil 410 } 411 412 // Add persists the assertion after ensuring it is properly signed and consistent with all the stored knowledge. 413 // It will return an error when trying to add an older revision of the assertion than the one currently stored. 414 func (db *Database) Add(assert Assertion) error { 415 ref := assert.Ref() 416 417 if len(ref.PrimaryKey) == 0 { 418 return fmt.Errorf("internal error: assertion type %q has no primary key", ref.Type.Name) 419 } 420 421 err := db.Check(assert) 422 if err != nil { 423 if ufe, ok := err.(*UnsupportedFormatError); ok { 424 _, err := ref.Resolve(db.Find) 425 if err != nil && !IsNotFound(err) { 426 return err 427 } 428 return &UnsupportedFormatError{Ref: ufe.Ref, Format: ufe.Format, Update: err == nil} 429 } 430 return err 431 } 432 433 for i, keyVal := range ref.PrimaryKey { 434 if keyVal == "" { 435 return fmt.Errorf("missing or non-string primary key header: %v", ref.Type.PrimaryKey[i]) 436 } 437 } 438 439 // assuming trusted account keys/assertions will be managed 440 // through the os snap this seems the safest policy until we 441 // know more/better 442 _, err = db.trusted.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat()) 443 if !IsNotFound(err) { 444 return fmt.Errorf("cannot add %q assertion with primary key clashing with a trusted assertion: %v", ref.Type.Name, ref.PrimaryKey) 445 } 446 447 _, err = db.predefined.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat()) 448 if !IsNotFound(err) { 449 return fmt.Errorf("cannot add %q assertion with primary key clashing with a predefined assertion: %v", ref.Type.Name, ref.PrimaryKey) 450 } 451 452 // this is non empty only in the stacked case 453 if len(db.stackedOn) != 0 { 454 headers, err := HeadersFromPrimaryKey(ref.Type, ref.PrimaryKey) 455 if err != nil { 456 return fmt.Errorf("internal error: HeadersFromPrimaryKey for %q failed on prechecked data: %s", ref.Type.Name, ref.PrimaryKey) 457 } 458 cur, err := find(db.stackedOn, ref.Type, headers, -1) 459 if err == nil { 460 curRev := cur.Revision() 461 rev := assert.Revision() 462 if curRev >= rev { 463 return &RevisionError{Current: curRev, Used: rev} 464 } 465 } else if !IsNotFound(err) { 466 return err 467 } 468 } 469 470 return db.bs.Put(ref.Type, assert) 471 } 472 473 func searchMatch(assert Assertion, expectedHeaders map[string]string) bool { 474 // check non-primary-key headers as well 475 for expectedKey, expectedValue := range expectedHeaders { 476 if assert.Header(expectedKey) != expectedValue { 477 return false 478 } 479 } 480 return true 481 } 482 483 func find(backstores []Backstore, assertionType *AssertionType, headers map[string]string, maxFormat int) (Assertion, error) { 484 err := checkAssertType(assertionType) 485 if err != nil { 486 return nil, err 487 } 488 maxSupp := assertionType.MaxSupportedFormat() 489 if maxFormat == -1 { 490 maxFormat = maxSupp 491 } else { 492 if maxFormat > maxSupp { 493 return nil, fmt.Errorf("cannot find %q assertions for format %d higher than supported format %d", assertionType.Name, maxFormat, maxSupp) 494 } 495 } 496 497 keyValues, err := PrimaryKeyFromHeaders(assertionType, headers) 498 if err != nil { 499 return nil, err 500 } 501 502 var assert Assertion 503 for _, bs := range backstores { 504 a, err := bs.Get(assertionType, keyValues, maxFormat) 505 if err == nil { 506 assert = a 507 break 508 } 509 if !IsNotFound(err) { 510 return nil, err 511 } 512 } 513 514 if assert == nil || !searchMatch(assert, headers) { 515 return nil, &NotFoundError{Type: assertionType, Headers: headers} 516 } 517 518 return assert, nil 519 } 520 521 // Find an assertion based on arbitrary headers. 522 // Provided headers must contain the primary key for the assertion type. 523 // It returns a NotFoundError if the assertion cannot be found. 524 func (db *Database) Find(assertionType *AssertionType, headers map[string]string) (Assertion, error) { 525 return find(db.backstores, assertionType, headers, -1) 526 } 527 528 // FindMaxFormat finds an assertion like Find but such that its 529 // format is <= maxFormat by passing maxFormat along to the backend. 530 // It returns a NotFoundError if such an assertion cannot be found. 531 func (db *Database) FindMaxFormat(assertionType *AssertionType, headers map[string]string, maxFormat int) (Assertion, error) { 532 return find(db.backstores, assertionType, headers, maxFormat) 533 } 534 535 // FindPredefined finds an assertion in the predefined sets (trusted 536 // or not) based on arbitrary headers. Provided headers must contain 537 // the primary key for the assertion type. It returns a NotFoundError 538 // if the assertion cannot be found. 539 func (db *Database) FindPredefined(assertionType *AssertionType, headers map[string]string) (Assertion, error) { 540 return find([]Backstore{db.trusted, db.predefined}, assertionType, headers, -1) 541 } 542 543 // FindTrusted finds an assertion in the trusted set based on arbitrary headers. 544 // Provided headers must contain the primary key for the assertion type. 545 // It returns a NotFoundError if the assertion cannot be found. 546 func (db *Database) FindTrusted(assertionType *AssertionType, headers map[string]string) (Assertion, error) { 547 return find([]Backstore{db.trusted}, assertionType, headers, -1) 548 } 549 550 func (db *Database) findMany(backstores []Backstore, assertionType *AssertionType, headers map[string]string) ([]Assertion, error) { 551 err := checkAssertType(assertionType) 552 if err != nil { 553 return nil, err 554 } 555 res := []Assertion{} 556 557 foundCb := func(assert Assertion) { 558 res = append(res, assert) 559 } 560 561 // TODO: Find variant taking this 562 maxFormat := assertionType.MaxSupportedFormat() 563 for _, bs := range backstores { 564 err = bs.Search(assertionType, headers, foundCb, maxFormat) 565 if err != nil { 566 return nil, err 567 } 568 } 569 570 if len(res) == 0 { 571 return nil, &NotFoundError{Type: assertionType, Headers: headers} 572 } 573 return res, nil 574 } 575 576 // FindMany finds assertions based on arbitrary headers. 577 // It returns a NotFoundError if no assertion can be found. 578 func (db *Database) FindMany(assertionType *AssertionType, headers map[string]string) ([]Assertion, error) { 579 return db.findMany(db.backstores, assertionType, headers) 580 } 581 582 // FindManyPrefined finds assertions in the predefined sets (trusted 583 // or not) based on arbitrary headers. It returns a NotFoundError if 584 // no assertion can be found. 585 func (db *Database) FindManyPredefined(assertionType *AssertionType, headers map[string]string) ([]Assertion, error) { 586 return db.findMany([]Backstore{db.trusted, db.predefined}, assertionType, headers) 587 } 588 589 // FindSequence finds an assertion for the given headers and after for 590 // a sequence-forming type. 591 // The provided headers must contain a sequence key, i.e. a prefix of 592 // the primary key for the assertion type except for the sequence 593 // number header. 594 // The assertion is the first in the sequence under the sequence key 595 // with sequence number > after. 596 // If after is -1 it returns instead the assertion with the largest 597 // sequence number. 598 // It will constraint itself to assertions with format <= maxFormat 599 // unless maxFormat is -1. 600 // It returns a NotFoundError if the assertion cannot be found. 601 func (db *Database) FindSequence(assertType *AssertionType, sequenceHeaders map[string]string, after, maxFormat int) (SequenceMember, error) { 602 err := checkAssertType(assertType) 603 if err != nil { 604 return nil, err 605 } 606 if !assertType.SequenceForming() { 607 return nil, fmt.Errorf("cannot use FindSequence with non sequence-forming assertion type %q", assertType.Name) 608 } 609 maxSupp := assertType.MaxSupportedFormat() 610 if maxFormat == -1 { 611 maxFormat = maxSupp 612 } else { 613 if maxFormat > maxSupp { 614 return nil, fmt.Errorf("cannot find %q assertions for format %d higher than supported format %d", assertType.Name, maxFormat, maxSupp) 615 } 616 } 617 618 // form the sequence key using all keys but the last one which 619 // is the sequence number 620 seqKey, err := keysFromHeaders(assertType.PrimaryKey[:len(assertType.PrimaryKey)-1], sequenceHeaders) 621 if err != nil { 622 return nil, err 623 } 624 625 // find the better result across backstores' results 626 better := func(cur, a SequenceMember) SequenceMember { 627 if cur == nil { 628 return a 629 } 630 curSeq := cur.Sequence() 631 aSeq := a.Sequence() 632 if after == -1 { 633 if aSeq > curSeq { 634 return a 635 } 636 } else { 637 if aSeq < curSeq { 638 return a 639 } 640 } 641 return cur 642 } 643 644 var assert SequenceMember 645 for _, bs := range db.backstores { 646 a, err := bs.SequenceMemberAfter(assertType, seqKey, after, maxFormat) 647 if err == nil { 648 assert = better(assert, a) 649 continue 650 } 651 if !IsNotFound(err) { 652 return nil, err 653 } 654 } 655 656 if assert != nil { 657 return assert, nil 658 } 659 660 return nil, &NotFoundError{Type: assertType, Headers: sequenceHeaders} 661 } 662 663 // assertion checkers 664 665 // CheckSigningKeyIsNotExpired checks that the signing key is not expired. 666 func CheckSigningKeyIsNotExpired(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTime time.Time) error { 667 if signingKey == nil { 668 // assert isn't signed with an account-key key, CheckSignature 669 // will fail anyway unless we teach it more stuff, 670 // Also this check isn't so relevant for self-signed asserts 671 // (e.g. account-key-request) 672 return nil 673 } 674 if !signingKey.isKeyValidAt(checkTime) { 675 return fmt.Errorf("assertion is signed with expired public key %q from %q", assert.SignKeyID(), assert.AuthorityID()) 676 } 677 return nil 678 } 679 680 // CheckSignature checks that the signature is valid. 681 func CheckSignature(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTime time.Time) error { 682 var pubKey PublicKey 683 if signingKey != nil { 684 pubKey = signingKey.publicKey() 685 } else { 686 custom, ok := assert.(customSigner) 687 if !ok { 688 return fmt.Errorf("cannot check no-authority assertion type %q", assert.Type().Name) 689 } 690 pubKey = custom.signKey() 691 } 692 content, encSig := assert.Signature() 693 signature, err := decodeSignature(encSig) 694 if err != nil { 695 return err 696 } 697 err = pubKey.verify(content, signature) 698 if err != nil { 699 return fmt.Errorf("failed signature verification: %v", err) 700 } 701 return nil 702 } 703 704 type timestamped interface { 705 Timestamp() time.Time 706 } 707 708 // CheckTimestampVsSigningKeyValidity verifies that the timestamp of 709 // the assertion is within the signing key validity. 710 func CheckTimestampVsSigningKeyValidity(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTime time.Time) error { 711 if signingKey == nil { 712 // assert isn't signed with an account-key key, CheckSignature 713 // will fail anyway unless we teach it more stuff. 714 // Also this check isn't so relevant for self-signed asserts 715 // (e.g. account-key-request) 716 return nil 717 } 718 if tstamped, ok := assert.(timestamped); ok { 719 checkTime := tstamped.Timestamp() 720 if !signingKey.isKeyValidAt(checkTime) { 721 until := "" 722 if !signingKey.Until().IsZero() { 723 until = fmt.Sprintf(" until %q", signingKey.Until()) 724 } 725 return fmt.Errorf("%s assertion timestamp outside of signing key validity (key valid since %q%s)", assert.Type().Name, signingKey.Since(), until) 726 } 727 } 728 return nil 729 } 730 731 // XXX: keeping these in this form until we know better 732 733 // A consistencyChecker performs further checks based on the full 734 // assertion database knowledge and its own signing key. 735 type consistencyChecker interface { 736 checkConsistency(roDB RODatabase, signingKey *AccountKey) error 737 } 738 739 // CheckCrossConsistency verifies that the assertion is consistent with the other statements in the database. 740 func CheckCrossConsistency(assert Assertion, signingKey *AccountKey, roDB RODatabase, checkTime time.Time) error { 741 // see if the assertion requires further checks 742 if checker, ok := assert.(consistencyChecker); ok { 743 return checker.checkConsistency(roDB, signingKey) 744 } 745 return nil 746 } 747 748 // DefaultCheckers lists the default and recommended assertion 749 // checkers used by Database if none are specified in the 750 // DatabaseConfig.Checkers. 751 var DefaultCheckers = []Checker{ 752 CheckSigningKeyIsNotExpired, 753 CheckSignature, 754 CheckTimestampVsSigningKeyValidity, 755 CheckCrossConsistency, 756 }