func (as *assertsSuite) TestEncoderSingleDecodeOK(c *C) { encoded := []byte("type: test-only\n" + "authority-id: auth-id2\n" + "primary-key: abc\n" + "revision: 5\n" + "header1: value1\n" + "header2: value2\n" + "body-length: 8\n\n" + "THE-BODY" + "\n\n" + "openpgp c2ln") a0, err := asserts.Decode(encoded) c.Assert(err, IsNil) cont0, _ := a0.Signature() stream := new(bytes.Buffer) enc := asserts.NewEncoder(stream) enc.Encode(a0) a1, err := asserts.Decode(stream.Bytes()) c.Assert(err, IsNil) cont1, _ := a1.Signature() c.Check(cont1, DeepEquals, cont0) }
func (mbss *memBackstoreSuite) TestSearch2Levels(c *C) { encoded := "type: test-only-2\n" + "authority-id: auth-id1\n" + "pk1: a\n" + "pk2: x" + "\n\n" + "openpgp c2ln" aAX, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) encoded = "type: test-only-2\n" + "authority-id: auth-id1\n" + "pk1: b\n" + "pk2: x" + "\n\n" + "openpgp c2ln" aBX, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) err = mbss.bs.Put(asserts.TestOnly2Type, aAX) c.Assert(err, IsNil) err = mbss.bs.Put(asserts.TestOnly2Type, aBX) c.Assert(err, IsNil) found := map[string]asserts.Assertion{} cb := func(a asserts.Assertion) { found[a.Header("pk1")+":"+a.Header("pk2")] = a } err = mbss.bs.Search(asserts.TestOnly2Type, map[string]string{ "pk2": "x", }, cb) c.Assert(err, IsNil) c.Check(found, HasLen, 2) }
func (mbss *memBackstoreSuite) TestSearch(c *C) { encoded := "type: test-only\n" + "authority-id: auth-id1\n" + "primary-key: one\n" + "other: other1" + "\n\n" + "openpgp c2ln" a1, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) encoded = "type: test-only\n" + "authority-id: auth-id1\n" + "primary-key: two\n" + "other: other2" + "\n\n" + "openpgp c2ln" a2, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) err = mbss.bs.Put(asserts.TestOnlyType, a1) c.Assert(err, IsNil) err = mbss.bs.Put(asserts.TestOnlyType, a2) c.Assert(err, IsNil) found := map[string]asserts.Assertion{} cb := func(a asserts.Assertion) { found[a.Header("primary-key")] = a } err = mbss.bs.Search(asserts.TestOnlyType, nil, cb) c.Assert(err, IsNil) c.Check(found, HasLen, 2) found = map[string]asserts.Assertion{} err = mbss.bs.Search(asserts.TestOnlyType, map[string]string{ "primary-key": "one", }, cb) c.Assert(err, IsNil) c.Check(found, DeepEquals, map[string]asserts.Assertion{ "one": a1, }) found = map[string]asserts.Assertion{} err = mbss.bs.Search(asserts.TestOnlyType, map[string]string{ "other": "other2", }, cb) c.Assert(err, IsNil) c.Check(found, DeepEquals, map[string]asserts.Assertion{ "two": a2, }) found = map[string]asserts.Assertion{} err = mbss.bs.Search(asserts.TestOnlyType, map[string]string{ "primary-key": "two", "other": "other1", }, cb) c.Assert(err, IsNil) c.Check(found, HasLen, 0) }
func (sds *snapBuildSuite) TestDecodeInvalid(c *C) { encoded := "type: snap-build\n" + "authority-id: dev-id1\n" + "snap-id: snap-id-1\n" + "snap-digest: sha256 ...\n" + "grade: stable\n" + "snap-size: 10000\n" + sds.tsLine + "body-length: 0" + "\n\n" + "openpgp c2ln" invalidTests := []struct{ original, invalid, expectedErr string }{ {"snap-id: snap-id-1\n", "", `"snap-id" header is mandatory`}, {"snap-digest: sha256 ...\n", "", `"snap-digest" header is mandatory`}, {"grade: stable\n", "", `"grade" header is mandatory`}, {"snap-size: 10000\n", "", `"snap-size" header is mandatory`}, {"snap-size: 10000\n", "snap-size: -1\n", `"snap-size" header is not an unsigned integer: -1`}, {"snap-size: 10000\n", "snap-size: zzz\n", `"snap-size" header is not an unsigned integer: zzz`}, {sds.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`}, } for _, test := range invalidTests { invalid := strings.Replace(encoded, test.original, test.invalid, 1) _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, snapBuildErrPrefix+test.expectedErr) } }
func (aks *accountKeySuite) TestDecodeInvalidHeaders(c *C) { encoded := "type: account-key\n" + "authority-id: canonical\n" + "account-id: acc-id1\n" + "public-key-id: " + aks.keyid + "\n" + "public-key-fingerprint: " + aks.fp + "\n" + aks.sinceLine + aks.untilLine + fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n\n" + aks.pubKeyBody + "\n\n" + "openpgp c2ln" invalidHeaderTests := []struct{ original, invalid, expectedErr string }{ {"account-id: acc-id1\n", "", `"account-id" header is mandatory`}, {aks.sinceLine, "", `"since" header is mandatory`}, {aks.untilLine, "", `"until" header is mandatory`}, {aks.sinceLine, "since: 12:30\n", `"since" header is not a RFC3339 date: .*`}, {aks.untilLine, "until: " + aks.since.Format(time.RFC3339) + "\n", `invalid 'since' and 'until' times \(no gap after 'since' till 'until'\)`}, {"public-key-id: " + aks.keyid + "\n", "", `"public-key-id" header is mandatory`}, {"public-key-fingerprint: " + aks.fp + "\n", "", `"public-key-fingerprint" header is mandatory`}, } for _, test := range invalidHeaderTests { invalid := strings.Replace(encoded, test.original, test.invalid, 1) _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, accKeyErrPrefix+test.expectedErr) } }
func (aks *accountKeySuite) TestDecodeInvalidPublicKey(c *C) { headers := "type: account-key\n" + "authority-id: canonical\n" + "account-id: acc-id1\n" + "public-key-id: " + aks.keyid + "\n" + "public-key-fingerprint: " + aks.fp + "\n" + aks.sinceLine + aks.untilLine invalidPublicKeyTests := []struct{ body, expectedErr string }{ {"", "empty public key"}, {"stuff", "public key: expected format and base64 data separated by space"}, {"openpgp _", "public key: could not decode base64 data: .*"}, {strings.Replace(aks.pubKeyBody, "openpgp", "mystery", 1), `unsupported public key format: "mystery"`}, {"openpgp anVuaw==", "could not decode public key data: .*"}, } for _, test := range invalidPublicKeyTests { invalid := headers + fmt.Sprintf("body-length: %v", len(test.body)) + "\n\n" + test.body + "\n\n" + "openpgp c2ln" _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, accKeyErrPrefix+test.expectedErr) } }
func (chks *checkSuite) TestCheckForgery(c *C) { trustedKey := testPrivKey0 cfg := &asserts.DatabaseConfig{ Backstore: chks.bs, KeypairManager: asserts.NewMemoryKeypairManager(), TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", &trustedKey.PublicKey)}, } db, err := asserts.OpenDatabase(cfg) c.Assert(err, IsNil) encoded := asserts.Encode(chks.a) content, encodedSig := chks.a.Signature() // forgery forgedSig := new(packet.Signature) forgedSig.PubKeyAlgo = testPrivKey1.PubKeyAlgo forgedSig.Hash = crypto.SHA256 forgedSig.CreationTime = time.Now() forgedSig.IssuerKeyId = &testPrivKey0.KeyId h := crypto.SHA256.New() h.Write(content) err = forgedSig.Sign(h, testPrivKey1, &packet.Config{DefaultHash: crypto.SHA256}) c.Assert(err, IsNil) buf := new(bytes.Buffer) forgedSig.Serialize(buf) forgedSigEncoded := "openpgp " + base64.StdEncoding.EncodeToString(buf.Bytes()) forgedEncoded := bytes.Replace(encoded, encodedSig, []byte(forgedSigEncoded), 1) c.Assert(forgedEncoded, Not(DeepEquals), encoded) forgedAssert, err := asserts.Decode(forgedEncoded) c.Assert(err, IsNil) err = db.Check(forgedAssert) c.Assert(err, ErrorMatches, "failed signature verification: .*") }
func (as *assertsSuite) TestAssembleRoundtrip(c *C) { encoded := []byte("type: test-only\n" + "authority-id: auth-id2\n" + "primary-key1: key1\n" + "primary-key2: key2\n" + "revision: 5\n" + "header1: value1\n" + "header2: value2\n" + "body-length: 8\n\n" + "THE-BODY" + "\n\n" + "openpgp c2ln") a, err := asserts.Decode(encoded) c.Assert(err, IsNil) cont, sig := a.Signature() reassembled, err := asserts.Assemble(a.Headers(), a.Body(), cont, sig) c.Assert(err, IsNil) c.Check(reassembled.Headers(), DeepEquals, a.Headers()) c.Check(reassembled.Body(), DeepEquals, a.Body()) reassembledEncoded := asserts.Encode(reassembled) c.Check(reassembledEncoded, DeepEquals, encoded) }
func (as *assertsSuite) TestDecodeInvalid(c *C) { encoded := "type: test-only\n" + "authority-id: auth-id\n" + "revision: 0\n" + "body-length: 5" + "\n\n" + "abcde" + "\n\n" + "openpgp c2ln" invalidAssertTests := []struct{ original, invalid, expectedErr string }{ {"body-length: 5", "body-length: z", `assertion: "body-length" header is not an integer: z`}, {"body-length: 5", "body-length: 3", "assertion body length and declared body-length don't match: 5 != 3"}, {"authority-id: auth-id\n", "", `assertion: "authority-id" header is mandatory`}, {"authority-id: auth-id\n", "authority-id: \n", `assertion: "authority-id" header should not be empty`}, {"openpgp c2ln", "", "empty assertion signature"}, {"type: test-only\n", "", `assertion: "type" header is mandatory`}, {"type: test-only\n", "type: unknown\n", `unknown assertion type: "unknown"`}, {"revision: 0\n", "revision: Z\n", `assertion: "revision" header is not an integer: Z`}, {"revision: 0\n", "revision: -10\n", "assertion: revision should be positive: -10"}, } for _, test := range invalidAssertTests { invalid := strings.Replace(encoded, test.original, test.invalid, 1) _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, test.expectedErr) } }
func (as *assertsSuite) TestDecodeEmptyBodyNormalize2NlNl(c *C) { a, err := asserts.Decode([]byte(exampleEmptyBody2NlNl)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.TestOnlyType) c.Check(a.Revision(), Equals, 0) c.Check(a.Body(), IsNil) }
func (sds *snapDeclSuite) TestDecodeInvalid(c *C) { encoded := "type: snap-declaration\n" + "authority-id: canonical\n" + "series: 16\n" + "snap-id: snap-id-1\n" + "snap-name: first\n" + "publisher-id: dev-id1\n" + "gates: snap-id-3,snap-id-4\n" + sds.tsLine + "body-length: 0" + "\n\n" + "openpgp c2ln" invalidTests := []struct{ original, invalid, expectedErr string }{ {"series: 16\n", "", `"series" header is mandatory`}, {"snap-id: snap-id-1\n", "", `"snap-id" header is mandatory`}, {"snap-name: first\n", "", `"snap-name" header is mandatory`}, {"publisher-id: dev-id1\n", "", `"publisher-id" header is mandatory`}, {"gates: snap-id-3,snap-id-4\n", "", `\"gates\" header is mandatory`}, {"gates: snap-id-3,snap-id-4\n", "gates: foo,\n", `empty entry in comma separated "gates" header: "foo,"`}, {sds.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`}, } for _, test := range invalidTests { invalid := strings.Replace(encoded, test.original, test.invalid, 1) _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, snapDeclErrPrefix+test.expectedErr) } }
func (as *assertsSuite) TestHeaders(c *C) { encoded := []byte("type: test-only\n" + "authority-id: auth-id2\n" + "primary-key1: key1\n" + "primary-key2: key2\n" + "revision: 5\n" + "header1: value1\n" + "header2: value2\n" + "body-length: 8\n\n" + "THE-BODY" + "\n\n" + "openpgp c2ln") a, err := asserts.Decode(encoded) c.Assert(err, IsNil) hs := a.Headers() c.Check(hs, DeepEquals, map[string]string{ "type": "test-only", "authority-id": "auth-id2", "primary-key1": "key1", "primary-key2": "key2", "revision": "5", "header1": "value1", "header2": "value2", "body-length": "8", }) }
func (as *assertsSuite) TestSignFormatSanitySupportMultilineHeaderValues(c *C) { headers := map[string]string{ "authority-id": "auth-id1", "primary-key": "0", } multilineVals := []string{ "a\n", "\na", "a\n\b\nc", "a\n\b\nc\n", "\na\n", "\n\na\n\nb\n\nc", } for _, multilineVal := range multilineVals { headers["multiline"] = multilineVal if len(multilineVal)%2 == 1 { headers["odd"] = "true" } a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, asserts.OpenPGPPrivateKey(testPrivKey1)) c.Assert(err, IsNil) decoded, err := asserts.Decode(asserts.Encode(a)) c.Assert(err, IsNil) c.Check(decoded.Header("multiline"), Equals, multilineVal) } }
func checkContent(c *C, a asserts.Assertion, encoded string) { expected, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) expectedCont, _ := expected.Signature() cont, _ := a.Signature() c.Check(cont, DeepEquals, expectedCont) }
func (as *assertsSuite) TestSignFormatSanityEmptyBody(c *C) { headers := map[string]string{ "authority-id": "auth-id1", "primary-key": "0", } a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, asserts.OpenPGPPrivateKey(testPrivKey1)) c.Assert(err, IsNil) _, err = asserts.Decode(asserts.Encode(a)) c.Check(err, IsNil) }
func (as *assertsSuite) TestDecodeEmptyBodyAllDefaults(c *C) { a, err := asserts.Decode([]byte(exampleEmptyBodyAllDefaults)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.TestOnlyType) _, ok := a.(*asserts.TestOnly) c.Check(ok, Equals, true) c.Check(a.Revision(), Equals, 0) c.Check(a.Body(), IsNil) c.Check(a.Header("header1"), Equals, "") c.Check(a.AuthorityID(), Equals, "auth-id1") }
func (mods *modelSuite) TestDecodeInvalidMandatory(c *C) { encoded := strings.Replace(modelExample, "TSLINE", mods.tsLine, 1) mandatoryHeaders := []string{"series", "brand-id", "model", "os", "architecture", "gadget", "kernel", "store", "allowed-modes", "required-snaps", "class", "timestamp"} for _, mandatory := range mandatoryHeaders { invalid := strings.Replace(encoded, mandatory+":", "xyz:", 1) _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, fmt.Sprintf("%s%q header is mandatory", modelErrPrefix, mandatory)) } }
func (mbss *memBackstoreSuite) SetUpTest(c *C) { mbss.bs = asserts.NewMemoryBackstore() encoded := "type: test-only\n" + "authority-id: auth-id1\n" + "primary-key: foo" + "\n\n" + "openpgp c2ln" a, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) mbss.a = a }
func (ids *identitySuite) TestDecodeOK(c *C) { encoded := strings.Replace(identityExample, "TSLINE", ids.tsLine, 1) a, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.IdentityType) identity := a.(*asserts.Identity) c.Check(identity.AuthorityID(), Equals, "canonical") c.Check(identity.Timestamp(), Equals, ids.ts) c.Check(identity.AccountID(), Equals, "abc-123") c.Check(identity.DisplayName(), Equals, "Display Name") c.Check(identity.IsCertified(), Equals, true) }
func (as *assertsSuite) TestDecodeHeaderParsingErrors(c *C) { headerParsingErrorsTests := []struct{ encoded, expectedErr string }{ {string([]byte{255, '\n', '\n'}), "header is not utf8"}, {"foo: a\nbar\n\n", "header entry missing name value ': ' separation: \"bar\""}, {"TYPE: foo\n\n", `invalid header name: "TYPE"`}, } for _, test := range headerParsingErrorsTests { _, err := asserts.Decode([]byte(test.encoded)) c.Check(err, ErrorMatches, "parsing assertion headers: "+test.expectedErr) } }
func (as *assertsSuite) TestDecodeWithABodyAndExtraHeaders(c *C) { a, err := asserts.Decode([]byte(exampleBodyAndExtraHeaders)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.TestOnlyType) c.Check(a.AuthorityID(), Equals, "auth-id2") c.Check(a.Header("primary-key"), Equals, "abc") c.Check(a.Revision(), Equals, 5) c.Check(a.Header("header1"), Equals, "value1") c.Check(a.Header("header2"), Equals, "value2") c.Check(a.Body(), DeepEquals, []byte("THE-BODY")) }
func (ids *identitySuite) TestCheckInconsistentTimestamp(c *C) { ex, err := asserts.Decode([]byte(strings.Replace(identityExample, "TSLINE", ids.tsLine, 1))) c.Assert(err, IsNil) signingKeyID, accSignDB, db := makeSignAndCheckDbWithAccountKey(c, "canonical") headers := ex.Headers() headers["timestamp"] = "2011-01-01T14:00:00Z" identity, err := accSignDB.Sign(asserts.IdentityType, headers, nil, signingKeyID) c.Assert(err, IsNil) err = db.Check(identity) c.Assert(err, ErrorMatches, "identity assertion timestamp outside of signing key validity") }
func (as *assertsSuite) TestDecodeEmptyBodyNormalize2NlNl(c *C) { encoded := "type: test-only\n" + "authority-id: auth-id1\n" + "revision: 0\n" + "body-length: 0" + "\n\n" + "\n\n" + "openpgp c2ln" a, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.TestOnlyType) c.Check(a.Revision(), Equals, 0) c.Check(a.Body(), IsNil) }
func (aks *accountKeySuite) TestDecodeFingerprintMismatch(c *C) { invalid := "type: account-key\n" + "authority-id: canonical\n" + "account-id: acc-id1\n" + "fingerprint: 00\n" + aks.sinceLine + aks.untilLine + fmt.Sprintf("body-length: %v", len(aks.pubKeyBody)) + "\n\n" + aks.pubKeyBody + "\n\n" + "openpgp c2ln" _, err := asserts.Decode([]byte(invalid)) c.Check(err, ErrorMatches, accKeyErrPrefix+"public key does not match provided fingerprint") }
func (as *assertsSuite) TestSignFormatSanityNonEmptyBody(c *C) { headers := map[string]string{ "authority-id": "auth-id1", "primary-key": "0", } body := []byte("THE-BODY") a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, body, asserts.OpenPGPPrivateKey(testPrivKey1)) c.Assert(err, IsNil) c.Check(a.Body(), DeepEquals, body) decoded, err := asserts.Decode(asserts.Encode(a)) c.Assert(err, IsNil) c.Check(decoded.Body(), DeepEquals, body) }
func (mods *modelSuite) TestModelCheck(c *C) { ex, err := asserts.Decode([]byte(strings.Replace(modelExample, "TSLINE", mods.tsLine, 1))) c.Assert(err, IsNil) signingKeyID, accSignDB, db := makeSignAndCheckDbWithAccountKey(c, "brand-id1") headers := ex.Headers() headers["timestamp"] = "2015-11-25T20:00:00Z" model, err := accSignDB.Sign(asserts.ModelType, headers, nil, signingKeyID) c.Assert(err, IsNil) err = db.Check(model) c.Assert(err, IsNil) }
func (mods *modelSuite) TestModelCheckInconsistentTimestamp(c *C) { ex, err := asserts.Decode([]byte(strings.Replace(modelExample, "TSLINE", mods.tsLine, 1))) c.Assert(err, IsNil) signingKeyID, accSignDB, db := makeSignAndCheckDbWithAccountKey(c, "brand-id1") headers := ex.Headers() headers["timestamp"] = "2011-01-01T14:00:00Z" model, err := accSignDB.Sign(asserts.ModelType, headers, nil, signingKeyID) c.Assert(err, IsNil) err = db.Check(model) c.Assert(err, ErrorMatches, "model assertion timestamp outside of signing key validity") }
func (dss *deviceSerialSuite) TestDecodeOK(c *C) { encoded := strings.Replace(deviceSerialExample, "TSLINE", dss.tsLine, 1) encoded = strings.Replace(encoded, "DEVICEKEY", strings.Replace(dss.encodedDevKey, "\n", "\n ", -1), 1) a, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.DeviceSerialType) deviceSerial := a.(*asserts.DeviceSerial) c.Check(deviceSerial.AuthorityID(), Equals, "canonical") c.Check(deviceSerial.Timestamp(), Equals, dss.ts) c.Check(deviceSerial.BrandID(), Equals, "brand-id1") c.Check(deviceSerial.Model(), Equals, "baz-3000") c.Check(deviceSerial.Serial(), Equals, "2700") c.Check(deviceSerial.DeviceKey().Fingerprint(), Equals, dss.deviceKey.PublicKey().Fingerprint()) }
func (as *assertsSuite) TestDecodeEmptyBodyAllDefaults(c *C) { encoded := "type: test-only\n" + "authority-id: auth-id1" + "\n\n" + "openpgp c2ln" a, err := asserts.Decode([]byte(encoded)) c.Assert(err, IsNil) c.Check(a.Type(), Equals, asserts.TestOnlyType) _, ok := a.(*asserts.TestOnly) c.Check(ok, Equals, true) c.Check(a.Revision(), Equals, 0) c.Check(a.Body(), IsNil) c.Check(a.Header("header1"), Equals, "") c.Check(a.AuthorityID(), Equals, "auth-id1") }
func (as *assertsSuite) TestDecodeHeaderParsingErrors(c *C) { headerParsingErrorsTests := []struct{ encoded, expectedErr string }{ {string([]byte{255, '\n', '\n'}), "header is not utf8"}, {"foo: a\nbar\n\n", `header entry missing ':' separator: "bar"`}, {"TYPE: foo\n\n", `invalid header name: "TYPE"`}, {"foo: a\nbar:>\n\n", `header entry should have a space or newline \(multiline\) before value: "bar:>"`}, {"foo: a\nbar:\n\n", `empty multiline header value: "bar:"`}, {"foo: a\nbar:\nbaz: x\n\n", `empty multiline header value: "bar:"`}, } for _, test := range headerParsingErrorsTests { _, err := asserts.Decode([]byte(test.encoded)) c.Check(err, ErrorMatches, "parsing assertion headers: "+test.expectedErr) } }