github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/asserts/account_key_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015-2016 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 "encoding/base64" 24 "fmt" 25 "path/filepath" 26 "strings" 27 "time" 28 29 . "gopkg.in/check.v1" 30 31 "github.com/snapcore/snapd/asserts" 32 "github.com/snapcore/snapd/asserts/assertstest" 33 ) 34 35 type accountKeySuite struct { 36 privKey asserts.PrivateKey 37 pubKeyBody string 38 keyID string 39 since, until time.Time 40 sinceLine, untilLine string 41 } 42 43 var _ = Suite(&accountKeySuite{}) 44 45 func (aks *accountKeySuite) SetUpSuite(c *C) { 46 cfg1 := &asserts.DatabaseConfig{} 47 accDb, err := asserts.OpenDatabase(cfg1) 48 c.Assert(err, IsNil) 49 aks.privKey = testPrivKey1 50 err = accDb.ImportKey(aks.privKey) 51 c.Assert(err, IsNil) 52 aks.keyID = aks.privKey.PublicKey().ID() 53 54 pubKey, err := accDb.PublicKey(aks.keyID) 55 c.Assert(err, IsNil) 56 pubKeyEncoded, err := asserts.EncodePublicKey(pubKey) 57 c.Assert(err, IsNil) 58 aks.pubKeyBody = string(pubKeyEncoded) 59 60 aks.since, err = time.Parse(time.RFC822, "16 Nov 15 15:04 UTC") 61 c.Assert(err, IsNil) 62 aks.until = aks.since.AddDate(1, 0, 0) 63 aks.sinceLine = "since: " + aks.since.Format(time.RFC3339) + "\n" 64 aks.untilLine = "until: " + aks.until.Format(time.RFC3339) + "\n" 65 } 66 67 func (aks *accountKeySuite) TestDecodeOK(c *C) { 68 encoded := "type: account-key\n" + 69 "authority-id: canonical\n" + 70 "account-id: acc-id1\n" + 71 "name: default\n" + 72 "public-key-sha3-384: " + aks.keyID + "\n" + 73 aks.sinceLine + 74 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 75 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 76 aks.pubKeyBody + "\n\n" + 77 "AXNpZw==" 78 a, err := asserts.Decode([]byte(encoded)) 79 c.Assert(err, IsNil) 80 c.Check(a.Type(), Equals, asserts.AccountKeyType) 81 accKey := a.(*asserts.AccountKey) 82 c.Check(accKey.AccountID(), Equals, "acc-id1") 83 c.Check(accKey.Name(), Equals, "default") 84 c.Check(accKey.PublicKeyID(), Equals, aks.keyID) 85 c.Check(accKey.Since(), Equals, aks.since) 86 } 87 88 func (aks *accountKeySuite) TestDecodeNoName(c *C) { 89 // XXX: remove this test once name is mandatory 90 encoded := "type: account-key\n" + 91 "authority-id: canonical\n" + 92 "account-id: acc-id1\n" + 93 "public-key-sha3-384: " + aks.keyID + "\n" + 94 aks.sinceLine + 95 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 96 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 97 aks.pubKeyBody + "\n\n" + 98 "AXNpZw==" 99 a, err := asserts.Decode([]byte(encoded)) 100 c.Assert(err, IsNil) 101 c.Check(a.Type(), Equals, asserts.AccountKeyType) 102 accKey := a.(*asserts.AccountKey) 103 c.Check(accKey.AccountID(), Equals, "acc-id1") 104 c.Check(accKey.Name(), Equals, "") 105 c.Check(accKey.PublicKeyID(), Equals, aks.keyID) 106 c.Check(accKey.Since(), Equals, aks.since) 107 } 108 109 func (aks *accountKeySuite) TestUntil(c *C) { 110 111 untilSinceLine := "until: " + aks.since.Format(time.RFC3339) + "\n" 112 113 tests := []struct { 114 untilLine string 115 until time.Time 116 }{ 117 {"", time.Time{}}, // zero time default 118 {aks.untilLine, aks.until}, // in the future 119 {untilSinceLine, aks.since}, // same as since 120 } 121 122 for _, test := range tests { 123 c.Log(test) 124 encoded := "type: account-key\n" + 125 "authority-id: canonical\n" + 126 "account-id: acc-id1\n" + 127 "name: default\n" + 128 "public-key-sha3-384: " + aks.keyID + "\n" + 129 aks.sinceLine + 130 test.untilLine + 131 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 132 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 133 aks.pubKeyBody + "\n\n" + 134 "openpgp c2ln" 135 a, err := asserts.Decode([]byte(encoded)) 136 c.Assert(err, IsNil) 137 accKey := a.(*asserts.AccountKey) 138 c.Check(accKey.Until(), Equals, test.until) 139 } 140 } 141 142 const ( 143 accKeyErrPrefix = "assertion account-key: " 144 accKeyReqErrPrefix = "assertion account-key-request: " 145 ) 146 147 func (aks *accountKeySuite) TestDecodeInvalidHeaders(c *C) { 148 149 encoded := "type: account-key\n" + 150 "authority-id: canonical\n" + 151 "account-id: acc-id1\n" + 152 "name: default\n" + 153 "public-key-sha3-384: " + aks.keyID + "\n" + 154 aks.sinceLine + 155 aks.untilLine + 156 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 157 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 158 aks.pubKeyBody + "\n\n" + 159 "AXNpZw==" 160 161 untilPast := aks.since.AddDate(-1, 0, 0) 162 untilPastLine := "until: " + untilPast.Format(time.RFC3339) + "\n" 163 164 invalidHeaderTests := []struct{ original, invalid, expectedErr string }{ 165 {"account-id: acc-id1\n", "", `"account-id" header is mandatory`}, 166 {"account-id: acc-id1\n", "account-id: \n", `"account-id" header should not be empty`}, 167 // XXX: enable this once name is mandatory 168 // {"name: default\n", "", `"name" header is mandatory`}, 169 {"name: default\n", "name: \n", `"name" header should not be empty`}, 170 {"name: default\n", "name: a b\n", `"name" header contains invalid characters: "a b"`}, 171 {"name: default\n", "name: -default\n", `"name" header contains invalid characters: "-default"`}, 172 {"name: default\n", "name: foo:bar\n", `"name" header contains invalid characters: "foo:bar"`}, 173 {"name: default\n", "name: a--b\n", `"name" header contains invalid characters: "a--b"`}, 174 {"name: default\n", "name: 42\n", `"name" header contains invalid characters: "42"`}, 175 {"public-key-sha3-384: " + aks.keyID + "\n", "", `"public-key-sha3-384" header is mandatory`}, 176 {"public-key-sha3-384: " + aks.keyID + "\n", "public-key-sha3-384: \n", `"public-key-sha3-384" header should not be empty`}, 177 {aks.sinceLine, "", `"since" header is mandatory`}, 178 {aks.sinceLine, "since: \n", `"since" header should not be empty`}, 179 {aks.sinceLine, "since: 12:30\n", `"since" header is not a RFC3339 date: .*`}, 180 {aks.sinceLine, "since: \n", `"since" header should not be empty`}, 181 {aks.untilLine, "until: \n", `"until" header is not a RFC3339 date: .*`}, 182 {aks.untilLine, "until: 12:30\n", `"until" header is not a RFC3339 date: .*`}, 183 {aks.untilLine, untilPastLine, `'until' time cannot be before 'since' time`}, 184 } 185 186 for _, test := range invalidHeaderTests { 187 invalid := strings.Replace(encoded, test.original, test.invalid, 1) 188 _, err := asserts.Decode([]byte(invalid)) 189 c.Check(err, ErrorMatches, accKeyErrPrefix+test.expectedErr) 190 } 191 } 192 193 func (aks *accountKeySuite) TestDecodeInvalidPublicKey(c *C) { 194 headers := "type: account-key\n" + 195 "authority-id: canonical\n" + 196 "account-id: acc-id1\n" + 197 "name: default\n" + 198 "public-key-sha3-384: " + aks.keyID + "\n" + 199 aks.sinceLine + 200 aks.untilLine 201 202 raw, err := base64.StdEncoding.DecodeString(aks.pubKeyBody) 203 c.Assert(err, IsNil) 204 spurious := base64.StdEncoding.EncodeToString(append(raw, "gorp"...)) 205 206 invalidPublicKeyTests := []struct{ body, expectedErr string }{ 207 {"", "cannot decode public key: no data"}, 208 {"==", "cannot decode public key: .*"}, 209 {"stuff", "cannot decode public key: .*"}, 210 {"AnNpZw==", "unsupported public key format version: 2"}, 211 {"AUJST0tFTg==", "cannot decode public key: .*"}, 212 {spurious, "public key has spurious trailing data"}, 213 } 214 215 for _, test := range invalidPublicKeyTests { 216 invalid := headers + 217 fmt.Sprintf("body-length: %v", len(test.body)) + "\n" + 218 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 219 test.body + "\n\n" + 220 "AXNpZw==" 221 222 _, err := asserts.Decode([]byte(invalid)) 223 c.Check(err, ErrorMatches, accKeyErrPrefix+test.expectedErr) 224 } 225 } 226 227 func (aks *accountKeySuite) TestDecodeKeyIDMismatch(c *C) { 228 invalid := "type: account-key\n" + 229 "authority-id: canonical\n" + 230 "account-id: acc-id1\n" + 231 "name: default\n" + 232 "public-key-sha3-384: aa\n" + 233 aks.sinceLine + 234 aks.untilLine + 235 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 236 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 237 aks.pubKeyBody + "\n\n" + 238 "AXNpZw==" 239 240 _, err := asserts.Decode([]byte(invalid)) 241 c.Check(err, ErrorMatches, accKeyErrPrefix+"public key does not match provided key id") 242 } 243 244 func (aks *accountKeySuite) openDB(c *C) *asserts.Database { 245 trustedKey := testPrivKey0 246 247 topDir := filepath.Join(c.MkDir(), "asserts-db") 248 bs, err := asserts.OpenFSBackstore(topDir) 249 c.Assert(err, IsNil) 250 cfg := &asserts.DatabaseConfig{ 251 Backstore: bs, 252 Trusted: []asserts.Assertion{ 253 asserts.BootstrapAccountForTest("canonical"), 254 asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey()), 255 }, 256 } 257 db, err := asserts.OpenDatabase(cfg) 258 c.Assert(err, IsNil) 259 return db 260 } 261 262 func (aks *accountKeySuite) prereqAccount(c *C, db *asserts.Database) { 263 trustedKey := testPrivKey0 264 265 headers := map[string]interface{}{ 266 "authority-id": "canonical", 267 "display-name": "Acct1", 268 "account-id": "acc-id1", 269 "username": "acc-id1", 270 "validation": "unproven", 271 "timestamp": aks.since.Format(time.RFC3339), 272 } 273 acct1, err := asserts.AssembleAndSignInTest(asserts.AccountType, headers, nil, trustedKey) 274 c.Assert(err, IsNil) 275 276 // prereq 277 db.Add(acct1) 278 } 279 280 func (aks *accountKeySuite) TestAccountKeyCheck(c *C) { 281 trustedKey := testPrivKey0 282 283 headers := map[string]interface{}{ 284 "authority-id": "canonical", 285 "account-id": "acc-id1", 286 "name": "default", 287 "public-key-sha3-384": aks.keyID, 288 "since": aks.since.Format(time.RFC3339), 289 "until": aks.until.Format(time.RFC3339), 290 } 291 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 292 c.Assert(err, IsNil) 293 294 db := aks.openDB(c) 295 296 aks.prereqAccount(c, db) 297 298 err = db.Check(accKey) 299 c.Assert(err, IsNil) 300 } 301 302 func (aks *accountKeySuite) TestAccountKeyCheckNoAccount(c *C) { 303 trustedKey := testPrivKey0 304 305 headers := map[string]interface{}{ 306 "authority-id": "canonical", 307 "account-id": "acc-id1", 308 "name": "default", 309 "public-key-sha3-384": aks.keyID, 310 "since": aks.since.Format(time.RFC3339), 311 "until": aks.until.Format(time.RFC3339), 312 } 313 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 314 c.Assert(err, IsNil) 315 316 db := aks.openDB(c) 317 318 err = db.Check(accKey) 319 c.Assert(err, ErrorMatches, `account-key assertion for "acc-id1" does not have a matching account assertion`) 320 } 321 322 func (aks *accountKeySuite) TestAccountKeyCheckUntrustedAuthority(c *C) { 323 trustedKey := testPrivKey0 324 325 db := aks.openDB(c) 326 storeDB := assertstest.NewSigningDB("canonical", trustedKey) 327 otherDB := setup3rdPartySigning(c, "other", storeDB, db) 328 329 headers := map[string]interface{}{ 330 "account-id": "acc-id1", 331 "name": "default", 332 "public-key-sha3-384": aks.keyID, 333 "since": aks.since.Format(time.RFC3339), 334 "until": aks.until.Format(time.RFC3339), 335 } 336 accKey, err := otherDB.Sign(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), "") 337 c.Assert(err, IsNil) 338 339 err = db.Check(accKey) 340 c.Assert(err, ErrorMatches, `account-key assertion for "acc-id1" is not signed by a directly trusted authority:.*`) 341 } 342 343 func (aks *accountKeySuite) TestAccountKeyCheckSameNameAndNewRevision(c *C) { 344 trustedKey := testPrivKey0 345 346 headers := map[string]interface{}{ 347 "authority-id": "canonical", 348 "account-id": "acc-id1", 349 "name": "default", 350 "public-key-sha3-384": aks.keyID, 351 "since": aks.since.Format(time.RFC3339), 352 "until": aks.until.Format(time.RFC3339), 353 } 354 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 355 c.Assert(err, IsNil) 356 357 db := aks.openDB(c) 358 aks.prereqAccount(c, db) 359 360 err = db.Add(accKey) 361 c.Assert(err, IsNil) 362 363 headers["revision"] = "1" 364 newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 365 c.Assert(err, IsNil) 366 367 err = db.Check(newAccKey) 368 c.Assert(err, IsNil) 369 } 370 371 func (aks *accountKeySuite) TestAccountKeyCheckSameAccountAndDifferentName(c *C) { 372 trustedKey := testPrivKey0 373 374 headers := map[string]interface{}{ 375 "authority-id": "canonical", 376 "account-id": "acc-id1", 377 "name": "default", 378 "public-key-sha3-384": aks.keyID, 379 "since": aks.since.Format(time.RFC3339), 380 "until": aks.until.Format(time.RFC3339), 381 } 382 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 383 c.Assert(err, IsNil) 384 385 db := aks.openDB(c) 386 aks.prereqAccount(c, db) 387 388 err = db.Add(accKey) 389 c.Assert(err, IsNil) 390 391 newPrivKey, _ := assertstest.GenerateKey(752) 392 err = db.ImportKey(newPrivKey) 393 c.Assert(err, IsNil) 394 newPubKey, err := db.PublicKey(newPrivKey.PublicKey().ID()) 395 c.Assert(err, IsNil) 396 newPubKeyEncoded, err := asserts.EncodePublicKey(newPubKey) 397 c.Assert(err, IsNil) 398 399 headers["name"] = "another" 400 headers["public-key-sha3-384"] = newPubKey.ID() 401 newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, newPubKeyEncoded, trustedKey) 402 c.Assert(err, IsNil) 403 404 err = db.Check(newAccKey) 405 c.Assert(err, IsNil) 406 } 407 408 func (aks *accountKeySuite) TestAccountKeyCheckSameNameAndDifferentAccount(c *C) { 409 trustedKey := testPrivKey0 410 411 headers := map[string]interface{}{ 412 "authority-id": "canonical", 413 "account-id": "acc-id1", 414 "name": "default", 415 "public-key-sha3-384": aks.keyID, 416 "since": aks.since.Format(time.RFC3339), 417 "until": aks.until.Format(time.RFC3339), 418 } 419 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 420 c.Assert(err, IsNil) 421 422 db := aks.openDB(c) 423 err = db.ImportKey(trustedKey) 424 c.Assert(err, IsNil) 425 aks.prereqAccount(c, db) 426 427 err = db.Add(accKey) 428 c.Assert(err, IsNil) 429 430 newPrivKey, _ := assertstest.GenerateKey(752) 431 err = db.ImportKey(newPrivKey) 432 c.Assert(err, IsNil) 433 newPubKey, err := db.PublicKey(newPrivKey.PublicKey().ID()) 434 c.Assert(err, IsNil) 435 newPubKeyEncoded, err := asserts.EncodePublicKey(newPubKey) 436 c.Assert(err, IsNil) 437 438 acct2 := assertstest.NewAccount(db, "acc-id2", map[string]interface{}{ 439 "authority-id": "canonical", 440 "account-id": "acc-id2", 441 }, trustedKey.PublicKey().ID()) 442 db.Add(acct2) 443 444 headers["account-id"] = "acc-id2" 445 headers["public-key-sha3-384"] = newPubKey.ID() 446 headers["revision"] = "1" 447 newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, newPubKeyEncoded, trustedKey) 448 c.Assert(err, IsNil) 449 450 err = db.Check(newAccKey) 451 c.Assert(err, IsNil) 452 } 453 454 func (aks *accountKeySuite) TestAccountKeyCheckNameClash(c *C) { 455 trustedKey := testPrivKey0 456 457 headers := map[string]interface{}{ 458 "authority-id": "canonical", 459 "account-id": "acc-id1", 460 "name": "default", 461 "public-key-sha3-384": aks.keyID, 462 "since": aks.since.Format(time.RFC3339), 463 "until": aks.until.Format(time.RFC3339), 464 } 465 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 466 c.Assert(err, IsNil) 467 468 db := aks.openDB(c) 469 aks.prereqAccount(c, db) 470 471 err = db.Add(accKey) 472 c.Assert(err, IsNil) 473 474 newPrivKey, _ := assertstest.GenerateKey(752) 475 err = db.ImportKey(newPrivKey) 476 c.Assert(err, IsNil) 477 newPubKey, err := db.PublicKey(newPrivKey.PublicKey().ID()) 478 c.Assert(err, IsNil) 479 newPubKeyEncoded, err := asserts.EncodePublicKey(newPubKey) 480 c.Assert(err, IsNil) 481 482 headers["public-key-sha3-384"] = newPubKey.ID() 483 headers["revision"] = "1" 484 newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, newPubKeyEncoded, trustedKey) 485 c.Assert(err, IsNil) 486 487 err = db.Check(newAccKey) 488 c.Assert(err, ErrorMatches, fmt.Sprintf(`account-key assertion for "acc-id1" with ID %q has the same name "default" as existing ID %q`, newPubKey.ID(), aks.keyID)) 489 } 490 491 func (aks *accountKeySuite) TestAccountKeyAddAndFind(c *C) { 492 trustedKey := testPrivKey0 493 494 headers := map[string]interface{}{ 495 "authority-id": "canonical", 496 "account-id": "acc-id1", 497 "name": "default", 498 "public-key-sha3-384": aks.keyID, 499 "since": aks.since.Format(time.RFC3339), 500 "until": aks.until.Format(time.RFC3339), 501 } 502 accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) 503 c.Assert(err, IsNil) 504 505 db := aks.openDB(c) 506 507 aks.prereqAccount(c, db) 508 509 err = db.Add(accKey) 510 c.Assert(err, IsNil) 511 512 found, err := db.Find(asserts.AccountKeyType, map[string]string{ 513 "account-id": "acc-id1", 514 "public-key-sha3-384": aks.keyID, 515 }) 516 c.Assert(err, IsNil) 517 c.Assert(found, NotNil) 518 c.Check(found.Body(), DeepEquals, []byte(aks.pubKeyBody)) 519 } 520 521 func (aks *accountKeySuite) TestPublicKeyIsValidAt(c *C) { 522 // With since and until, i.e. signing account-key expires. 523 encoded := "type: account-key\n" + 524 "authority-id: canonical\n" + 525 "account-id: acc-id1\n" + 526 "name: default\n" + 527 "public-key-sha3-384: " + aks.keyID + "\n" + 528 aks.sinceLine + 529 aks.untilLine + 530 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 531 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 532 aks.pubKeyBody + "\n\n" + 533 "AXNpZw==" 534 a, err := asserts.Decode([]byte(encoded)) 535 c.Assert(err, IsNil) 536 537 accKey := a.(*asserts.AccountKey) 538 539 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since), Equals, true) 540 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, -1)), Equals, false) 541 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, 1)), Equals, true) 542 543 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until), Equals, false) 544 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until.AddDate(0, -1, 0)), Equals, true) 545 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until.AddDate(0, 1, 0)), Equals, false) 546 547 // With no until, i.e. signing account-key never expires. 548 encoded = "type: account-key\n" + 549 "authority-id: canonical\n" + 550 "account-id: acc-id1\n" + 551 "name: default\n" + 552 "public-key-sha3-384: " + aks.keyID + "\n" + 553 aks.sinceLine + 554 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 555 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 556 aks.pubKeyBody + "\n\n" + 557 "openpgp c2ln" 558 a, err = asserts.Decode([]byte(encoded)) 559 c.Assert(err, IsNil) 560 561 accKey = a.(*asserts.AccountKey) 562 563 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since), Equals, true) 564 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, -1)), Equals, false) 565 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, 1)), Equals, true) 566 567 // With since == until, i.e. signing account-key has been revoked. 568 encoded = "type: account-key\n" + 569 "authority-id: canonical\n" + 570 "account-id: acc-id1\n" + 571 "name: default\n" + 572 "public-key-sha3-384: " + aks.keyID + "\n" + 573 aks.sinceLine + 574 "until: " + aks.since.Format(time.RFC3339) + "\n" + 575 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 576 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 577 aks.pubKeyBody + "\n\n" + 578 "openpgp c2ln" 579 a, err = asserts.Decode([]byte(encoded)) 580 c.Assert(err, IsNil) 581 582 accKey = a.(*asserts.AccountKey) 583 584 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since), Equals, false) 585 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, -1)), Equals, false) 586 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.since.AddDate(0, 0, 1)), Equals, false) 587 588 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until), Equals, false) 589 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until.AddDate(0, -1, 0)), Equals, false) 590 c.Check(asserts.AccountKeyIsKeyValidAt(accKey, aks.until.AddDate(0, 1, 0)), Equals, false) 591 } 592 593 func (aks *accountKeySuite) TestPrerequisites(c *C) { 594 encoded := "type: account-key\n" + 595 "authority-id: canonical\n" + 596 "account-id: acc-id1\n" + 597 "name: default\n" + 598 "public-key-sha3-384: " + aks.keyID + "\n" + 599 aks.sinceLine + 600 aks.untilLine + 601 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 602 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + "\n\n" + 603 aks.pubKeyBody + "\n\n" + 604 "AXNpZw==" 605 a, err := asserts.Decode([]byte(encoded)) 606 c.Assert(err, IsNil) 607 608 prereqs := a.Prerequisites() 609 c.Assert(prereqs, HasLen, 1) 610 c.Check(prereqs[0], DeepEquals, &asserts.Ref{ 611 Type: asserts.AccountType, 612 PrimaryKey: []string{"acc-id1"}, 613 }) 614 } 615 616 func (aks *accountKeySuite) TestAccountKeyRequestHappy(c *C) { 617 akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, 618 map[string]interface{}{ 619 "account-id": "acc-id1", 620 "name": "default", 621 "public-key-sha3-384": aks.keyID, 622 "since": aks.since.Format(time.RFC3339), 623 }, []byte(aks.pubKeyBody), aks.privKey) 624 c.Assert(err, IsNil) 625 626 // roundtrip 627 a, err := asserts.Decode(asserts.Encode(akr)) 628 c.Assert(err, IsNil) 629 630 akr2, ok := a.(*asserts.AccountKeyRequest) 631 c.Assert(ok, Equals, true) 632 633 db := aks.openDB(c) 634 aks.prereqAccount(c, db) 635 636 err = db.Check(akr2) 637 c.Check(err, IsNil) 638 639 c.Check(akr2.AccountID(), Equals, "acc-id1") 640 c.Check(akr2.Name(), Equals, "default") 641 c.Check(akr2.PublicKeyID(), Equals, aks.keyID) 642 c.Check(akr2.Since(), Equals, aks.since) 643 } 644 645 func (aks *accountKeySuite) TestAccountKeyRequestUntil(c *C) { 646 db := aks.openDB(c) 647 aks.prereqAccount(c, db) 648 649 tests := []struct { 650 untilHeader string 651 until time.Time 652 }{ 653 {"", time.Time{}}, // zero time default 654 {aks.until.Format(time.RFC3339), aks.until}, // in the future 655 {aks.since.Format(time.RFC3339), aks.since}, // same as since 656 } 657 658 for _, test := range tests { 659 c.Log(test) 660 headers := map[string]interface{}{ 661 "account-id": "acc-id1", 662 "name": "default", 663 "public-key-sha3-384": aks.keyID, 664 "since": aks.since.Format(time.RFC3339), 665 } 666 if test.untilHeader != "" { 667 headers["until"] = test.untilHeader 668 } 669 akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, headers, []byte(aks.pubKeyBody), aks.privKey) 670 c.Assert(err, IsNil) 671 a, err := asserts.Decode(asserts.Encode(akr)) 672 c.Assert(err, IsNil) 673 akr2 := a.(*asserts.AccountKeyRequest) 674 c.Check(akr2.Until(), Equals, test.until) 675 err = db.Check(akr2) 676 c.Check(err, IsNil) 677 } 678 } 679 680 func (aks *accountKeySuite) TestAccountKeyRequestAddAndFind(c *C) { 681 akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, 682 map[string]interface{}{ 683 "account-id": "acc-id1", 684 "name": "default", 685 "public-key-sha3-384": aks.keyID, 686 "since": aks.since.Format(time.RFC3339), 687 }, []byte(aks.pubKeyBody), aks.privKey) 688 c.Assert(err, IsNil) 689 690 db := aks.openDB(c) 691 aks.prereqAccount(c, db) 692 693 err = db.Add(akr) 694 c.Assert(err, IsNil) 695 696 found, err := db.Find(asserts.AccountKeyRequestType, map[string]string{ 697 "account-id": "acc-id1", 698 "public-key-sha3-384": aks.keyID, 699 }) 700 c.Assert(err, IsNil) 701 c.Assert(found, NotNil) 702 c.Check(found.Body(), DeepEquals, []byte(aks.pubKeyBody)) 703 } 704 705 func (aks *accountKeySuite) TestAccountKeyRequestDecodeInvalid(c *C) { 706 encoded := "type: account-key-request\n" + 707 "account-id: acc-id1\n" + 708 "name: default\n" + 709 "public-key-sha3-384: " + aks.keyID + "\n" + 710 aks.sinceLine + 711 aks.untilLine + 712 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 713 "sign-key-sha3-384: " + aks.privKey.PublicKey().ID() + "\n\n" + 714 aks.pubKeyBody + "\n\n" + 715 "AXNpZw==" 716 717 untilPast := aks.since.AddDate(-1, 0, 0) 718 untilPastLine := "until: " + untilPast.Format(time.RFC3339) + "\n" 719 720 invalidTests := []struct{ original, invalid, expectedErr string }{ 721 {"account-id: acc-id1\n", "", `"account-id" header is mandatory`}, 722 {"account-id: acc-id1\n", "account-id: \n", `"account-id" header should not be empty`}, 723 {"name: default\n", "", `"name" header is mandatory`}, 724 {"name: default\n", "name: \n", `"name" header should not be empty`}, 725 {"name: default\n", "name: a b\n", `"name" header contains invalid characters: "a b"`}, 726 {"name: default\n", "name: -default\n", `"name" header contains invalid characters: "-default"`}, 727 {"name: default\n", "name: foo:bar\n", `"name" header contains invalid characters: "foo:bar"`}, 728 {"public-key-sha3-384: " + aks.keyID + "\n", "", `"public-key-sha3-384" header is mandatory`}, 729 {"public-key-sha3-384: " + aks.keyID + "\n", "public-key-sha3-384: \n", `"public-key-sha3-384" header should not be empty`}, 730 {aks.sinceLine, "", `"since" header is mandatory`}, 731 {aks.sinceLine, "since: \n", `"since" header should not be empty`}, 732 {aks.sinceLine, "since: 12:30\n", `"since" header is not a RFC3339 date: .*`}, 733 {aks.sinceLine, "since: \n", `"since" header should not be empty`}, 734 {aks.untilLine, "until: \n", `"until" header is not a RFC3339 date: .*`}, 735 {aks.untilLine, "until: 12:30\n", `"until" header is not a RFC3339 date: .*`}, 736 {aks.untilLine, untilPastLine, `'until' time cannot be before 'since' time`}, 737 } 738 739 for _, test := range invalidTests { 740 invalid := strings.Replace(encoded, test.original, test.invalid, 1) 741 _, err := asserts.Decode([]byte(invalid)) 742 c.Check(err, ErrorMatches, accKeyReqErrPrefix+test.expectedErr) 743 } 744 } 745 746 func (aks *accountKeySuite) TestAccountKeyRequestDecodeInvalidPublicKey(c *C) { 747 headers := "type: account-key-request\n" + 748 "account-id: acc-id1\n" + 749 "name: default\n" + 750 "public-key-sha3-384: " + aks.keyID + "\n" + 751 aks.sinceLine + 752 aks.untilLine 753 754 raw, err := base64.StdEncoding.DecodeString(aks.pubKeyBody) 755 c.Assert(err, IsNil) 756 spurious := base64.StdEncoding.EncodeToString(append(raw, "gorp"...)) 757 758 invalidPublicKeyTests := []struct{ body, expectedErr string }{ 759 {"", "cannot decode public key: no data"}, 760 {"==", "cannot decode public key: .*"}, 761 {"stuff", "cannot decode public key: .*"}, 762 {"AnNpZw==", "unsupported public key format version: 2"}, 763 {"AUJST0tFTg==", "cannot decode public key: .*"}, 764 {spurious, "public key has spurious trailing data"}, 765 } 766 767 for _, test := range invalidPublicKeyTests { 768 invalid := headers + 769 fmt.Sprintf("body-length: %v", len(test.body)) + "\n" + 770 "sign-key-sha3-384: " + aks.privKey.PublicKey().ID() + "\n\n" + 771 test.body + "\n\n" + 772 "AXNpZw==" 773 774 _, err := asserts.Decode([]byte(invalid)) 775 c.Check(err, ErrorMatches, accKeyReqErrPrefix+test.expectedErr) 776 } 777 } 778 779 func (aks *accountKeySuite) TestAccountKeyRequestDecodeKeyIDMismatch(c *C) { 780 invalid := "type: account-key-request\n" + 781 "account-id: acc-id1\n" + 782 "name: default\n" + 783 "public-key-sha3-384: aa\n" + 784 aks.sinceLine + 785 aks.untilLine + 786 fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n" + 787 "sign-key-sha3-384: " + aks.privKey.PublicKey().ID() + "\n\n" + 788 aks.pubKeyBody + "\n\n" + 789 "AXNpZw==" 790 791 _, err := asserts.Decode([]byte(invalid)) 792 c.Check(err, ErrorMatches, "assertion account-key-request: public key does not match provided key id") 793 } 794 795 func (aks *accountKeySuite) TestAccountKeyRequestNoAccount(c *C) { 796 headers := map[string]interface{}{ 797 "account-id": "acc-id1", 798 "name": "default", 799 "public-key-sha3-384": aks.keyID, 800 "since": aks.since.Format(time.RFC3339), 801 } 802 akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, headers, []byte(aks.pubKeyBody), aks.privKey) 803 c.Assert(err, IsNil) 804 805 db := aks.openDB(c) 806 807 err = db.Check(akr) 808 c.Assert(err, ErrorMatches, `account-key-request assertion for "acc-id1" does not have a matching account assertion`) 809 }