From a65c7959bc775a2c63f9b17aef28415e72b1ffe5 Mon Sep 17 00:00:00 2001 From: Martin Hutchinson Date: Tue, 20 Feb 2024 09:41:44 +0000 Subject: [PATCH 1/2] Breaking change: add structure to manifest This fixes #90 --- .../ftlog/example_firmware_release.json | 22 +-- release/firmware/ftlog/log_entries.go | 60 ++++++--- release/firmware/ftlog/log_entries_test.go | 14 +- release/firmware/update/fetch.go | 10 +- release/firmware/update/fetch_test.go | 126 ++++++++---------- release/firmware/verify.go | 2 +- 6 files changed, 124 insertions(+), 110 deletions(-) diff --git a/release/firmware/ftlog/example_firmware_release.json b/release/firmware/ftlog/example_firmware_release.json index 31dfd22..6a14852 100644 --- a/release/firmware/ftlog/example_firmware_release.json +++ b/release/firmware/ftlog/example_firmware_release.json @@ -1,13 +1,19 @@ { "component": "TRUSTED_APPLET", - "git_tag_name": "0.1.2", - "git_commit_fingerprint": "aac1e176cfac1a1e079b5f624b83fda54b5d0f76", - "firmware_digest_sha256": "8l4TaroPsSq+zwG+XMPZw+EdpUoXH0IT4cKM2RmFyNE=", - "tamago_version": "1.20.6", - "build_envs": [ - "DEBUG=1", - "CHECK=no" - ], + "git": { + "tag_name": "0.1.2", + "commit_fingerprint": "aac1e176cfac1a1e079b5f624b83fda54b5d0f76" + }, + "build": { + "tamago_version": "1.20.6", + "envs": [ + "DEBUG=1", + "CHECK=no" + ] + }, + "output": { + "firmware_digest_sha256": "8l4TaroPsSq+zwG+XMPZw+EdpUoXH0IT4cKM2RmFyNE=" + }, "hab": { "target": "ci", "signature_digest_sha256": "8l4TaroPsSq+zwG+XMPZw+EdpUoXH0IT4cKM2RmFyNE=" diff --git a/release/firmware/ftlog/log_entries.go b/release/firmware/ftlog/log_entries.go index 4108f40..35c1ed7 100644 --- a/release/firmware/ftlog/log_entries.go +++ b/release/firmware/ftlog/log_entries.go @@ -31,6 +31,11 @@ const ( // FirmwareRelease represents a firmware release in the log. type FirmwareRelease struct { + // SchemaVersion gives a unique ID for this version of the schema. This will be + // incremented when there are breaking changes to the schema that all clients + // should be aware of. + SchemaVersion string `json:"schema_version"` + // Component identifies the type of firmware (e.g. OS or applet). // This component is key to disambiguate what the firmware is, and other // implicit information can be derived from this. For example, the git @@ -38,40 +43,59 @@ type FirmwareRelease struct { // build. Component string `json:"component"` - // GitTagName identifies the version of this release, e.g. "0.1.2" - GitTagName semver.Version `json:"git_tag_name"` + // Git contains information about the origin of the code used to build this release. + Git Git `json:"git"` + + // Build contains information about the toolchain used to build this release. + Build Build `json:"build"` + + // Output contains commitments to the binaries distributed in this release. + Output Output `json:"output"` + + // HAB holds a signature and related data for firmware which must be authenticated + // by the device's mask ROM at boot. + // Currently, this is only meaningful for Bootloader and Recovery firmware images. + HAB *HAB `json:"hab,omitempty"` +} + +// Git holds information about the source from which the binary was built. +type Git struct { + // TagName identifies the version of this release, e.g. "0.1.2" + TagName semver.Version `json:"tag_name"` - // GitCommitFingerprint contains the hex-encoded SHA-1 commit hash of the git repository when checked + // CommitFingerprint contains the hex-encoded SHA-1 commit hash of the git repository when checked // out at TagName. Committing to this information allows verifiers that cannot // reproduce a build to quickly narrow down the problem space: - // - if this GitCommitFingerprint is different then they have checked out different code + // - if this CommitFingerprint is different then they have checked out different code // than was used to build the binary. This could happen if the wrong repo was // used, or because the TagName was changed to a different commit - // - if the GitCommitFingerprint is the same, then they have the same code checked out but + // - if the CommitFingerprint is the same, then they have the same code checked out but // there is a problem with the build toolchain (different tooling or non-reproducible // builds). - GitCommitFingerprint string `json:"git_commit_fingerprint"` - - // FirmwareDigestSha256 is the hash of the compiled firmware binary. Believers that are - // installing a firmware release must check that the firmware data they are going to - // believe has a fingerprint matching this hash. Verifiers that check out the correct - // source repo & version must be able to reproducibly build a binary that has this fingerprint. - FirmwareDigestSha256 []byte `json:"firmware_digest_sha256"` + CommitFingerprint string `json:"commit_fingerprint"` +} +// Build holds information about the build toolchain and methodology for turning the source +// into the binary. +type Build struct { // TamagoVersion identifies the version of [Tamago] that the builder used to compile // the binary with FirmwareDigestSha256. // // [Tamago]: https://github.com/usbarmory/tamago TamagoVersion semver.Version `json:"tamago_version"` - // BuildEnvs contains all environment variables set for this build. Each value in the string + // Envs contains all environment variables set for this build. Each value in the string // array will be a single key/value assignment, such as "DEBUG=1". - BuildEnvs []string `json:"build_envs,omitempty"` + Envs []string `json:"envs,omitempty"` +} - // HAB holds a signature and related data for firmware which must be authenticated - // by the device's mask ROM at boot. - // Currently, this is only meaningful for Bootloader and Recovery firmware images. - HAB *HAB `json:"hab,omitempty"` +// Output holds commitments to the binary artifacts that were produced. +type Output struct { + // FirmwareDigestSha256 is the hash of the compiled firmware binary. Believers that are + // installing a firmware release must check that the firmware data they are going to + // believe has a fingerprint matching this hash. Verifiers that check out the correct + // source repo & version must be able to reproducibly build a binary that has this fingerprint. + FirmwareDigestSha256 []byte `json:"firmware_digest_sha256"` } // HAB holds information relating to SecureBoot. diff --git a/release/firmware/ftlog/log_entries_test.go b/release/firmware/ftlog/log_entries_test.go index fcf2c74..657027a 100644 --- a/release/firmware/ftlog/log_entries_test.go +++ b/release/firmware/ftlog/log_entries_test.go @@ -39,25 +39,25 @@ func TestParseFirmwareRelease(t *testing.T) { if got, want := r.Component, ftlog.ComponentApplet; got != want { t.Errorf("Got %q, want %q", got, want) } - if got, want := r.GitTagName, *semver.New("0.1.2"); got != want { + if got, want := r.Git.TagName, *semver.New("0.1.2"); got != want { t.Errorf("Got %q, want %q", got, want) } - if got, want := len(r.GitCommitFingerprint), 40; got != want { + if got, want := len(r.Git.CommitFingerprint), 40; got != want { t.Errorf("Got %d, want %d", got, want) } - if got, want := r.GitCommitFingerprint, "aac1e176cfac1a1e079b5f624b83fda54b5d0f76"; got != want { + if got, want := r.Git.CommitFingerprint, "aac1e176cfac1a1e079b5f624b83fda54b5d0f76"; got != want { t.Errorf("Got %x, want %x", got, want) } - if got, want := len(r.FirmwareDigestSha256), 32; got != want { + if got, want := len(r.Output.FirmwareDigestSha256), 32; got != want { t.Errorf("Got %d, want %d", got, want) } - if got, want := r.FirmwareDigestSha256, mustDecode("8l4TaroPsSq+zwG+XMPZw+EdpUoXH0IT4cKM2RmFyNE="); !bytes.Equal(got, want) { + if got, want := r.Output.FirmwareDigestSha256, mustDecode("8l4TaroPsSq+zwG+XMPZw+EdpUoXH0IT4cKM2RmFyNE="); !bytes.Equal(got, want) { t.Errorf("Got %x, want %x", got, want) } - if got, want := r.TamagoVersion, *semver.New("1.20.6"); got != want { + if got, want := r.Build.TamagoVersion, *semver.New("1.20.6"); got != want { t.Errorf("Got %q, want %q", got, want) } - if got, want := r.BuildEnvs, []string{"DEBUG=1", "CHECK=no"}; !reflect.DeepEqual(got, want) { + if got, want := r.Build.Envs, []string{"DEBUG=1", "CHECK=no"}; !reflect.DeepEqual(got, want) { t.Errorf("Got %q, want %q", got, want) } if got, want := r.HAB.Target, "ci"; got != want { diff --git a/release/firmware/update/fetch.go b/release/firmware/update/fetch.go index a3fb753..e80fcc9 100644 --- a/release/firmware/update/fetch.go +++ b/release/firmware/update/fetch.go @@ -71,10 +71,10 @@ type FetcherOpts struct { // BinaryPath returns the relative path within a bucket for the binary referenced by the manifest. func BinaryPath(fr ftlog.FirmwareRelease) (string, error) { - if len(fr.FirmwareDigestSha256) == 0 { + if len(fr.Output.FirmwareDigestSha256) == 0 { return "", errors.New("firmware digest unset") } - return fmt.Sprintf("%064x", fr.FirmwareDigestSha256), nil + return fmt.Sprintf("%064x", fr.Output.FirmwareDigestSha256), nil } // HABSignaturePath returns the relative path within a bucket for the HAB signature referenced by the manifest. @@ -160,7 +160,7 @@ func (f *Fetcher) GetLatestVersions(_ context.Context) (os semver.Version, apple if f.latestOS == nil || f.latestApplet == nil { return semver.Version{}, semver.Version{}, errors.New("no versions of OS or applet found in log") } - return f.latestOS.manifest.GitTagName, f.latestApplet.manifest.GitTagName, nil + return f.latestOS.manifest.Git.TagName, f.latestApplet.manifest.Git.TagName, nil } func (f *Fetcher) GetOS(ctx context.Context) (firmware.Bundle, error) { @@ -314,8 +314,8 @@ func (f *Fetcher) Scan(ctx context.Context) error { // numbering. func highestRelease(current *firmwareRelease, candidate *firmwareRelease) *firmwareRelease { if current == nil || - current.manifest.GitTagName.LessThan(candidate.manifest.GitTagName) || - current.manifest.GitTagName.Equal(candidate.manifest.GitTagName) { + current.manifest.Git.TagName.LessThan(candidate.manifest.Git.TagName) || + current.manifest.Git.TagName.Equal(candidate.manifest.Git.TagName) { return candidate } return current diff --git a/release/firmware/update/fetch_test.go b/release/firmware/update/fetch_test.go index 2776405..fd24bc0 100644 --- a/release/firmware/update/fetch_test.go +++ b/release/firmware/update/fetch_test.go @@ -57,15 +57,15 @@ func TestBinPath(t *testing.T) { }{ { name: "Path From Firmware Hash", - r: ftlog.FirmwareRelease{FirmwareDigestSha256: []byte{0x12, 0x34, 0x56, 0x78}}, + r: ftlog.FirmwareRelease{Output: ftlog.Output{FirmwareDigestSha256: []byte{0x12, 0x34, 0x56, 0x78}}}, want: fmt.Sprintf("%064s", "12345678"), }, { name: "Other fields ignored", - r: ftlog.FirmwareRelease{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.9.1"), FirmwareDigestSha256: []byte{0x12, 0x34, 0x56, 0x78}}, + r: ftlog.FirmwareRelease{Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.9.1")}, Output: ftlog.Output{FirmwareDigestSha256: []byte{0x12, 0x34, 0x56, 0x78}}}, want: fmt.Sprintf("%064s", "12345678"), }, { name: "Digest unset is an error", - r: ftlog.FirmwareRelease{Component: ftlog.ComponentApplet, GitTagName: *semver.New("7.7.7")}, + r: ftlog.FirmwareRelease{Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("7.7.7")}}, wantErr: true, }, } { @@ -106,28 +106,28 @@ func TestFetcher(t *testing.T) { desc: "Rolling updates", releases: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.2.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.2.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, }, want: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.2.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.2.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, }, }, { @@ -135,94 +135,78 @@ func TestFetcher(t *testing.T) { habTarget: "orange", // only match HAB signed firmware targetting "orange" devices releases: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, { - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.4.1")}, - {HAB: &ftlog.HAB{Target: "banana"}, Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.8.1")}, // this should be ignored + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.4.1")}}, + {HAB: &ftlog.HAB{Target: "banana"}, Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.8.1")}}, // this should be ignored }, }, want: [][]ftlog.FirmwareRelease{ { - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, { - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.4.1")}, - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, - }, - }, - }, { - desc: "Missing HAB section", - habTarget: "orange", // only match HAB signed firmware targetting "orange" devices - releases: [][]ftlog.FirmwareRelease{ - { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.1.1")}, - {HAB: nil, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - }, - }, - want: [][]ftlog.FirmwareRelease{ - { - {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.1.1")}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.4.1")}}, + {HAB: &ftlog.HAB{Target: "orange"}, Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, }, }, { desc: "Finds latest within multiple revs", releases: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.2")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("2.0.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.7.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.8.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.3.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.2")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("2.0.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.7.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.8.1")}}, }, }, want: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.2")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("2.0.1")}, - {Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.7.1")}, - {Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.8.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.2")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("2.0.1")}}, + {Component: ftlog.ComponentBoot, Git: ftlog.Git{TagName: *semver.New("1.7.1")}}, + {Component: ftlog.ComponentRecovery, Git: ftlog.Git{TagName: *semver.New("1.8.1")}}, }, }, }, { desc: "ignores later lower versions", releases: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.2")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.0.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.2")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.0.1")}}, }, }, want: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.1.1")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1")}}, }, }, }, { desc: "Use log precedence", releases: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1+banana")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1+banana")}, - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1+orange")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1+orange")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1+banana")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1+banana")}}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1+orange")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1+orange")}}, }, }, want: [][]ftlog.FirmwareRelease{ { - {Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1+orange")}, - {Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1+orange")}, + {Component: ftlog.ComponentOS, Git: ftlog.Git{TagName: *semver.New("1.0.1+orange")}}, + {Component: ftlog.ComponentApplet, Git: ftlog.Git{TagName: *semver.New("1.1.1+orange")}}, }, }, }, @@ -276,7 +260,7 @@ func TestFetcher(t *testing.T) { if _, err = f.GetBoot(ctx); err != nil { t.Fatalf("GetBoot: %v", err) } - got = f.latestBoot.manifest.GitTagName + got = f.latestBoot.manifest.Git.TagName case ftlog.ComponentOS: got = os if _, err = f.GetOS(ctx); err != nil { @@ -286,10 +270,10 @@ func TestFetcher(t *testing.T) { if _, err = f.GetRecovery(ctx); err != nil { t.Fatalf("GetRecovery: %v", err) } - got = f.latestRecovery.manifest.GitTagName + got = f.latestRecovery.manifest.Git.TagName } - if got.String() != want.GitTagName.String() { + if got.String() != want.Git.TagName.String() { t.Errorf("got %v, want %v", got, want) } } @@ -299,7 +283,7 @@ func TestFetcher(t *testing.T) { } func getBinary(_ context.Context, release ftlog.FirmwareRelease) ([]byte, []byte, error) { - return []byte(release.GitTagName.String()), nil, nil + return []byte(release.Git.TagName.String()), nil, nil } func mustNewVerifierSigner(t *testing.T, vk, sk string) (note.Verifier, note.Signer) { diff --git a/release/firmware/verify.go b/release/firmware/verify.go index bcbab56..b39c180 100644 --- a/release/firmware/verify.go +++ b/release/firmware/verify.go @@ -66,7 +66,7 @@ func (v *BundleVerifier) Verify(b Bundle) (*ftlog.FirmwareRelease, error) { } h := sha256.Sum256(b.Firmware) - if manifestHash, calculatedHash := manifest.FirmwareDigestSha256, h[:]; !bytes.Equal(manifestHash, calculatedHash) { + if manifestHash, calculatedHash := manifest.Output.FirmwareDigestSha256, h[:]; !bytes.Equal(manifestHash, calculatedHash) { return nil, fmt.Errorf("firmware hash mismatch: manifest says %x but firmware bytes hash to %x", manifestHash, calculatedHash) } return &manifest, nil From 60406729b1abb3262376ebbbdb5dea7b93b57666 Mon Sep 17 00:00:00 2001 From: Martin Hutchinson Date: Tue, 20 Feb 2024 10:59:37 +0000 Subject: [PATCH 2/2] Schema version is an int, and in tests --- release/firmware/ftlog/example_firmware_release.json | 1 + release/firmware/ftlog/log_entries.go | 2 +- release/firmware/ftlog/log_entries_test.go | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/release/firmware/ftlog/example_firmware_release.json b/release/firmware/ftlog/example_firmware_release.json index 6a14852..d735434 100644 --- a/release/firmware/ftlog/example_firmware_release.json +++ b/release/firmware/ftlog/example_firmware_release.json @@ -1,4 +1,5 @@ { + "schema_version": 1, "component": "TRUSTED_APPLET", "git": { "tag_name": "0.1.2", diff --git a/release/firmware/ftlog/log_entries.go b/release/firmware/ftlog/log_entries.go index 35c1ed7..e0b923d 100644 --- a/release/firmware/ftlog/log_entries.go +++ b/release/firmware/ftlog/log_entries.go @@ -34,7 +34,7 @@ type FirmwareRelease struct { // SchemaVersion gives a unique ID for this version of the schema. This will be // incremented when there are breaking changes to the schema that all clients // should be aware of. - SchemaVersion string `json:"schema_version"` + SchemaVersion int `json:"schema_version"` // Component identifies the type of firmware (e.g. OS or applet). // This component is key to disambiguate what the firmware is, and other diff --git a/release/firmware/ftlog/log_entries_test.go b/release/firmware/ftlog/log_entries_test.go index 657027a..4a70436 100644 --- a/release/firmware/ftlog/log_entries_test.go +++ b/release/firmware/ftlog/log_entries_test.go @@ -36,6 +36,9 @@ func TestParseFirmwareRelease(t *testing.T) { if err := json.Unmarshal(bs, &r); err != nil { t.Fatalf("Unmarshal: %v", err) } + if got, want := r.SchemaVersion, 1; got != want { + t.Errorf("Got %q, want %q", got, want) + } if got, want := r.Component, ftlog.ComponentApplet; got != want { t.Errorf("Got %q, want %q", got, want) }