gitee.com/mysnapcore/mysnapd@v0.1.0/asserts/asserts_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 "io" 25 "strings" 26 27 . "gopkg.in/check.v1" 28 29 "gitee.com/mysnapcore/mysnapd/asserts" 30 ) 31 32 type assertsSuite struct{} 33 34 var _ = Suite(&assertsSuite{}) 35 36 func (as *assertsSuite) TestType(c *C) { 37 c.Check(asserts.Type("test-only"), Equals, asserts.TestOnlyType) 38 } 39 40 func (as *assertsSuite) TestUnknown(c *C) { 41 c.Check(asserts.Type(""), IsNil) 42 c.Check(asserts.Type("unknown"), IsNil) 43 } 44 45 func (as *assertsSuite) TestTypeMaxSupportedFormat(c *C) { 46 c.Check(asserts.Type("test-only").MaxSupportedFormat(), Equals, 1) 47 } 48 49 func (as *assertsSuite) TestTypeNames(c *C) { 50 c.Check(asserts.TypeNames(), DeepEquals, []string{ 51 "account", 52 "account-key", 53 "account-key-request", 54 // XXX "authority-delegation", 55 "base-declaration", 56 "device-session-request", 57 "model", 58 "preseed", 59 "repair", 60 "serial", 61 "serial-request", 62 "snap-build", 63 "snap-declaration", 64 "snap-developer", 65 "snap-revision", 66 "store", 67 "system-user", 68 "test-only", 69 "test-only-2", 70 "test-only-decl", 71 "test-only-no-authority", 72 "test-only-no-authority-pk", 73 "test-only-rev", 74 "test-only-seq", 75 "validation", 76 "validation-set", 77 }) 78 } 79 80 func (as *assertsSuite) TestMaxSupportedFormats(c *C) { 81 snapDeclMaxFormat := asserts.SnapDeclarationType.MaxSupportedFormat() 82 systemUserMaxFormat := asserts.SystemUserType.MaxSupportedFormat() 83 // validity 84 c.Check(snapDeclMaxFormat >= 4, Equals, true) 85 c.Check(systemUserMaxFormat >= 2, Equals, true) 86 c.Check(asserts.MaxSupportedFormats(1), DeepEquals, map[string]int{ 87 "snap-declaration": snapDeclMaxFormat, 88 "system-user": systemUserMaxFormat, 89 "test-only": 1, 90 "test-only-seq": 2, 91 }) 92 93 // all 94 maxFormats := asserts.MaxSupportedFormats(0) 95 c.Assert(maxFormats, HasLen, len(asserts.TypeNames())) 96 c.Check(maxFormats["test-only"], Equals, 1) 97 c.Check(maxFormats["test-only-2"], Equals, 0) 98 c.Check(maxFormats["snap-declaration"], Equals, snapDeclMaxFormat) 99 } 100 101 func (as *assertsSuite) TestSuggestFormat(c *C) { 102 fmtnum, err := asserts.SuggestFormat(asserts.Type("test-only-2"), nil, nil) 103 c.Assert(err, IsNil) 104 c.Check(fmtnum, Equals, 0) 105 } 106 107 func (as *assertsSuite) TestPrimaryKeyHelpers(c *C) { 108 headers, err := asserts.HeadersFromPrimaryKey(asserts.TestOnlyType, []string{"one"}) 109 c.Assert(err, IsNil) 110 c.Check(headers, DeepEquals, map[string]string{ 111 "primary-key": "one", 112 }) 113 114 headers, err = asserts.HeadersFromPrimaryKey(asserts.TestOnly2Type, []string{"bar", "baz"}) 115 c.Assert(err, IsNil) 116 c.Check(headers, DeepEquals, map[string]string{ 117 "pk1": "bar", 118 "pk2": "baz", 119 }) 120 121 _, err = asserts.HeadersFromPrimaryKey(asserts.TestOnly2Type, []string{"bar"}) 122 c.Check(err, ErrorMatches, `primary key has wrong length for "test-only-2" assertion`) 123 124 _, err = asserts.HeadersFromPrimaryKey(asserts.TestOnly2Type, []string{"", "baz"}) 125 c.Check(err, ErrorMatches, `primary key "pk1" header cannot be empty`) 126 127 pk, err := asserts.PrimaryKeyFromHeaders(asserts.TestOnly2Type, headers) 128 c.Assert(err, IsNil) 129 c.Check(pk, DeepEquals, []string{"bar", "baz"}) 130 131 headers["other"] = "foo" 132 pk1, err := asserts.PrimaryKeyFromHeaders(asserts.TestOnly2Type, headers) 133 c.Assert(err, IsNil) 134 c.Check(pk1, DeepEquals, pk) 135 136 delete(headers, "pk2") 137 _, err = asserts.PrimaryKeyFromHeaders(asserts.TestOnly2Type, headers) 138 c.Check(err, ErrorMatches, `must provide primary key: pk2`) 139 } 140 141 func (as *assertsSuite) TestPrimaryKeyHelpersOptionalPrimaryKeys(c *C) { 142 // optional primary key headers 143 r := asserts.MockOptionalPrimaryKey(asserts.TestOnlyType, "opt1", "o1-defl") 144 defer r() 145 146 pk, err := asserts.PrimaryKeyFromHeaders(asserts.TestOnlyType, map[string]string{"primary-key": "k1"}) 147 c.Assert(err, IsNil) 148 c.Check(pk, DeepEquals, []string{"k1", "o1-defl"}) 149 150 pk, err = asserts.PrimaryKeyFromHeaders(asserts.TestOnlyType, map[string]string{"primary-key": "k1", "opt1": "B"}) 151 c.Assert(err, IsNil) 152 c.Check(pk, DeepEquals, []string{"k1", "B"}) 153 154 hdrs, err := asserts.HeadersFromPrimaryKey(asserts.TestOnlyType, []string{"k1", "B"}) 155 c.Assert(err, IsNil) 156 c.Check(hdrs, DeepEquals, map[string]string{ 157 "primary-key": "k1", 158 "opt1": "B", 159 }) 160 161 hdrs, err = asserts.HeadersFromPrimaryKey(asserts.TestOnlyType, []string{"k1"}) 162 c.Assert(err, IsNil) 163 c.Check(hdrs, DeepEquals, map[string]string{ 164 "primary-key": "k1", 165 "opt1": "o1-defl", 166 }) 167 168 _, err = asserts.HeadersFromPrimaryKey(asserts.TestOnlyType, nil) 169 c.Check(err, ErrorMatches, `primary key has wrong length for "test-only" assertion`) 170 171 _, err = asserts.HeadersFromPrimaryKey(asserts.TestOnlyType, []string{"pk", "opt1", "what"}) 172 c.Check(err, ErrorMatches, `primary key has wrong length for "test-only" assertion`) 173 } 174 175 func (as *assertsSuite) TestRef(c *C) { 176 ref := &asserts.Ref{ 177 Type: asserts.TestOnly2Type, 178 PrimaryKey: []string{"abc", "xyz"}, 179 } 180 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz") 181 } 182 183 func (as *assertsSuite) TestRefString(c *C) { 184 ref := &asserts.Ref{ 185 Type: asserts.AccountType, 186 PrimaryKey: []string{"canonical"}, 187 } 188 189 c.Check(ref.String(), Equals, "account (canonical)") 190 191 ref = &asserts.Ref{ 192 Type: asserts.SnapDeclarationType, 193 PrimaryKey: []string{"18", "SNAPID"}, 194 } 195 196 c.Check(ref.String(), Equals, "snap-declaration (SNAPID; series:18)") 197 198 ref = &asserts.Ref{ 199 Type: asserts.ModelType, 200 PrimaryKey: []string{"18", "BRAND", "baz-3000"}, 201 } 202 203 c.Check(ref.String(), Equals, "model (baz-3000; series:18 brand-id:BRAND)") 204 205 // broken primary key 206 ref = &asserts.Ref{ 207 Type: asserts.ModelType, 208 PrimaryKey: []string{"18"}, 209 } 210 c.Check(ref.String(), Equals, "model (???)") 211 212 ref = &asserts.Ref{ 213 Type: asserts.TestOnlyNoAuthorityType, 214 } 215 c.Check(ref.String(), Equals, "test-only-no-authority (-)") 216 } 217 218 func (as *assertsSuite) TestRefResolveError(c *C) { 219 ref := &asserts.Ref{ 220 Type: asserts.TestOnly2Type, 221 PrimaryKey: []string{"abc"}, 222 } 223 _, err := ref.Resolve(nil) 224 c.Check(err, ErrorMatches, `"test-only-2" assertion reference primary key has the wrong length \(expected \[pk1 pk2\]\): \[abc\]`) 225 } 226 227 func (as *assertsSuite) TestReducePrimaryKey(c *C) { 228 // optional primary key headers 229 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt1", "o1-defl")() 230 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt2", "o2-defl")() 231 232 tests := []struct { 233 pk []string 234 reduced []string 235 }{ 236 {nil, nil}, 237 {[]string{"k1"}, []string{"k1"}}, 238 {[]string{"k1", "k2"}, []string{"k1", "k2"}}, 239 {[]string{"k1", "k2", "A"}, []string{"k1", "k2", "A"}}, 240 {[]string{"k1", "k2", "o1-defl"}, []string{"k1", "k2"}}, 241 {[]string{"k1", "k2", "A", "o2-defl"}, []string{"k1", "k2", "A"}}, 242 {[]string{"k1", "k2", "A", "B"}, []string{"k1", "k2", "A", "B"}}, 243 {[]string{"k1", "k2", "o1-defl", "B"}, []string{"k1", "k2", "o1-defl", "B"}}, 244 {[]string{"k1", "k2", "o1-defl", "o2-defl"}, []string{"k1", "k2"}}, 245 {[]string{"k1", "k2", "o1-defl", "o2-defl", "what"}, []string{"k1", "k2", "o1-defl", "o2-defl", "what"}}, 246 } 247 248 for _, t := range tests { 249 c.Check(asserts.ReducePrimaryKey(asserts.TestOnly2Type, t.pk), DeepEquals, t.reduced) 250 } 251 } 252 253 func (as *assertsSuite) TestRefOptionalPrimaryKeys(c *C) { 254 // optional primary key headers 255 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt1", "o1-defl")() 256 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt2", "o2-defl")() 257 258 ref := &asserts.Ref{ 259 Type: asserts.TestOnly2Type, 260 PrimaryKey: []string{"abc", "xyz"}, 261 } 262 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz") 263 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc)`) 264 265 ref = &asserts.Ref{ 266 Type: asserts.TestOnly2Type, 267 PrimaryKey: []string{"abc", "xyz", "o1-defl"}, 268 } 269 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz") 270 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc)`) 271 272 ref = &asserts.Ref{ 273 Type: asserts.TestOnly2Type, 274 PrimaryKey: []string{"abc", "xyz", "o1-defl", "o2-defl"}, 275 } 276 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz") 277 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc)`) 278 279 ref = &asserts.Ref{ 280 Type: asserts.TestOnly2Type, 281 PrimaryKey: []string{"abc", "xyz", "A"}, 282 } 283 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz/A") 284 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc opt1:A)`) 285 286 ref = &asserts.Ref{ 287 Type: asserts.TestOnly2Type, 288 PrimaryKey: []string{"abc", "xyz", "A", "o2-defl"}, 289 } 290 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz/A") 291 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc opt1:A)`) 292 293 ref = &asserts.Ref{ 294 Type: asserts.TestOnly2Type, 295 PrimaryKey: []string{"abc", "xyz", "o1-defl", "B"}, 296 } 297 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz/o1-defl/B") 298 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc opt2:B)`) 299 300 ref = &asserts.Ref{ 301 Type: asserts.TestOnly2Type, 302 PrimaryKey: []string{"abc", "xyz", "A", "B"}, 303 } 304 c.Check(ref.Unique(), Equals, "test-only-2/abc/xyz/A/B") 305 c.Check(ref.String(), Equals, `test-only-2 (xyz; pk1:abc opt1:A opt2:B)`) 306 } 307 308 func (as *assertsSuite) TestAcceptablePrimaryKey(c *C) { 309 // optional primary key headers 310 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt1", "o1-defl")() 311 defer asserts.MockOptionalPrimaryKey(asserts.TestOnly2Type, "opt2", "o2-defl")() 312 313 tests := []struct { 314 pk []string 315 ok bool 316 }{ 317 {nil, false}, 318 {[]string{"k1"}, false}, 319 {[]string{"k1", "k2"}, true}, 320 {[]string{"k1", "k2", "A"}, true}, 321 {[]string{"k1", "k2", "o1-defl"}, true}, 322 {[]string{"k1", "k2", "A", "B"}, true}, 323 {[]string{"k1", "k2", "o1-defl", "o2-defl", "what"}, false}, 324 } 325 326 for _, t := range tests { 327 c.Check(asserts.TestOnly2Type.AcceptablePrimaryKey(t.pk), Equals, t.ok) 328 } 329 } 330 331 func (as *assertsSuite) TestAtRevisionString(c *C) { 332 ref := asserts.Ref{ 333 Type: asserts.AccountType, 334 PrimaryKey: []string{"canonical"}, 335 } 336 337 at := &asserts.AtRevision{ 338 Ref: ref, 339 } 340 c.Check(at.String(), Equals, "account (canonical) at revision 0") 341 342 at = &asserts.AtRevision{ 343 Ref: ref, 344 Revision: asserts.RevisionNotKnown, 345 } 346 c.Check(at.String(), Equals, "account (canonical)") 347 } 348 349 const exKeyID = "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" 350 351 const exampleEmptyBodyAllDefaults = "type: test-only\n" + 352 "authority-id: auth-id1\n" + 353 "primary-key: abc\n" + 354 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 355 "\n\n" + 356 "AXNpZw==" 357 358 func (as *assertsSuite) TestDecodeEmptyBodyAllDefaults(c *C) { 359 a, err := asserts.Decode([]byte(exampleEmptyBodyAllDefaults)) 360 c.Assert(err, IsNil) 361 c.Check(a.Type(), Equals, asserts.TestOnlyType) 362 _, ok := a.(*asserts.TestOnly) 363 c.Check(ok, Equals, true) 364 c.Check(a.Revision(), Equals, 0) 365 c.Check(a.Format(), Equals, 0) 366 c.Check(a.Body(), IsNil) 367 c.Check(a.Header("header1"), IsNil) 368 c.Check(a.HeaderString("header1"), Equals, "") 369 c.Check(a.AuthorityID(), Equals, "auth-id1") 370 c.Check(a.SignKeyID(), Equals, exKeyID) 371 } 372 373 const exampleEmptyBodyOptionalPrimaryKeySet = "type: test-only\n" + 374 "authority-id: auth-id1\n" + 375 "primary-key: abc\n" + 376 "opt1: A\n" + 377 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 378 "\n\n" + 379 "AXNpZw==" 380 381 func (as *assertsSuite) TestDecodeOptionalPrimaryKeys(c *C) { 382 r := asserts.MockOptionalPrimaryKey(asserts.TestOnlyType, "opt1", "o1-defl") 383 defer r() 384 385 a, err := asserts.Decode([]byte(exampleEmptyBodyAllDefaults)) 386 c.Assert(err, IsNil) 387 c.Check(a.Type(), Equals, asserts.TestOnlyType) 388 _, ok := a.(*asserts.TestOnly) 389 c.Check(ok, Equals, true) 390 c.Check(a.Revision(), Equals, 0) 391 c.Check(a.Format(), Equals, 0) 392 c.Check(a.Body(), IsNil) 393 c.Check(a.HeaderString("opt1"), Equals, "o1-defl") 394 c.Check(a.Header("header1"), IsNil) 395 c.Check(a.HeaderString("header1"), Equals, "") 396 c.Check(a.AuthorityID(), Equals, "auth-id1") 397 c.Check(a.SignKeyID(), Equals, exKeyID) 398 399 a, err = asserts.Decode([]byte(exampleEmptyBodyOptionalPrimaryKeySet)) 400 c.Assert(err, IsNil) 401 c.Check(a.Type(), Equals, asserts.TestOnlyType) 402 _, ok = a.(*asserts.TestOnly) 403 c.Check(ok, Equals, true) 404 c.Check(a.Revision(), Equals, 0) 405 c.Check(a.Format(), Equals, 0) 406 c.Check(a.Body(), IsNil) 407 c.Check(a.HeaderString("opt1"), Equals, "A") 408 c.Check(a.Header("header1"), IsNil) 409 c.Check(a.HeaderString("header1"), Equals, "") 410 c.Check(a.AuthorityID(), Equals, "auth-id1") 411 c.Check(a.SignKeyID(), Equals, exKeyID) 412 } 413 414 const exampleEmptyBody2NlNl = "type: test-only\n" + 415 "authority-id: auth-id1\n" + 416 "primary-key: xyz\n" + 417 "revision: 0\n" + 418 "body-length: 0\n" + 419 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 420 "\n\n" + 421 "\n\n" + 422 "AXNpZw==\n" 423 424 func (as *assertsSuite) TestDecodeEmptyBodyNormalize2NlNl(c *C) { 425 a, err := asserts.Decode([]byte(exampleEmptyBody2NlNl)) 426 c.Assert(err, IsNil) 427 c.Check(a.Type(), Equals, asserts.TestOnlyType) 428 c.Check(a.Revision(), Equals, 0) 429 c.Check(a.Format(), Equals, 0) 430 c.Check(a.Body(), IsNil) 431 } 432 433 const exampleBodyAndExtraHeaders = "type: test-only\n" + 434 "format: 1\n" + 435 "authority-id: auth-id2\n" + 436 "primary-key: abc\n" + 437 "revision: 5\n" + 438 "header1: value1\n" + 439 "header2: value2\n" + 440 "body-length: 8\n" + 441 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 442 "THE-BODY" + 443 "\n\n" + 444 "AXNpZw==\n" 445 446 func (as *assertsSuite) TestDecodeWithABodyAndExtraHeaders(c *C) { 447 a, err := asserts.Decode([]byte(exampleBodyAndExtraHeaders)) 448 c.Assert(err, IsNil) 449 c.Check(a.Type(), Equals, asserts.TestOnlyType) 450 c.Check(a.AuthorityID(), Equals, "auth-id2") 451 c.Check(a.SignKeyID(), Equals, exKeyID) 452 c.Check(a.Header("primary-key"), Equals, "abc") 453 c.Check(a.Revision(), Equals, 5) 454 c.Check(a.Format(), Equals, 1) 455 c.Check(a.SupportedFormat(), Equals, true) 456 c.Check(a.Header("header1"), Equals, "value1") 457 c.Check(a.Header("header2"), Equals, "value2") 458 c.Check(a.Body(), DeepEquals, []byte("THE-BODY")) 459 460 } 461 462 const exampleUnsupportedFormat = "type: test-only\n" + 463 "format: 77\n" + 464 "authority-id: auth-id2\n" + 465 "primary-key: abc\n" + 466 "revision: 5\n" + 467 "header1: value1\n" + 468 "header2: value2\n" + 469 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 470 "AXNpZw==\n" 471 472 func (as *assertsSuite) TestDecodeUnsupportedFormat(c *C) { 473 a, err := asserts.Decode([]byte(exampleUnsupportedFormat)) 474 c.Assert(err, IsNil) 475 c.Check(a.Type(), Equals, asserts.TestOnlyType) 476 c.Check(a.AuthorityID(), Equals, "auth-id2") 477 c.Check(a.SignKeyID(), Equals, exKeyID) 478 c.Check(a.Header("primary-key"), Equals, "abc") 479 c.Check(a.Revision(), Equals, 5) 480 c.Check(a.Format(), Equals, 77) 481 c.Check(a.SupportedFormat(), Equals, false) 482 } 483 484 func (as *assertsSuite) TestDecodeGetSignatureBits(c *C) { 485 content := "type: test-only\n" + 486 "authority-id: auth-id1\n" + 487 "primary-key: xyz\n" + 488 "revision: 5\n" + 489 "header1: value1\n" + 490 "body-length: 8\n" + 491 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 492 "THE-BODY" 493 encoded := content + 494 "\n\n" + 495 "AXNpZw==" 496 a, err := asserts.Decode([]byte(encoded)) 497 c.Assert(err, IsNil) 498 c.Check(a.Type(), Equals, asserts.TestOnlyType) 499 c.Check(a.AuthorityID(), Equals, "auth-id1") 500 c.Check(a.SignKeyID(), Equals, exKeyID) 501 cont, signature := a.Signature() 502 c.Check(signature, DeepEquals, []byte("AXNpZw==")) 503 c.Check(cont, DeepEquals, []byte(content)) 504 } 505 506 func (as *assertsSuite) TestDecodeNoSignatureSplit(c *C) { 507 for _, encoded := range []string{"", "foo"} { 508 _, err := asserts.Decode([]byte(encoded)) 509 c.Check(err, ErrorMatches, "assertion content/signature separator not found") 510 } 511 } 512 513 func (as *assertsSuite) TestDecodeHeaderParsingErrors(c *C) { 514 headerParsingErrorsTests := []struct{ encoded, expectedErr string }{ 515 {string([]byte{255, '\n', '\n'}), "header is not utf8"}, 516 {"foo: a\nbar\n\n", `header entry missing ':' separator: "bar"`}, 517 {"TYPE: foo\n\n", `invalid header name: "TYPE"`}, 518 {"foo: a\nbar:>\n\n", `header entry should have a space or newline \(for multiline\) before value: "bar:>"`}, 519 {"foo: a\nbar:\n\n", `expected 4 chars nesting prefix after multiline introduction "bar:": EOF`}, 520 {"foo: a\nbar:\nbaz: x\n\n", `expected 4 chars nesting prefix after multiline introduction "bar:": "baz: x"`}, 521 {"foo: a:\nbar: b\nfoo: x\n\n", `repeated header: "foo"`}, 522 } 523 524 for _, test := range headerParsingErrorsTests { 525 _, err := asserts.Decode([]byte(test.encoded)) 526 c.Check(err, ErrorMatches, "parsing assertion headers: "+test.expectedErr) 527 } 528 } 529 530 func (as *assertsSuite) TestDecodeInvalid(c *C) { 531 keyIDHdr := "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n" 532 encoded := "type: test-only\n" + 533 "format: 0\n" + 534 "authority-id: auth-id\n" + 535 "primary-key: abc\n" + 536 "revision: 0\n" + 537 "body-length: 5\n" + 538 keyIDHdr + 539 "\n" + 540 "abcde" + 541 "\n\n" + 542 "AXNpZw==" 543 544 invalidAssertTests := []struct{ original, invalid, expectedErr string }{ 545 {"body-length: 5", "body-length: z", `assertion: "body-length" header is not an integer: z`}, 546 {"body-length: 5", "body-length: 3", "assertion body length and declared body-length don't match: 5 != 3"}, 547 {"authority-id: auth-id\n", "", `assertion: "authority-id" header is mandatory`}, 548 {"authority-id: auth-id\n", "authority-id: \n", `assertion: "authority-id" header should not be empty`}, 549 {keyIDHdr, "", `assertion: "sign-key-sha3-384" header is mandatory`}, 550 {keyIDHdr, "sign-key-sha3-384: \n", `assertion: "sign-key-sha3-384" header should not be empty`}, 551 {keyIDHdr, "sign-key-sha3-384: $\n", `assertion: "sign-key-sha3-384" header cannot be decoded: .*`}, 552 {keyIDHdr, "sign-key-sha3-384: eHl6\n", `assertion: "sign-key-sha3-384" header does not have the expected bit length: 24`}, 553 {"AXNpZw==", "", "empty assertion signature"}, 554 {"type: test-only\n", "", `assertion: "type" header is mandatory`}, 555 {"type: test-only\n", "type: unknown\n", `unknown assertion type: "unknown"`}, 556 {"revision: 0\n", "revision: Z\n", `assertion: "revision" header is not an integer: Z`}, 557 {"revision: 0\n", "revision:\n - 1\n", `assertion: "revision" header is not an integer: \[1\]`}, 558 {"revision: 0\n", "revision: 00\n", `assertion: "revision" header has invalid prefix zeros: 00`}, 559 {"revision: 0\n", "revision: -10\n", "assertion: revision should be positive: -10"}, 560 {"revision: 0\n", "revision: 99999999999999999999\n", `assertion: "revision" header is out of range: 99999999999999999999`}, 561 {"format: 0\n", "format: Z\n", `assertion: "format" header is not an integer: Z`}, 562 {"format: 0\n", "format: -10\n", "assertion: format should be positive: -10"}, 563 {"primary-key: abc\n", "", `assertion test-only: "primary-key" header is mandatory`}, 564 {"primary-key: abc\n", "primary-key:\n - abc\n", `assertion test-only: "primary-key" header must be a string`}, 565 {"primary-key: abc\n", "primary-key: a/c\n", `assertion test-only: "primary-key" primary key header cannot contain '/'`}, 566 {"abcde", "ab\xffde", "assertion body is not utf8"}, 567 } 568 569 for _, test := range invalidAssertTests { 570 invalid := strings.Replace(encoded, test.original, test.invalid, 1) 571 _, err := asserts.Decode([]byte(invalid)) 572 c.Check(err, ErrorMatches, test.expectedErr) 573 } 574 } 575 576 func (as *assertsSuite) TestDecodeNoAuthorityInvalid(c *C) { 577 invalid := "type: test-only-no-authority\n" + 578 "authority-id: auth-id1\n" + 579 "hdr: FOO\n" + 580 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 581 "\n\n" + 582 "openpgp c2ln" 583 584 _, err := asserts.Decode([]byte(invalid)) 585 c.Check(err, ErrorMatches, `"test-only-no-authority" assertion cannot have authority-id set`) 586 } 587 588 func checkContent(c *C, a asserts.Assertion, encoded string) { 589 expected, err := asserts.Decode([]byte(encoded)) 590 c.Assert(err, IsNil) 591 expectedCont, _ := expected.Signature() 592 593 cont, _ := a.Signature() 594 c.Check(cont, DeepEquals, expectedCont) 595 } 596 597 func (as *assertsSuite) TestEncoderDecoderHappy(c *C) { 598 stream := new(bytes.Buffer) 599 enc := asserts.NewEncoder(stream) 600 enc.WriteEncoded([]byte(exampleEmptyBody2NlNl)) 601 enc.WriteEncoded([]byte(exampleBodyAndExtraHeaders)) 602 enc.WriteEncoded([]byte(exampleEmptyBodyAllDefaults)) 603 604 decoder := asserts.NewDecoder(stream) 605 a, err := decoder.Decode() 606 c.Assert(err, IsNil) 607 c.Check(a.Type(), Equals, asserts.TestOnlyType) 608 _, ok := a.(*asserts.TestOnly) 609 c.Check(ok, Equals, true) 610 checkContent(c, a, exampleEmptyBody2NlNl) 611 612 a, err = decoder.Decode() 613 c.Assert(err, IsNil) 614 checkContent(c, a, exampleBodyAndExtraHeaders) 615 616 a, err = decoder.Decode() 617 c.Assert(err, IsNil) 618 checkContent(c, a, exampleEmptyBodyAllDefaults) 619 620 a, err = decoder.Decode() 621 c.Assert(err, Equals, io.EOF) 622 c.Check(a, IsNil) 623 } 624 625 func (as *assertsSuite) TestDecodeEmptyStream(c *C) { 626 stream := new(bytes.Buffer) 627 decoder := asserts.NewDecoder(stream) 628 _, err := decoder.Decode() 629 c.Check(err, Equals, io.EOF) 630 } 631 632 func (as *assertsSuite) TestDecoderHappyWithSeparatorsVariations(c *C) { 633 streams := []string{ 634 exampleBodyAndExtraHeaders, 635 exampleEmptyBody2NlNl, 636 exampleEmptyBodyAllDefaults, 637 } 638 639 for _, streamData := range streams { 640 stream := bytes.NewBufferString(streamData) 641 decoder := asserts.NewDecoderStressed(stream, 16, 1024, 1024, 1024) 642 a, err := decoder.Decode() 643 c.Assert(err, IsNil, Commentf("stream: %q", streamData)) 644 645 checkContent(c, a, streamData) 646 647 a, err = decoder.Decode() 648 c.Check(a, IsNil) 649 c.Check(err, Equals, io.EOF, Commentf("stream: %q", streamData)) 650 } 651 } 652 653 func (as *assertsSuite) TestDecoderHappyWithTrailerDoubleNewlines(c *C) { 654 streams := []string{ 655 exampleBodyAndExtraHeaders, 656 exampleEmptyBody2NlNl, 657 exampleEmptyBodyAllDefaults, 658 } 659 660 for _, streamData := range streams { 661 stream := bytes.NewBufferString(streamData) 662 if strings.HasSuffix(streamData, "\n") { 663 stream.WriteString("\n") 664 } else { 665 stream.WriteString("\n\n") 666 } 667 668 decoder := asserts.NewDecoderStressed(stream, 16, 1024, 1024, 1024) 669 a, err := decoder.Decode() 670 c.Assert(err, IsNil, Commentf("stream: %q", streamData)) 671 672 checkContent(c, a, streamData) 673 674 a, err = decoder.Decode() 675 c.Check(a, IsNil) 676 c.Check(err, Equals, io.EOF, Commentf("stream: %q", streamData)) 677 } 678 } 679 680 func (as *assertsSuite) TestDecoderUnexpectedEOF(c *C) { 681 streamData := exampleBodyAndExtraHeaders + "\n" + exampleEmptyBodyAllDefaults 682 fstHeadEnd := strings.Index(exampleBodyAndExtraHeaders, "\n\n") 683 sndHeadEnd := len(exampleBodyAndExtraHeaders) + 1 + strings.Index(exampleEmptyBodyAllDefaults, "\n\n") 684 685 for _, brk := range []int{1, fstHeadEnd / 2, fstHeadEnd, fstHeadEnd + 1, fstHeadEnd + 2, fstHeadEnd + 6} { 686 stream := bytes.NewBufferString(streamData[:brk]) 687 decoder := asserts.NewDecoderStressed(stream, 16, 1024, 1024, 1024) 688 _, err := decoder.Decode() 689 c.Check(err, Equals, io.ErrUnexpectedEOF, Commentf("brk: %d", brk)) 690 } 691 692 for _, brk := range []int{sndHeadEnd, sndHeadEnd + 1} { 693 stream := bytes.NewBufferString(streamData[:brk]) 694 decoder := asserts.NewDecoder(stream) 695 _, err := decoder.Decode() 696 c.Assert(err, IsNil) 697 698 _, err = decoder.Decode() 699 c.Check(err, Equals, io.ErrUnexpectedEOF, Commentf("brk: %d", brk)) 700 } 701 } 702 703 func (as *assertsSuite) TestDecoderBrokenBodySeparation(c *C) { 704 streamData := strings.Replace(exampleBodyAndExtraHeaders, "THE-BODY\n\n", "THE-BODY", 1) 705 decoder := asserts.NewDecoder(bytes.NewBufferString(streamData)) 706 _, err := decoder.Decode() 707 c.Assert(err, ErrorMatches, "missing content/signature separator") 708 709 streamData = strings.Replace(exampleBodyAndExtraHeaders, "THE-BODY\n\n", "THE-BODY\n", 1) 710 decoder = asserts.NewDecoder(bytes.NewBufferString(streamData)) 711 _, err = decoder.Decode() 712 c.Assert(err, ErrorMatches, "missing content/signature separator") 713 } 714 715 func (as *assertsSuite) TestDecoderHeadTooBig(c *C) { 716 decoder := asserts.NewDecoderStressed(bytes.NewBufferString(exampleBodyAndExtraHeaders), 4, 4, 1024, 1024) 717 _, err := decoder.Decode() 718 c.Assert(err, ErrorMatches, `error reading assertion headers: maximum size exceeded while looking for delimiter "\\n\\n"`) 719 } 720 721 func (as *assertsSuite) TestDecoderBodyTooBig(c *C) { 722 decoder := asserts.NewDecoderStressed(bytes.NewBufferString(exampleBodyAndExtraHeaders), 1024, 1024, 5, 1024) 723 _, err := decoder.Decode() 724 c.Assert(err, ErrorMatches, "assertion body length 8 exceeds maximum body size") 725 } 726 727 func (as *assertsSuite) TestDecoderSignatureTooBig(c *C) { 728 decoder := asserts.NewDecoderStressed(bytes.NewBufferString(exampleBodyAndExtraHeaders), 4, 1024, 1024, 7) 729 _, err := decoder.Decode() 730 c.Assert(err, ErrorMatches, `error reading assertion signature: maximum size exceeded while looking for delimiter "\\n\\n"`) 731 } 732 733 func (as *assertsSuite) TestDecoderDefaultMaxBodySize(c *C) { 734 enc := strings.Replace(exampleBodyAndExtraHeaders, "body-length: 8", "body-length: 2097153", 1) 735 decoder := asserts.NewDecoder(bytes.NewBufferString(enc)) 736 _, err := decoder.Decode() 737 c.Assert(err, ErrorMatches, "assertion body length 2097153 exceeds maximum body size") 738 } 739 740 func (as *assertsSuite) TestDecoderWithTypeMaxBodySize(c *C) { 741 ex1 := strings.Replace(exampleBodyAndExtraHeaders, "body-length: 8", "body-length: 2097152", 1) 742 ex1 = strings.Replace(ex1, "THE-BODY", strings.Repeat("B", 2*1024*1024), 1) 743 ex1toobig := strings.Replace(exampleBodyAndExtraHeaders, "body-length: 8", "body-length: 2097153", 1) 744 ex1toobig = strings.Replace(ex1toobig, "THE-BODY", strings.Repeat("B", 2*1024*1024+1), 1) 745 const ex2 = `type: test-only-2 746 authority-id: auth-id1 747 pk1: foo 748 pk2: bar 749 body-length: 3 750 sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij 751 752 XYZ 753 754 AXNpZw==` 755 756 decoder := asserts.NewDecoderWithTypeMaxBodySize(bytes.NewBufferString(ex1+"\n"+ex2), map[*asserts.AssertionType]int{ 757 asserts.TestOnly2Type: 3, 758 }) 759 a1, err := decoder.Decode() 760 c.Assert(err, IsNil) 761 c.Check(a1.Body(), HasLen, 2*1024*1024) 762 a2, err := decoder.Decode() 763 c.Assert(err, IsNil) 764 c.Check(a2.Body(), DeepEquals, []byte("XYZ")) 765 766 decoder = asserts.NewDecoderWithTypeMaxBodySize(bytes.NewBufferString(ex1+"\n"+ex2), map[*asserts.AssertionType]int{ 767 asserts.TestOnly2Type: 2, 768 }) 769 a1, err = decoder.Decode() 770 c.Assert(err, IsNil) 771 c.Check(a1.Body(), HasLen, 2*1024*1024) 772 _, err = decoder.Decode() 773 c.Assert(err, ErrorMatches, `assertion body length 3 exceeds maximum body size 2 for "test-only-2" assertions`) 774 775 decoder = asserts.NewDecoderWithTypeMaxBodySize(bytes.NewBufferString(ex2+"\n\n"+ex1toobig), map[*asserts.AssertionType]int{ 776 asserts.TestOnly2Type: 3, 777 }) 778 a2, err = decoder.Decode() 779 c.Assert(err, IsNil) 780 c.Check(a2.Body(), DeepEquals, []byte("XYZ")) 781 _, err = decoder.Decode() 782 c.Assert(err, ErrorMatches, "assertion body length 2097153 exceeds maximum body size") 783 } 784 785 func (as *assertsSuite) TestEncode(c *C) { 786 encoded := []byte("type: test-only\n" + 787 "authority-id: auth-id2\n" + 788 "primary-key: xyz\n" + 789 "revision: 5\n" + 790 "header1: value1\n" + 791 "header2: value2\n" + 792 "body-length: 8\n" + 793 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 794 "THE-BODY" + 795 "\n\n" + 796 "AXNpZw==") 797 a, err := asserts.Decode(encoded) 798 c.Assert(err, IsNil) 799 encodeRes := asserts.Encode(a) 800 c.Check(encodeRes, DeepEquals, encoded) 801 } 802 803 func (as *assertsSuite) TestEncoderOK(c *C) { 804 encoded := []byte("type: test-only\n" + 805 "authority-id: auth-id2\n" + 806 "primary-key: xyzyz\n" + 807 "revision: 5\n" + 808 "header1: value1\n" + 809 "header2: value2\n" + 810 "body-length: 8\n" + 811 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 812 "THE-BODY" + 813 "\n\n" + 814 "AXNpZw==") 815 a0, err := asserts.Decode(encoded) 816 c.Assert(err, IsNil) 817 cont0, _ := a0.Signature() 818 819 stream := new(bytes.Buffer) 820 enc := asserts.NewEncoder(stream) 821 enc.Encode(a0) 822 823 c.Check(bytes.HasSuffix(stream.Bytes(), []byte{'\n'}), Equals, true) 824 825 dec := asserts.NewDecoder(stream) 826 a1, err := dec.Decode() 827 c.Assert(err, IsNil) 828 829 cont1, _ := a1.Signature() 830 c.Check(cont1, DeepEquals, cont0) 831 } 832 833 func (as *assertsSuite) TestEncoderSingleDecodeOK(c *C) { 834 encoded := []byte("type: test-only\n" + 835 "authority-id: auth-id2\n" + 836 "primary-key: abc\n" + 837 "revision: 5\n" + 838 "header1: value1\n" + 839 "header2: value2\n" + 840 "body-length: 8\n" + 841 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 842 "THE-BODY" + 843 "\n\n" + 844 "AXNpZw==") 845 a0, err := asserts.Decode(encoded) 846 c.Assert(err, IsNil) 847 cont0, _ := a0.Signature() 848 849 stream := new(bytes.Buffer) 850 enc := asserts.NewEncoder(stream) 851 enc.Encode(a0) 852 853 a1, err := asserts.Decode(stream.Bytes()) 854 c.Assert(err, IsNil) 855 856 cont1, _ := a1.Signature() 857 c.Check(cont1, DeepEquals, cont0) 858 } 859 860 func (as *assertsSuite) TestSignFormatValidityEmptyBody(c *C) { 861 headers := map[string]interface{}{ 862 "authority-id": "auth-id1", 863 "primary-key": "0", 864 } 865 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 866 c.Assert(err, IsNil) 867 868 _, err = asserts.Decode(asserts.Encode(a)) 869 c.Check(err, IsNil) 870 } 871 872 func (as *assertsSuite) TestSignFormatValidityNonEmptyBody(c *C) { 873 headers := map[string]interface{}{ 874 "authority-id": "auth-id1", 875 "primary-key": "0", 876 } 877 body := []byte("THE-BODY") 878 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, body, testPrivKey1) 879 c.Assert(err, IsNil) 880 c.Check(a.Body(), DeepEquals, body) 881 882 decoded, err := asserts.Decode(asserts.Encode(a)) 883 c.Assert(err, IsNil) 884 c.Check(decoded.Body(), DeepEquals, body) 885 } 886 887 func (as *assertsSuite) TestSignFormatValiditySupportMultilineHeaderValues(c *C) { 888 headers := map[string]interface{}{ 889 "authority-id": "auth-id1", 890 "primary-key": "0", 891 } 892 893 multilineVals := []string{ 894 "a\n", 895 "\na", 896 "a\n\b\nc", 897 "a\n\b\nc\n", 898 "\na\n", 899 "\n\na\n\nb\n\nc", 900 } 901 902 for _, multilineVal := range multilineVals { 903 headers["multiline"] = multilineVal 904 if len(multilineVal)%2 == 1 { 905 headers["odd"] = "true" 906 } 907 908 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 909 c.Assert(err, IsNil) 910 911 decoded, err := asserts.Decode(asserts.Encode(a)) 912 c.Assert(err, IsNil) 913 914 c.Check(decoded.Header("multiline"), Equals, multilineVal) 915 } 916 } 917 918 func (as *assertsSuite) TestSignFormatAndRevision(c *C) { 919 headers := map[string]interface{}{ 920 "authority-id": "auth-id1", 921 "primary-key": "0", 922 "format": "1", 923 "revision": "11", 924 } 925 926 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 927 c.Assert(err, IsNil) 928 929 c.Check(a.Revision(), Equals, 11) 930 c.Check(a.Format(), Equals, 1) 931 c.Check(a.SupportedFormat(), Equals, true) 932 933 a1, err := asserts.Decode(asserts.Encode(a)) 934 c.Assert(err, IsNil) 935 936 c.Check(a1.Revision(), Equals, 11) 937 c.Check(a1.Format(), Equals, 1) 938 c.Check(a1.SupportedFormat(), Equals, true) 939 } 940 941 func (as *assertsSuite) TestSignFormatOptionalPrimaryKeys(c *C) { 942 r := asserts.MockOptionalPrimaryKey(asserts.TestOnlyType, "opt1", "o1-defl") 943 defer r() 944 945 headers := map[string]interface{}{ 946 "authority-id": "auth-id1", 947 "primary-key": "k1", 948 "header1": "a", 949 } 950 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 951 c.Assert(err, IsNil) 952 953 b := asserts.Encode(a) 954 c.Check(bytes.HasPrefix(b, []byte(`type: test-only 955 authority-id: auth-id1 956 primary-key: k1 957 header1:`)), Equals, true) 958 c.Check(a.HeaderString("opt1"), Equals, "o1-defl") 959 960 _, err = asserts.Decode(b) 961 c.Check(err, IsNil) 962 963 // defaults are always normalized away 964 headers = map[string]interface{}{ 965 "authority-id": "auth-id1", 966 "primary-key": "k1", 967 "opt1": "o1-defl", 968 "header1": "a", 969 } 970 a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 971 c.Assert(err, IsNil) 972 973 b = asserts.Encode(a) 974 c.Check(bytes.HasPrefix(b, []byte(`type: test-only 975 authority-id: auth-id1 976 primary-key: k1 977 header1:`)), Equals, true) 978 c.Check(a.HeaderString("opt1"), Equals, "o1-defl") 979 980 _, err = asserts.Decode(b) 981 c.Check(err, IsNil) 982 983 headers = map[string]interface{}{ 984 "authority-id": "auth-id1", 985 "primary-key": "k1", 986 "opt1": "A", 987 "header1": "a", 988 } 989 a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 990 c.Assert(err, IsNil) 991 992 b = asserts.Encode(a) 993 c.Check(bytes.HasPrefix(b, []byte(`type: test-only 994 authority-id: auth-id1 995 primary-key: k1 996 opt1: A 997 header1:`)), Equals, true) 998 c.Check(a.HeaderString("opt1"), Equals, "A") 999 1000 _, err = asserts.Decode(b) 1001 c.Check(err, IsNil) 1002 } 1003 1004 func (as *assertsSuite) TestSignBodyIsUTF8Text(c *C) { 1005 headers := map[string]interface{}{ 1006 "authority-id": "auth-id1", 1007 "primary-key": "0", 1008 } 1009 _, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, []byte{'\xff'}, testPrivKey1) 1010 c.Assert(err, ErrorMatches, "assertion body is not utf8") 1011 } 1012 1013 func (as *assertsSuite) TestHeaders(c *C) { 1014 encoded := []byte("type: test-only\n" + 1015 "authority-id: auth-id2\n" + 1016 "primary-key: abc\n" + 1017 "revision: 5\n" + 1018 "header1: value1\n" + 1019 "header2: value2\n" + 1020 "body-length: 8\n" + 1021 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 1022 "THE-BODY" + 1023 "\n\n" + 1024 "AXNpZw==") 1025 a, err := asserts.Decode(encoded) 1026 c.Assert(err, IsNil) 1027 1028 hs := a.Headers() 1029 c.Check(hs, DeepEquals, map[string]interface{}{ 1030 "type": "test-only", 1031 "authority-id": "auth-id2", 1032 "primary-key": "abc", 1033 "revision": "5", 1034 "header1": "value1", 1035 "header2": "value2", 1036 "body-length": "8", 1037 "sign-key-sha3-384": exKeyID, 1038 }) 1039 } 1040 1041 func (as *assertsSuite) TestHeadersReturnsCopy(c *C) { 1042 encoded := []byte("type: test-only\n" + 1043 "authority-id: auth-id2\n" + 1044 "primary-key: xyz\n" + 1045 "revision: 5\n" + 1046 "header1: value1\n" + 1047 "header2: value2\n" + 1048 "body-length: 8\n" + 1049 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 1050 "THE-BODY" + 1051 "\n\n" + 1052 "AXNpZw==") 1053 a, err := asserts.Decode(encoded) 1054 c.Assert(err, IsNil) 1055 1056 hs := a.Headers() 1057 // casual later result mutation doesn't trip us 1058 delete(hs, "primary-key") 1059 c.Check(a.Header("primary-key"), Equals, "xyz") 1060 } 1061 1062 func (as *assertsSuite) TestAssembleRoundtrip(c *C) { 1063 encoded := []byte("type: test-only\n" + 1064 "format: 1\n" + 1065 "authority-id: auth-id2\n" + 1066 "primary-key: abc\n" + 1067 "revision: 5\n" + 1068 "header1: value1\n" + 1069 "header2: value2\n" + 1070 "body-length: 8\n" + 1071 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 1072 "THE-BODY" + 1073 "\n\n" + 1074 "AXNpZw==") 1075 a, err := asserts.Decode(encoded) 1076 c.Assert(err, IsNil) 1077 1078 cont, sig := a.Signature() 1079 reassembled, err := asserts.Assemble(a.Headers(), a.Body(), cont, sig) 1080 c.Assert(err, IsNil) 1081 1082 c.Check(reassembled.Headers(), DeepEquals, a.Headers()) 1083 c.Check(reassembled.Body(), DeepEquals, a.Body()) 1084 1085 reassembledEncoded := asserts.Encode(reassembled) 1086 c.Check(reassembledEncoded, DeepEquals, encoded) 1087 } 1088 1089 func (as *assertsSuite) TestSignKeyID(c *C) { 1090 headers := map[string]interface{}{ 1091 "authority-id": "auth-id1", 1092 "primary-key": "0", 1093 } 1094 a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 1095 c.Assert(err, IsNil) 1096 1097 keyID := a.SignKeyID() 1098 c.Check(keyID, Equals, testPrivKey1.PublicKey().ID()) 1099 } 1100 1101 func (as *assertsSuite) TestSelfRef(c *C) { 1102 headers := map[string]interface{}{ 1103 "authority-id": "auth-id1", 1104 "primary-key": "0", 1105 } 1106 a1, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1) 1107 c.Assert(err, IsNil) 1108 1109 c.Check(a1.Ref(), DeepEquals, &asserts.Ref{ 1110 Type: asserts.TestOnlyType, 1111 PrimaryKey: []string{"0"}, 1112 }) 1113 1114 c.Check(a1.At(), DeepEquals, &asserts.AtRevision{ 1115 Ref: asserts.Ref{ 1116 Type: asserts.TestOnlyType, 1117 PrimaryKey: []string{"0"}, 1118 }, 1119 Revision: 0, 1120 }) 1121 1122 headers = map[string]interface{}{ 1123 "authority-id": "auth-id1", 1124 "pk1": "a", 1125 "pk2": "b", 1126 "revision": "1", 1127 } 1128 a2, err := asserts.AssembleAndSignInTest(asserts.TestOnly2Type, headers, nil, testPrivKey1) 1129 c.Assert(err, IsNil) 1130 1131 c.Check(a2.Ref(), DeepEquals, &asserts.Ref{ 1132 Type: asserts.TestOnly2Type, 1133 PrimaryKey: []string{"a", "b"}, 1134 }) 1135 1136 c.Check(a2.At(), DeepEquals, &asserts.AtRevision{ 1137 Ref: asserts.Ref{ 1138 Type: asserts.TestOnly2Type, 1139 PrimaryKey: []string{"a", "b"}, 1140 }, 1141 Revision: 1, 1142 }) 1143 } 1144 1145 func (as *assertsSuite) TestAssembleHeadersCheck(c *C) { 1146 cont := []byte("type: test-only\n" + 1147 "authority-id: auth-id2\n" + 1148 "primary-key: abc\n" + 1149 "revision: 5") 1150 headers := map[string]interface{}{ 1151 "type": "test-only", 1152 "authority-id": "auth-id2", 1153 "primary-key": "abc", 1154 "revision": 5, // must be a string actually! 1155 } 1156 1157 _, err := asserts.Assemble(headers, nil, cont, nil) 1158 c.Check(err, ErrorMatches, `header "revision": header values must be strings or nested lists or maps with strings as the only scalars: 5`) 1159 } 1160 1161 func (as *assertsSuite) TestSignWithoutAuthorityMisuse(c *C) { 1162 _, err := asserts.SignWithoutAuthority(asserts.TestOnlyType, nil, nil, testPrivKey1) 1163 c.Check(err, ErrorMatches, `cannot sign assertions needing a definite authority with SignWithoutAuthority`) 1164 1165 _, err = asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityType, 1166 map[string]interface{}{ 1167 "authority-id": "auth-id1", 1168 "hdr": "FOO", 1169 }, nil, testPrivKey1) 1170 c.Check(err, ErrorMatches, `"test-only-no-authority" assertion cannot have authority-id set`) 1171 } 1172 1173 func (ss *serialSuite) TestSignatureCheckError(c *C) { 1174 sreq, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityType, 1175 map[string]interface{}{ 1176 "hdr": "FOO", 1177 }, nil, testPrivKey1) 1178 c.Assert(err, IsNil) 1179 1180 err = asserts.SignatureCheck(sreq, testPrivKey2.PublicKey()) 1181 c.Check(err, ErrorMatches, `failed signature verification:.*`) 1182 } 1183 1184 func (as *assertsSuite) TestWithAuthority(c *C) { 1185 withAuthority := []string{ 1186 "account", 1187 "account-key", 1188 // XXX "authority-delegation", 1189 "base-declaration", 1190 "store", 1191 "snap-declaration", 1192 "snap-build", 1193 "snap-revision", 1194 "snap-developer", 1195 "model", 1196 "preseed", 1197 "serial", 1198 "system-user", 1199 "validation", 1200 "validation-set", 1201 "repair", 1202 } 1203 c.Check(withAuthority, HasLen, asserts.NumAssertionType-3) // excluding device-session-request, serial-request, account-key-request 1204 for _, name := range withAuthority { 1205 typ := asserts.Type(name) 1206 _, err := asserts.AssembleAndSignInTest(typ, nil, nil, testPrivKey1) 1207 c.Check(err, ErrorMatches, `"authority-id" header is mandatory`) 1208 } 1209 } 1210 1211 func (as *assertsSuite) TestSequenceForming(c *C) { 1212 sequenceForming := []string{ 1213 "repair", 1214 "validation-set", 1215 } 1216 for _, name := range sequenceForming { 1217 typ := asserts.Type(name) 1218 c.Check(typ.SequenceForming(), Equals, true) 1219 } 1220 1221 c.Check(asserts.SnapDeclarationType.SequenceForming(), Equals, false) 1222 } 1223 1224 func (as *assertsSuite) TestHeadersFromSequenceKey(c *C) { 1225 headers, err := asserts.HeadersFromSequenceKey(asserts.TestOnlySeqType, []string{"one"}) 1226 c.Assert(err, IsNil) 1227 c.Check(headers, DeepEquals, map[string]string{"n": "one"}) 1228 1229 _, err = asserts.HeadersFromSequenceKey(asserts.TestOnlySeqType, []string{"one", "two"}) 1230 c.Check(err, ErrorMatches, `sequence key has wrong length for "test-only-seq" assertion`) 1231 1232 _, err = asserts.HeadersFromSequenceKey(asserts.TestOnlySeqType, []string{}) 1233 c.Check(err, ErrorMatches, `sequence key has wrong length for "test-only-seq" assertion`) 1234 1235 _, err = asserts.HeadersFromSequenceKey(asserts.TestOnlySeqType, []string{""}) 1236 c.Check(err, ErrorMatches, `sequence key "n" header cannot be empty`) 1237 } 1238 1239 func (as *assertsSuite) TestAtSequenceString(c *C) { 1240 atSeq := asserts.AtSequence{ 1241 Type: asserts.ValidationSetType, 1242 SequenceKey: []string{"16", "canonical", "foo"}, 1243 Sequence: 8, 1244 Revision: 2, 1245 } 1246 c.Check(atSeq.String(), Equals, "validation-set canonical/foo/8 at revision 2") 1247 1248 // Sequence number not set 1249 atSeq = asserts.AtSequence{ 1250 Type: asserts.ValidationSetType, 1251 SequenceKey: []string{"16", "canonical", "foo"}, 1252 Revision: asserts.RevisionNotKnown, 1253 } 1254 c.Check(atSeq.String(), Equals, "validation-set canonical/foo") 1255 1256 atSeq = asserts.AtSequence{ 1257 Type: asserts.ValidationSetType, 1258 SequenceKey: []string{"16", "canonical", "foo"}, 1259 Sequence: 8, 1260 Pinned: true, 1261 Revision: 2, 1262 } 1263 c.Check(atSeq.String(), Equals, "validation-set canonical/foo=8 at revision 2") 1264 1265 atSeq = asserts.AtSequence{ 1266 Type: asserts.ValidationSetType, 1267 SequenceKey: []string{"16", "canonical"}, 1268 Revision: 2, 1269 } 1270 c.Check(atSeq.String(), Equals, "validation-set ??? at revision 2") 1271 } 1272 1273 func (as *assertsSuite) TestAtSequenceUnique(c *C) { 1274 atSeq := asserts.AtSequence{ 1275 Type: asserts.ValidationSetType, 1276 SequenceKey: []string{"16", "canonical", "foo"}, 1277 Sequence: 8, 1278 Revision: 2, 1279 } 1280 c.Check(atSeq.Unique(), Equals, "validation-set/16/canonical/foo") 1281 1282 // not a valid sequence-key (but Unique() doesn't care). 1283 atSeq = asserts.AtSequence{ 1284 Type: asserts.ValidationSetType, 1285 SequenceKey: []string{"16", "canonical"}, 1286 } 1287 c.Check(atSeq.Unique(), Equals, "validation-set/16/canonical") 1288 } 1289 1290 func (as *assertsSuite) TestAtSequenceResolveError(c *C) { 1291 atSeq := asserts.AtSequence{ 1292 Type: asserts.ValidationSetType, 1293 SequenceKey: []string{"abc"}, 1294 Sequence: 1, 1295 } 1296 _, err := atSeq.Resolve(nil) 1297 c.Check(err, ErrorMatches, `"validation-set" assertion reference primary key has the wrong length \(expected \[series account-id name sequence\]\): \[abc 1\]`) 1298 1299 atSeq = asserts.AtSequence{ 1300 Type: asserts.ValidationSetType, 1301 SequenceKey: []string{"16", "canonical", "foo"}, 1302 } 1303 _, err = atSeq.Resolve(nil) 1304 c.Assert(err, DeepEquals, &asserts.NotFoundError{ 1305 Type: asserts.ValidationSetType, 1306 Headers: map[string]string{ 1307 "series": "16", 1308 "account-id": "canonical", 1309 "name": "foo", 1310 }, 1311 }) 1312 } 1313 1314 func (as *assertsSuite) TestAtSequenceResolve(c *C) { 1315 atSeq := asserts.AtSequence{ 1316 Type: asserts.TestOnlySeqType, 1317 SequenceKey: []string{"foo"}, 1318 Sequence: 3, 1319 } 1320 a, err := atSeq.Resolve(func(atype *asserts.AssertionType, hdrs map[string]string) (asserts.Assertion, error) { 1321 c.Assert(atype, Equals, asserts.TestOnlySeqType) 1322 c.Assert(hdrs, DeepEquals, map[string]string{ 1323 "n": "foo", 1324 "sequence": "3", 1325 }) 1326 encoded := []byte("type: test-only-seq\n" + 1327 "format: 1\n" + 1328 "authority-id: auth-id2\n" + 1329 "n: abc\n" + 1330 "revision: 5\n" + 1331 "sequence: 3\n" + 1332 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" + 1333 "\n\n" + 1334 "AXNpZw==") 1335 a, err := asserts.Decode(encoded) 1336 return a, err 1337 }) 1338 c.Assert(err, IsNil) 1339 c.Assert(a, NotNil) 1340 c.Check(a.Type().Name, Equals, "test-only-seq") 1341 }