diff --git a/cmd/tdf-encrypt.go b/cmd/tdf-encrypt.go index a50651e9..9186ab5c 100644 --- a/cmd/tdf-encrypt.go +++ b/cmd/tdf-encrypt.go @@ -46,6 +46,7 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) { tdfType := c.Flags.GetOptionalString("tdf-type") kasURLPath := c.Flags.GetOptionalString("kas-url-path") wrappingKeyAlgStr := c.Flags.GetOptionalString("wrapping-key-algorithm") + targetMode := c.Flags.GetOptionalString("target-mode") var wrappingKeyAlgorithm ocrypto.KeyType switch wrappingKeyAlgStr { case string(ocrypto.RSA2048Key): @@ -110,7 +111,17 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) { ) // Do the encryption - encrypted, err := h.EncryptBytes(tdfType, bytesSlice, attrValues, fileMimeType, kasURLPath, c.Flags.GetOptionalBool("ecdsa-binding"), assertions, wrappingKeyAlgorithm) + encrypted, err := h.EncryptBytes( + tdfType, + bytesSlice, + attrValues, + fileMimeType, + kasURLPath, + c.Flags.GetOptionalBool("ecdsa-binding"), + assertions, + wrappingKeyAlgorithm, + targetMode, + ) if err != nil { cli.ExitWithError("Failed to encrypt", err) } @@ -188,6 +199,11 @@ func init() { encryptCmd.GetDocFlag("kas-url-path").Default, encryptCmd.GetDocFlag("kas-url-path").Description, ) + encryptCmd.Flags().String( + encryptCmd.GetDocFlag("target-mode").Name, + encryptCmd.GetDocFlag("target-mode").Default, + encryptCmd.GetDocFlag("target-mode").Description, + ) encryptCmd.Command.GroupID = TDF RootCmd.AddCommand(&encryptCmd.Command) diff --git a/cmd/tdf-inspect.go b/cmd/tdf-inspect.go index 1b388396..3f4e82ca 100644 --- a/cmd/tdf-inspect.go +++ b/cmd/tdf-inspect.go @@ -25,6 +25,7 @@ type tdfInspectManifest struct { IntegrityInformation sdk.IntegrityInformation `json:"integrityInformation"` EncryptionInformation sdk.EncryptionInformation `json:"encryptionInformation"` Assertions []sdk.Assertion `json:"assertions,omitempty"` + SchemaVersion string `json:"schemaVersion,omitempty"` } type nanoInspectResult struct { @@ -74,6 +75,7 @@ func tdf_InspectCmd(cmd *cobra.Command, args []string) { IntegrityInformation: result.ZTDFManifest.IntegrityInformation, EncryptionInformation: result.ZTDFManifest.EncryptionInformation, Assertions: result.ZTDFManifest.Assertions, + SchemaVersion: result.ZTDFManifest.TDFVersion, }, Attributes: result.Attributes, } diff --git a/docs/man/encrypt/_index.md b/docs/man/encrypt/_index.md index 068fe242..7741dfe5 100644 --- a/docs/man/encrypt/_index.md +++ b/docs/man/encrypt/_index.md @@ -34,6 +34,9 @@ command: - name: kas-url-path description: URL path to the KAS service at the platform endpoint domain. Leading slash is required if needed. default: /kas + - name: target-mode + description: The target TDF spec version (e.g., "4.3.0"); intended for legacy compatibility and subject to removal. + default: "" - name: with-assertions description: > EXPERIMENTAL: JSON string or path to a JSON file of assertions to bind metadata to the TDF. See examples for more information. WARNING: Providing keys in a JSON string is strongly discouraged. If including sensitive keys, instead provide a path to a JSON file containing that information. @@ -135,3 +138,11 @@ Signing with HS256 is also available. ```shell otdfctl encrypt hello.txt --out hello.txt.tdf --with-assertions my_assertions_signed_hs256.json ``` + +## Target Mode + +To encrypt with a target tdf spec version, use the `--target-mode` flag. A version < 4.3.0 will include hex encoded signature hashes and will not include a schema version in the manifest. + +```shell +otdfctl encrypt hello.txt --out hello.txt.tdf --target-mode 4.3.0 +``` diff --git a/e2e/encrypt-decrypt.bats b/e2e/encrypt-decrypt.bats index 50ee356f..80880d10 100755 --- a/e2e/encrypt-decrypt.bats +++ b/e2e/encrypt-decrypt.bats @@ -134,3 +134,21 @@ teardown_file(){ echo $SECRET_TEXT | ./otdfctl encrypt --tdf-type nano -o $OUT_TXT --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS -a $MIXED_CASE_FQN ./otdfctl decrypt --tdf-type nano --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS $OUTFILE_TXT | grep "$SECRET_TEXT" } + +@test "roundtrip TDF3, with target version < 4.3.0" { + ./otdfctl encrypt -o $OUTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --tdf-type tdf3 --target-mode v4.2.2 $INFILE_GO_MOD + ./otdfctl decrypt -o $RESULTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --tdf-type tdf3 $OUTFILE_GO_MOD + diff $INFILE_GO_MOD $RESULTFILE_GO_MOD + + schema_version_present=$(./otdfctl --host $HOST --tls-no-verify $WITH_CREDS inspect $OUTFILE_GO_MOD | jq '.manifest | has("schemaVersion")') + [[ $schema_version_present == false ]] +} + +@test "roundtrip TDF3, with target version >= 4.3.0" { + ./otdfctl encrypt -o $OUTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --tdf-type tdf3 --target-mode v4.3.1 $INFILE_GO_MOD + ./otdfctl decrypt -o $RESULTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --tdf-type tdf3 $OUTFILE_GO_MOD + diff $INFILE_GO_MOD $RESULTFILE_GO_MOD + + schema_version_present=$(./otdfctl --host $HOST --tls-no-verify $WITH_CREDS inspect $OUTFILE_GO_MOD | jq '.manifest | has("schemaVersion")') + [[ $schema_version_present == true ]] +} diff --git a/go.mod b/go.mod index 95625536..0511de02 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/opentdf/platform/lib/flattening v0.1.3 github.com/opentdf/platform/lib/ocrypto v0.1.9 github.com/opentdf/platform/protocol/go v0.2.29 - github.com/opentdf/platform/sdk v0.3.29 + github.com/opentdf/platform/sdk v0.4.1 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 @@ -34,6 +34,7 @@ require ( al.essio.dev/pkg/shellescape v1.5.1 // indirect buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240508200655-46a4cf4ba109.2 // indirect github.com/BurntSushi/toml v0.3.1 // indirect + github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -58,7 +59,7 @@ require ( github.com/gorilla/securecookie v1.1.2 // indirect github.com/gowebpki/jcs v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect diff --git a/go.sum b/go.sum index cbca203c..6106ef05 100644 --- a/go.sum +++ b/go.sum @@ -8,10 +8,10 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.12.0 h1:rbICA+XZFwrBef2Odk++0LjFvClNCJGRK+fsrP254Ts= -github.com/Microsoft/hcsshim v0.12.0/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g= github.com/Nerzal/gocloak/v13 v13.9.0 h1:YWsJsdM5b0yhM2Ba3MLydiOlujkBry4TtdzfIzSVZhw= github.com/Nerzal/gocloak/v13 v13.9.0/go.mod h1:YYuDcXZ7K2zKECyVP7pPqjKxx2AzYSpKDj8d6GuyM10= github.com/adrg/frontmatter v0.2.0 h1:/DgnNe82o03riBd1S+ZDjd43wAmC6W35q67NHeLkPd4= @@ -56,14 +56,14 @@ github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6Uo github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= -github.com/containerd/containerd v1.7.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= -github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= +github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII= +github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= -github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= -github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= @@ -141,8 +141,8 @@ github.com/gowebpki/jcs v1.0.1 h1:Qjzg8EOkrOTuWP7DqQ1FbYtcpEbeTzUoTN9bptp8FOU= github.com/gowebpki/jcs v1.0.1/go.mod h1:CID1cNZ+sHp1CCpAR8mPf6QRtagFBgPJE0FCUQ6+BrI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -228,8 +228,8 @@ github.com/opentdf/platform/lib/ocrypto v0.1.9 h1:GvgPB7CoK7JmWvsSvJ0hc+RC0wezgc github.com/opentdf/platform/lib/ocrypto v0.1.9/go.mod h1:UTtqh8mvhAYA+sEnaMxpr/406e84L5Q1sAxtKGIXfu4= github.com/opentdf/platform/protocol/go v0.2.29 h1:2L/uylxl49ALIqQwg4wmVEfxeUozM3ITpFuahmbHJ+U= github.com/opentdf/platform/protocol/go v0.2.29/go.mod h1:eldxqX2oF2ADtG8ivhfwn1lALVMX4aaUM+Lp9ynOJXs= -github.com/opentdf/platform/sdk v0.3.29 h1:ihTauf25sdgBKwBvK4GzFktSVINDLnwNch7xpLt88AY= -github.com/opentdf/platform/sdk v0.3.29/go.mod h1:GeN7MqqIwop5sMBAPGR28ZIKXSOHAHaECma/ppsXoiw= +github.com/opentdf/platform/sdk v0.4.1 h1:EVRbaqkob/R/QTVI7xRqyFe3XZ6efmTOkFY4afwaGjo= +github.com/opentdf/platform/sdk v0.4.1/go.mod h1:hqgvKdBceKoIcSm4Hlp8r2i9i33tbL0ORuGbnC5DFX0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= @@ -294,8 +294,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= -github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= +github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= +github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= diff --git a/pkg/handlers/tdf.go b/pkg/handlers/tdf.go index 6eca0fe7..ef2e54c5 100644 --- a/pkg/handlers/tdf.go +++ b/pkg/handlers/tdf.go @@ -48,6 +48,7 @@ func (h Handler) EncryptBytes( ecdsaBinding bool, assertions string, wrappingKeyAlgorithm ocrypto.KeyType, + targetMode string, ) (*bytes.Buffer, error) { var encrypted []byte enc := bytes.NewBuffer(encrypted) @@ -95,6 +96,10 @@ func (h Handler) EncryptBytes( opts = append(opts, sdk.WithAssertions(assertionConfigs...)) } + if targetMode != "" { + opts = append(opts, sdk.WithTargetMode(targetMode)) + } + _, err := h.sdk.CreateTDF(enc, bytes.NewReader(unencrypted), opts...) return enc, err