From 070f83e924cc837178a09b2b4d1089562c8f23da Mon Sep 17 00:00:00 2001
From: Bob Callaway <bobcallaway@users.noreply.github.com>
Date: Wed, 6 Oct 2021 12:49:06 -0400
Subject: [PATCH] Canonicalize JSON before inserting into trillian (#445)

Each of the supported types has a Canonicalize() method that generates a
JSON representation of the entry. If the golang library were to make a
change to the order of keys when marshalling an object, it would cause
a duplicate entry in the log for a semantically equivalent object.

This change simply transforms the JSON into RFC8785-compliant
canonicalized JSON protecting against any changes in JSON libraries
going forward.

Signed-off-by: Bob Callaway <bob.callaway@gmail.com>
---
 pkg/api/entries.go   |  4 ++--
 pkg/types/entries.go | 12 ++++++++++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/pkg/api/entries.go b/pkg/api/entries.go
index 17769e2..883e20a 100644
--- a/pkg/api/entries.go
+++ b/pkg/api/entries.go
@@ -148,7 +148,7 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
 	if err != nil {
 		return nil, handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf(validationError, err))
 	}
-	leaf, err := entry.Canonicalize(ctx)
+	leaf, err := types.CanonicalizeEntry(ctx, entry)
 	if err != nil {
 		if _, ok := (err).(types.ValidationError); ok {
 			return nil, handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf(validationError, err))
@@ -315,7 +315,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 					return err
 				}
 
-				leaf, err := entry.Canonicalize(httpReqCtx)
+				leaf, err := types.CanonicalizeEntry(httpReqCtx, entry)
 				if err != nil {
 					code = http.StatusInternalServerError
 					return err
diff --git a/pkg/types/entries.go b/pkg/types/entries.go
index 42a9bb8..e046482 100644
--- a/pkg/types/entries.go
+++ b/pkg/types/entries.go
@@ -23,6 +23,7 @@ import (
 	"net/url"
 	"reflect"
 
+	"github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer"
 	"github.com/go-openapi/strfmt"
 	"github.com/mitchellh/mapstructure"
 	"github.com/sigstore/rekor/pkg/generated/models"
@@ -105,6 +106,17 @@ func DecodeEntry(input, output interface{}) error {
 	return dec.Decode(input)
 }
 
+// CanonicalizeEntry returns the entry marshalled in JSON according to the
+// canonicalization rules of RFC8785 to protect against any changes in golang's JSON
+// marshalling logic that may reorder elements
+func CanonicalizeEntry(ctx context.Context, entry EntryImpl) ([]byte, error) {
+	canonicalEntry, err := entry.Canonicalize(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return jsoncanonicalizer.Transform(canonicalEntry)
+}
+
 // ArtifactProperties provide a consistent struct for passing values from
 // CLI flags to the type+version specific CreateProposeEntry() methods
 type ArtifactProperties struct {
-- 
GitLab