aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Hou <jayhou@google.com>2022-03-24 02:46:39 -0700
committerJay Hou <jayhou@google.com>2022-03-27 14:20:50 -0700
commit4492f6f2d9033c682b2792fe4eb2da5af0a20ecb (patch)
tree6f7a54c515f3d31d2bc912f56d1415096c7588b2
parent8ffd7d65992dd402d3832d0c2f6c948433543c4e (diff)
downloadavb-4492f6f2d9033c682b2792fe4eb2da5af0a20ecb.tar.gz
Look up payload (log entry) from image_info.txt rather than ask for the index as a parameter.
This provides for a better user experience, since we have this information on hand already. Test: go test ./... and ran ./verifier with payload. Signed-off-by: Jay Hou <jayhou@google.com> Change-Id: Ia6d06dba7855352cecdcbaa72ad6ec5d898f7c13
-rw-r--r--tools/transparency/verify/README.md12
-rw-r--r--tools/transparency/verify/cmd/verifier/verifier.go57
-rw-r--r--tools/transparency/verify/internal/tiles/reader.go39
-rw-r--r--tools/transparency/verify/internal/tiles/reader_test.go39
4 files changed, 115 insertions, 32 deletions
diff --git a/tools/transparency/verify/README.md b/tools/transparency/verify/README.md
index a8da1ee..c69fb05 100644
--- a/tools/transparency/verify/README.md
+++ b/tools/transparency/verify/README.md
@@ -1,6 +1,6 @@
# Verifier of Binary Transparency for Pixel Factory Images
-This repository contains code to read the transparency log for [Binary Transparency for Pixel Factory Images](https://developers.google.com/android/binary_transparency/pixel).
+This repository contains code to read the transparency log for [Binary Transparency for Pixel Factory Images](https://developers.google.com/android/binary_transparency/pixel). See the particular section for this tool [here](https://developers.google.com/android/binary_transparency/pixel#verifying-image-inclusion-inclusion-proof).
## Files and Directories
* `cmd/verifier/`
@@ -16,13 +16,13 @@ An executable named `verifier` should be produced upon successful build.
## Usage
The verifier uses the checkpoint and the log contents (found at the [tile directory](https://developers.google.com/android/binary_transparency/tile)) to check that your image payload is in the transparency log, i.e. that it is published by Google.
-To run the verifier after you have built it in the preious section:
+To run the verifier after you have built it in the previous section:
```
-$ ./verifier --payload_path=${PAYLOAD_PATH} --image_info_index=${IMAGE_INFO_INDEX}
+$ ./verifier --payload_path=${PAYLOAD_PATH}
```
-### Inputs
-The verifier takes two inputs: `payload_path` and `image_info_index`.
+### Input
+The verifier takes a `payload_path` as input.
Each Pixel Factory image corresponds to a [payload](https://developers.google.com/android/binary_transparency/pixel#log-content) stored in the transparency log, the format of which is:
```
@@ -30,8 +30,6 @@ Each Pixel Factory image corresponds to a [payload](https://developers.google.co
```
See [here](https://developers.google.com/android/binary_transparency/pixel#construct-the-payload-for-verification) for a few methods detailing how to extract this payload from an image.
-Set `image_info_index` to the index of your payload of interest in this list: [image\_info.txt](https://developers.google.com/android/binary_transparency/image_info.txt).
-
### Output
The output of the command is written to stdout:
* `OK` if the image is included in the log, i.e. that this [claim](https://developers.google.com/android/binary_transparency/pixel#claimant-model) is true,
diff --git a/tools/transparency/verify/cmd/verifier/verifier.go b/tools/transparency/verify/cmd/verifier/verifier.go
index 08fa727..d565f63 100644
--- a/tools/transparency/verify/cmd/verifier/verifier.go
+++ b/tools/transparency/verify/cmd/verifier/verifier.go
@@ -20,14 +20,12 @@
package main
import (
- // Using "flag" and "log" and not their "google3/base/go/" counterparts is
- // intended in order to reduce google3 dependencies. This code will live in
- // https://android.googlesource.com/platform/external/avb/+/master/tools/transparency/.
+ "bytes"
"crypto/sha256"
"flag"
- "fmt"
"log"
"os"
+ "path/filepath"
"github.com/google/binary_transparency/verifier/internal/checkpoint"
"github.com/google/binary_transparency/verifier/internal/tiles"
@@ -48,20 +46,27 @@ const (
var logPubKey []byte
var (
- imageInfoIndex = flag.Int64("image_info_index", -1, "Index representing the image of interest within the image_info.txt log file. Must be in the [0, logSize) range.")
- payloadPath = flag.String("payload_path", "", "Path to the payload describing the image of interest.")
- logBaseURL = flag.String("log_base_url", "https://developers.google.com/android/binary_transparency", "Base url for the verifiable log files.")
+ payloadPath = flag.String("payload_path", "", "Path to the payload describing the image of interest.")
+ logBaseURL = flag.String("log_base_url", "https://developers.google.com/android/binary_transparency", "Base url for the verifiable log files.")
)
func main() {
flag.Parse()
- if *imageInfoIndex < 0 {
- log.Fatal("must specify the image_info_index, in the [0, logSize) range, for the image of interest")
- }
if *payloadPath == "" {
log.Fatal("must specify the payload_path for the image payload")
}
+ b, err := os.ReadFile(*payloadPath)
+ if err != nil {
+ log.Fatalf("unable to open file %q: %v", *payloadPath, err)
+ }
+ // Payload should not contain excessive leading or trailing whitespace.
+ payloadBytes := bytes.TrimSpace(b)
+ payloadBytes = append(payloadBytes, '\n')
+ if string(b) != string(payloadBytes) {
+ log.Printf("Reformatted payload content from %q to %q", b, payloadBytes)
+ }
+
v, err := checkpoint.NewVerifier(logPubKey, KeyNameForVerifier)
if err != nil {
@@ -72,41 +77,43 @@ func main() {
log.Fatalf("error reading checkpoint for log(%s): %v", *logBaseURL, err)
}
- logSize := int64(root.Size)
- if *imageInfoIndex >= logSize {
- log.Fatalf("leaf_index must be in the [0, logSize) range: logSize=%d", logSize)
+ m, err := tiles.ImageInfosIndex(*logBaseURL)
+ if err != nil {
+ log.Fatalf("failed to load image info map to find log index: %v", err)
+ }
+ imageInfoIndex, ok := m[string(payloadBytes)]
+ if !ok {
+ log.Fatalf("failed to find payload %q in %s", string(payloadBytes), filepath.Join(*logBaseURL, "image_info.txt"))
}
+
var th tlog.Hash
copy(th[:], root.Hash)
+ logSize := int64(root.Size)
r := tiles.HashReader{URL: *logBaseURL}
- rp, err := tlog.ProveRecord(logSize, *imageInfoIndex, r)
+ rp, err := tlog.ProveRecord(logSize, imageInfoIndex, r)
if err != nil {
log.Fatalf("error in tlog.ProveRecord: %v", err)
}
- leafHash, err := payloadHash(*payloadPath)
+ leafHash, err := payloadHash(payloadBytes)
if err != nil {
log.Fatalf("error hashing payload: %v", err)
}
- if err := tlog.CheckRecord(rp, logSize, th, *imageInfoIndex, leafHash); err != nil {
+ if err := tlog.CheckRecord(rp, logSize, th, imageInfoIndex, leafHash); err != nil {
log.Fatalf("FAILURE: inclusion check error in tlog.CheckRecord: %v", err)
} else {
log.Print("OK. inclusion check success")
}
}
-// payloadHash returns the hash for the payload located at path p.
-func payloadHash(p string) (tlog.Hash, error) {
- var hash tlog.Hash
- f, err := os.ReadFile(p)
- if err != nil {
- return hash, fmt.Errorf("unable to open file %q: %v", p, err)
- }
- l := append([]byte{LeafHashPrefix}, f...)
+// payloadHash returns the hash of the payload.
+func payloadHash(p []byte) (tlog.Hash, error) {
+ l := append([]byte{LeafHashPrefix}, p...)
h := sha256.Sum256(l)
- copy(hash[:], h[:])
+ var hash tlog.Hash
+ copy(hash[:], h[:])
return hash, nil
}
diff --git a/tools/transparency/verify/internal/tiles/reader.go b/tools/transparency/verify/internal/tiles/reader.go
index 5ebbb5e..b0993f1 100644
--- a/tools/transparency/verify/internal/tiles/reader.go
+++ b/tools/transparency/verify/internal/tiles/reader.go
@@ -2,11 +2,14 @@
package tiles
import (
+ "errors"
"fmt"
"io"
"net/http"
"net/url"
"path"
+ "strconv"
+ "strings"
"golang.org/x/mod/sumdb/tlog"
)
@@ -47,6 +50,42 @@ func (h HashReader) ReadHashes(indices []int64) ([]tlog.Hash, error) {
return hashes, nil
}
+// ImageInfosIndex returns a map from payload to its index in the
+// transparency log according to the image_info.txt.
+func ImageInfosIndex(logBaseURL string) (map[string]int64, error) {
+ b, err := readFromURL(logBaseURL, "image_info.txt")
+ if err != nil {
+ return nil, err
+ }
+
+ imageInfos := string(b)
+ return parseImageInfosIndex(imageInfos)
+}
+
+func parseImageInfosIndex(imageInfos string) (map[string]int64, error) {
+ m := make(map[string]int64)
+
+ infosStr := strings.Split(imageInfos, "\n\n")
+ for _, infoStr := range infosStr {
+ pieces := strings.SplitN(infoStr, "\n", 2)
+ if len(pieces) != 2 {
+ return nil, errors.New("missing newline, malformed image_info.txt")
+ }
+
+ idx, err := strconv.ParseInt(pieces[0], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("failed to convert %q to int64", pieces[0])
+ }
+
+ // Ensure that each log entry does not have extraneous whitespace, but
+ // also terminates with a newline.
+ logEntry := strings.TrimSpace(pieces[1]) + "\n"
+ m[logEntry] = idx
+ }
+
+ return m, nil
+}
+
func readFromURL(base, suffix string) ([]byte, error) {
u, err := url.Parse(base)
if err != nil {
diff --git a/tools/transparency/verify/internal/tiles/reader_test.go b/tools/transparency/verify/internal/tiles/reader_test.go
index 3d0be09..47e26c3 100644
--- a/tools/transparency/verify/internal/tiles/reader_test.go
+++ b/tools/transparency/verify/internal/tiles/reader_test.go
@@ -141,3 +141,42 @@ func TestReadHashesCachedTile(t *testing.T) {
t.Errorf("wrong ReadHashes result: got %X, want %X", got[0], wantHash)
}
}
+
+func TestParseImageInfosIndex(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ imageInfos string
+ want map[string]int64
+ wantErr bool
+ }{
+ {
+ desc: "size 2",
+ imageInfos: "0\nbuild_fingerprint0\nimage_digest0\n\n1\nbuild_fingerprint1\nimage_digest1\n",
+ wantErr: false,
+ want: map[string]int64{
+ "build_fingerprint0\nimage_digest0\n": 0,
+ "build_fingerprint1\nimage_digest1\n": 1,
+ },
+ },
+ {
+ desc: "invalid log entry (no newlines)",
+ imageInfos: "0build_fingerprintimage_digest",
+ wantErr: true,
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ got, err := parseImageInfosIndex(tc.imageInfos)
+ if err != nil && !tc.wantErr {
+ t.Fatalf("parseImageInfosIndex(%s) received unexpected err %q", tc.imageInfos, err)
+ }
+
+ if err == nil && tc.wantErr {
+ t.Fatalf("parseImageInfosIndex(%s) did not return err, expected err", tc.imageInfos)
+ }
+
+ if diff := cmp.Diff(tc.want, got); diff != "" {
+ t.Errorf("parseImageInfosIndex returned unexpected diff (-want +got):\n%s", diff)
+ }
+ })
+ }
+}