Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate tree ID on calls to /api/v1/log/entries/retrieve #1017

Merged
merged 2 commits into from Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 10 additions & 6 deletions pkg/api/entries.go
Expand Up @@ -330,15 +330,19 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo

var searchHashes [][]byte
for _, entryID := range params.Entry.EntryUUIDs {
uuid, err := sharding.GetUUIDFromIDString(entryID)
if err != nil {
return handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf("could not get UUID from ID string %v", entryID))
}
if logEntry, err := retrieveLogEntry(httpReqCtx, entryID); err == nil {
if sharding.ValidateEntryID(entryID) == nil {
logEntry, err := retrieveLogEntry(httpReqCtx, entryID)
if err != nil {
return handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf("error getting log entry for %s", entryID))
}
resultPayload = append(resultPayload, logEntry)
continue
}
// If we couldn't get the entry, search for the hash later
// At this point, check if we got a uuid instead of an EntryID, so search for the hash later
uuid := entryID
if err := sharding.ValidateUUID(uuid); err != nil {
return handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf("validating uuid %s", uuid))
}
hash, err := hex.DecodeString(uuid)
if err != nil {
return handleRekorAPIError(params, http.StatusBadRequest, err, malformedUUID)
Expand Down
69 changes: 63 additions & 6 deletions tests/e2e_test.go
Expand Up @@ -279,12 +279,7 @@ func TestGetCLI(t *testing.T) {
outputContains(t, out, uuid)

// Exercise GET with the new EntryID (TreeID + UUID)
out = runCli(t, "loginfo")
tidStr := strings.TrimSpace(strings.Split(out, "TreeID: ")[1])
tid, err := strconv.ParseInt(tidStr, 10, 64)
if err != nil {
t.Errorf(err.Error())
}
tid := getTreeID(t)
entryID, err := sharding.CreateEntryIDFromParts(fmt.Sprintf("%x", tid), uuid)
if err != nil {
t.Error(err)
Expand Down Expand Up @@ -1219,3 +1214,65 @@ func getBody(t *testing.T, limit int) []byte {
s += "]}"
return []byte(s)
}

func getTreeID(t *testing.T) int64 {
out := runCli(t, "loginfo")
tidStr := strings.TrimSpace(strings.Split(out, "TreeID: ")[1])
tid, err := strconv.ParseInt(tidStr, 10, 64)
if err != nil {
t.Errorf(err.Error())
}
t.Log("Tree ID:", tid)
return tid
}

// This test confirms that we validate tree ID when using the /api/v1/log/entries/retrieve endpoint
// https://github.com/sigstore/rekor/issues/1014
func TestSearchValidateTreeID(t *testing.T) {
// Create something and add it to the log
artifactPath := filepath.Join(t.TempDir(), "artifact")
sigPath := filepath.Join(t.TempDir(), "signature.asc")

createdPGPSignedArtifact(t, artifactPath, sigPath)

// Write the public key to a file
pubPath := filepath.Join(t.TempDir(), "pubKey.asc")
if err := ioutil.WriteFile(pubPath, []byte(publicKey), 0644); err != nil {
t.Fatal(err)
}
out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
outputContains(t, out, "Created entry at")

uuid, err := sharding.GetUUIDFromIDString(getUUIDFromUploadOutput(t, out))
if err != nil {
t.Error(err)
}
// Make sure we can get by Entry ID
tid := getTreeID(t)
entryID, err := sharding.CreateEntryIDFromParts(fmt.Sprintf("%x", tid), uuid)
if err != nil {
t.Fatal(err)
}
body := "{\"entryUUIDs\":[\"%s\"]}"
resp, err := http.Post("http://localhost:3000/api/v1/log/entries/retrieve", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(body, entryID.ReturnEntryIDString()))))
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != 200 {
t.Fatalf("expected 200 status code but got %d", resp.StatusCode)
}

// Make sure we fail with a random tree ID
fakeTID := tid + 1
entryID, err = sharding.CreateEntryIDFromParts(fmt.Sprintf("%x", fakeTID), uuid)
if err != nil {
t.Fatal(err)
}
resp, err = http.Post("http://localhost:3000/api/v1/log/entries/retrieve", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(body, entryID.ReturnEntryIDString()))))
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != 400 {
t.Fatalf("expected 400 status code but got %d", resp.StatusCode)
}
}