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