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