Skip to content

Commit

Permalink
feat(core): add ecdsa-binding encrypt flag (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmihalcik-virtru authored Sep 5, 2024
1 parent ce28555 commit 8702ec0
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 23 deletions.
1 change: 1 addition & 0 deletions .github/spellcheck.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ decrypt
decryptable
decrypted
dev
ecdsa
encodings
enum
https
Expand Down
8 changes: 7 additions & 1 deletion cmd/tdf-encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) {
if tdfType == TDF3 {
encrypted, err = h.EncryptBytes(bytesSlice, values, fileMimeType, kasURLPath)
} else if tdfType == NANO {
encrypted, err = h.EncryptNanoBytes(bytesSlice, values, kasURLPath)
ecdsaBinding := c.Flags.GetOptionalBool("ecdsa-binding")
encrypted, err = h.EncryptNanoBytes(bytesSlice, values, kasURLPath, ecdsaBinding)
} else {
cli.ExitWithError("Failed to encrypt", fmt.Errorf("unrecognized tdf-type: %s", tdfType))
}
Expand Down Expand Up @@ -151,6 +152,11 @@ func init() {
encryptCmd.GetDocFlag("tdf-type").Default,
encryptCmd.GetDocFlag("tdf-type").Description,
)
encryptCmd.Flags().Bool(
encryptCmd.GetDocFlag("ecdsa-binding").Name,
false,
encryptCmd.GetDocFlag("ecdsa-binding").Description,
)
encryptCmd.Command.GroupID = "tdf"
encryptCmd.Flags().String(
encryptCmd.GetDocFlag("kas-url-path").Name,
Expand Down
73 changes: 55 additions & 18 deletions cmd/tdf-inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cmd

import (
"errors"
"fmt"
"strings"

"github.com/opentdf/otdfctl/pkg/cli"
"github.com/opentdf/otdfctl/pkg/handlers"
Expand All @@ -24,6 +26,13 @@ type tdfInspectManifest struct {
EncryptionInformation sdk.EncryptionInformation `json:"encryptionInformation"`
}

type nanoInspectResult struct {
Cipher string `json:"cipher"`
ECDSAEnabled bool `json:"ecdsaEnabled"`
Kas string `json:"kas"`
KID string `json:"kid"`
}

type tdfInspectResult struct {
Manifest tdfInspectManifest `json:"manifest"`
Attributes []string `json:"attributes"`
Expand All @@ -42,30 +51,58 @@ func tdf_InspectCmd(cmd *cobra.Command, args []string) {
result, errs := h.InspectTDF(data)
for _, err := range errs {
if errors.Is(err, handlers.ErrTDFInspectFailNotValidTDF) {
c.ExitWithError("not a valid ZTDF", err)
c.ExitWithError("not a valid TDF", err)
} else if errors.Is(err, handlers.ErrTDFInspectFailNotInspectable) {
c.ExitWithError("failed to inspect TDF", err)
}
}

m := tdfInspectResult{
Manifest: tdfInspectManifest{
Algorithm: result.Manifest.Algorithm,
KeyAccessType: result.Manifest.KeyAccessType,
MimeType: result.Manifest.MimeType,
Policy: result.Manifest.Policy,
Protocol: result.Manifest.Protocol,
SegmentHashAlgorithm: result.Manifest.SegmentHashAlgorithm,
Signature: result.Manifest.Signature,
Type: result.Manifest.Type,
Method: result.Manifest.Method,
IntegrityInformation: result.Manifest.IntegrityInformation,
EncryptionInformation: result.Manifest.EncryptionInformation,
},
Attributes: result.Attributes,
}
if result.ZTDFManifest != nil {
m := tdfInspectResult{
Manifest: tdfInspectManifest{
Algorithm: result.ZTDFManifest.Algorithm,
KeyAccessType: result.ZTDFManifest.KeyAccessType,
MimeType: result.ZTDFManifest.MimeType,
Policy: result.ZTDFManifest.Policy,
Protocol: result.ZTDFManifest.Protocol,
SegmentHashAlgorithm: result.ZTDFManifest.SegmentHashAlgorithm,
Signature: result.ZTDFManifest.Signature,
Type: result.ZTDFManifest.Type,
Method: result.ZTDFManifest.Method,
IntegrityInformation: result.ZTDFManifest.IntegrityInformation,
EncryptionInformation: result.ZTDFManifest.EncryptionInformation,
},
Attributes: result.Attributes,
}

c.PrintJson(m)
c.PrintJson(m)
} else if result.NanoHeader != nil {
kas, err := result.NanoHeader.GetKasURL().GetURL()
if err != nil {
c.ExitWithError("not a valid NanoTDF", err)
}
kid, err := result.NanoHeader.GetKasURL().GetIdentifier()
if err != nil {
c.ExitWithError("not a valid NanoTDF", err)
}
cipher := result.NanoHeader.GetCipher()
cipherBytes, err := sdk.SizeOfAuthTagForCipher(cipher)
if err != nil {
c.ExitWithError("not a valid NanoTDF", err)
}
cipherName := fmt.Sprintf("AES-%d", 8*cipherBytes)

n := nanoInspectResult{
Kas: kas,
KID: strings.TrimRight(kid, "\u0000"),
ECDSAEnabled: result.NanoHeader.IsEcdsaBindingEnabled(),
Cipher: cipherName,
}

c.PrintJson(n)
} else {
c.ExitWithError("failed to inspect TDF", nil)
}
}

func init() {
Expand Down
2 changes: 2 additions & 0 deletions docs/man/encrypt/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ command:
- tdf3
- nano
default: tdf3
- name: ecdsa-binding
description: For nano type containers only, enables ECDSA policy binding
- name: kas-url-path
description: URL path to the KAS service at the platform endpoint domain. Leading slash is required if needed.
default: /kas
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/google/uuid v1.6.0
github.com/itchyny/gojq v0.12.16
github.com/opentdf/platform/protocol/go v0.2.14
github.com/opentdf/platform/sdk v0.3.10
github.com/opentdf/platform/sdk v0.3.12
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ github.com/opentdf/platform/protocol/go v0.2.14 h1:0wqKDVTpuPICyH37ecKxR2+tZNsgX
github.com/opentdf/platform/protocol/go v0.2.14/go.mod h1:WqDcnFQJb0v8ivRQPidbehcL8ils5ZSZYXkuv0nyvsI=
github.com/opentdf/platform/sdk v0.3.10 h1:WoPtM6IcwwDIEqCcLq2jb6pd15bFXmEDaju9MKd6JtM=
github.com/opentdf/platform/sdk v0.3.10/go.mod h1:XqFivuo4tcqxGwJF9ORnLB3S5bjrgJwiaj6BAJUXJXg=
github.com/opentdf/platform/sdk v0.3.12 h1:1WBiogmIoFseG4xj3j0NXpcQz7a8huHos2KKwaFpYDs=
github.com/opentdf/platform/sdk v0.3.12/go.mod h1:XqFivuo4tcqxGwJF9ORnLB3S5bjrgJwiaj6BAJUXJXg=
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=
Expand Down
5 changes: 4 additions & 1 deletion pkg/handlers/nano-tdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"io"
)

func (h Handler) EncryptNanoBytes(b []byte, values []string, kasUrlPath string) (*bytes.Buffer, error) {
func (h Handler) EncryptNanoBytes(b []byte, values []string, kasUrlPath string, ecdsaBinding bool) (*bytes.Buffer, error) {
var encrypted []byte
enc := bytes.NewBuffer(encrypted)

Expand All @@ -16,6 +16,9 @@ func (h Handler) EncryptNanoBytes(b []byte, values []string, kasUrlPath string)

nanoTDFConfig.SetKasURL(h.platformEndpoint + kasUrlPath)
nanoTDFConfig.SetAttributes(values)
if ecdsaBinding {
nanoTDFConfig.EnableECDSAPolicyBinding()
}

// TODO: validate values are FQNs or return an error [https://github.com/opentdf/platform/issues/515]
_, err = h.sdk.CreateNanoTDF(enc, bytes.NewReader(b), *nanoTDFConfig)
Expand Down
35 changes: 33 additions & 2 deletions pkg/handlers/tdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handlers
import (
"bytes"
"errors"
"fmt"
"io"
"strings"

Expand Down Expand Up @@ -47,12 +48,26 @@ func (h Handler) DecryptTDF(toDecrypt []byte) (*bytes.Buffer, error) {
}

type TDFInspect struct {
Manifest sdk.Manifest
NanoHeader *sdk.NanoTDFHeader
ZTDFManifest *sdk.Manifest
Attributes []string
UnencryptedMetadata []byte
}

func (h Handler) InspectTDF(toInspect []byte) (TDFInspect, []error) {
if len(toInspect) < 3 {
return TDFInspect{}, []error{fmt.Errorf("tdf too small [%d] bytes", len(toInspect))}
}
switch {
case bytes.Equal([]byte("PK"), toInspect[0:2]):
return h.InspectZTDF(toInspect)
case bytes.Equal([]byte("L1L"), toInspect[0:3]):
return h.InspectNanoTDF(toInspect)
}
return TDFInspect{}, []error{fmt.Errorf("tdf format unrecognized")}
}

func (h Handler) InspectZTDF(toInspect []byte) (TDFInspect, []error) {
// grouping errors so we don't impact the piping of the data
errs := []error{}

Expand All @@ -74,9 +89,25 @@ func (h Handler) InspectTDF(toInspect []byte) (TDFInspect, []error) {
errs = append(errs, errors.Join(ErrTDFUnableToReadUnencryptedMetadata, err))
}

m := tdfreader.Manifest()
return TDFInspect{
Manifest: tdfreader.Manifest(),
ZTDFManifest: &m,
Attributes: attributes,
UnencryptedMetadata: unencryptedMetadata,
}, errs
}

func (h Handler) InspectNanoTDF(toInspect []byte) (TDFInspect, []error) {
header, size, err := sdk.NewNanoTDFHeaderFromReader(bytes.NewReader(toInspect))
if err != nil {
return TDFInspect{}, []error{errors.Join(ErrTDFInspectFailNotValidTDF, err)}
}
r := TDFInspect{
NanoHeader: &header,
}
remainder := uint32(len(toInspect)) - size
if remainder < 18 {
return r, []error{ErrTDFInspectFailNotValidTDF}
}
return r, nil
}
9 changes: 9 additions & 0 deletions tests/encrypt-decrypt.bats
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ teardown() {
diff $INFILE_GO_MOD $RESULTFILE_GO_MOD
}

@test "roundtrip NANO, no attributes, file, ecdsa binding" {
./otdfctl encrypt -o $OUTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --ecdsa-binding --tdf-type nano $INFILE_GO_MOD
./otdfctl decrypt -o $RESULTFILE_GO_MOD --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS --tdf-type nano $OUTFILE_GO_MOD
diff $INFILE_GO_MOD $RESULTFILE_GO_MOD
./otdfctl --host $HOST --tls-no-verify $WITH_CREDS inspect $OUTFILE_GO_MOD
ecdsa_enabled="$(./otdfctl --host $HOST --tls-no-verify $WITH_CREDS inspect $OUTFILE_GO_MOD | jq .ecdsaEnabled)"
[[ "$ecdsa_enabled" == true ]]
}

@test "roundtrip NANO, one attribute, stdin" {
echo $SECRET_TEXT | ./otdfctl encrypt --tdf-type nano -o $OUT_TXT --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS -a $FQN
./otdfctl decrypt --tdf-type nano --host $HOST --tls-no-verify $DEBUG_LEVEL $WITH_CREDS $OUTFILE_TXT | grep "$SECRET_TEXT"
Expand Down

0 comments on commit 8702ec0

Please sign in to comment.