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