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