From 9f11592af633204db0a9597a7e83547c45bbd39b Mon Sep 17 00:00:00 2001 From: Hayden Blauzvern Date: Thu, 7 Sep 2023 20:58:39 +0000 Subject: [PATCH] Allow parsing base64-encoded TUF metadata and root content Because these fields are specified as objects, they can either be data.Signed{} structs when initially created, or base64-encoded strings after canonicalization and being constructed from the leaf node value. Signed-off-by: Hayden Blauzvern --- pkg/types/tuf/v0.0.1/entry.go | 51 +++++++++++++++++++++++++++--- pkg/types/tuf/v0.0.1/entry_test.go | 17 ++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/pkg/types/tuf/v0.0.1/entry.go b/pkg/types/tuf/v0.0.1/entry.go index b8413cad7..be24fd6ed 100644 --- a/pkg/types/tuf/v0.0.1/entry.go +++ b/pkg/types/tuf/v0.0.1/entry.go @@ -19,6 +19,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/base64" "encoding/hex" "encoding/json" "errors" @@ -81,11 +82,11 @@ func NewEntry() types.EntryImpl { func (v V001Entry) IndexKeys() ([]string, error) { var result []string - keyBytes, err := json.Marshal(v.TufObj.Root.Content) + keyBytes, err := v.parseRootContent() if err != nil { return nil, err } - sigBytes, err := json.Marshal(v.TufObj.Metadata.Content) + sigBytes, err := v.parseMetadataContent() if err != nil { return nil, err } @@ -160,7 +161,7 @@ func (v *V001Entry) fetchExternalEntities(ctx context.Context) (pki.PublicKey, p var contentBytes []byte if v.TufObj.Metadata.Content != nil { var err error - contentBytes, err = json.Marshal(v.TufObj.Metadata.Content) + contentBytes, err = v.parseMetadataContent() if err != nil { return closePipesOnError(err) } @@ -189,7 +190,7 @@ func (v *V001Entry) fetchExternalEntities(ctx context.Context) (pki.PublicKey, p var contentBytes []byte if v.TufObj.Root.Content != nil { var err error - contentBytes, err = json.Marshal(v.TufObj.Root.Content) + contentBytes, err = v.parseRootContent() if err != nil { return closePipesOnError(err) } @@ -373,7 +374,7 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { if v.TufObj.Root == nil { return nil, errors.New("tuf v0.0.1 entry not initialized") } - keyBytes, err := json.Marshal(v.TufObj.Root.Content) + keyBytes, err := v.parseRootContent() if err != nil { return nil, err } @@ -400,3 +401,43 @@ func (v V001Entry) Insertable() (bool, error) { } return true, nil } + +func (v V001Entry) parseRootContent() ([]byte, error) { + var keyBytes []byte + // Root.Content can either be a base64-encoded string or object + switch v := v.TufObj.Root.Content.(type) { + case string: + b, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, fmt.Errorf("base64 decoding TUF root content: %w", err) + } + keyBytes = b + default: + var err error + keyBytes, err = json.Marshal(v) + if err != nil { + return nil, err + } + } + return keyBytes, nil +} + +func (v V001Entry) parseMetadataContent() ([]byte, error) { + var sigBytes []byte + // Metadata.Content can either be a base64-encoded string or object + switch v := v.TufObj.Metadata.Content.(type) { + case string: + b, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, fmt.Errorf("base64 decoding TUF metadata content: %w", err) + } + sigBytes = b + default: + var err error + sigBytes, err = json.Marshal(v) + if err != nil { + return nil, err + } + } + return sigBytes, nil +} diff --git a/pkg/types/tuf/v0.0.1/entry_test.go b/pkg/types/tuf/v0.0.1/entry_test.go index d9d05cc94..174bb8c69 100644 --- a/pkg/types/tuf/v0.0.1/entry_test.go +++ b/pkg/types/tuf/v0.0.1/entry_test.go @@ -19,6 +19,7 @@ package tuf import ( "bytes" "context" + "encoding/base64" "encoding/json" "os" "reflect" @@ -142,6 +143,22 @@ func TestCrossFieldValidation(t *testing.T) { expectCanonicalizeSuccess: true, expectVerifierSuccess: true, }, + { + caseDesc: "root with manifest & content base64-encoded", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Root: &models.TUFV001SchemaRoot{ + Content: base64.StdEncoding.EncodeToString(keyBytes), + }, + Metadata: &models.TUFV001SchemaMetadata{ + Content: base64.StdEncoding.EncodeToString(dataBytes), + }, + }, + }, + expectUnmarshalSuccess: true, + expectCanonicalizeSuccess: true, + expectVerifierSuccess: true, + }, { caseDesc: "root with invalid key content & with manifest with content", entry: V001Entry{