diff --git a/docs/grpc/index.html b/docs/grpc/index.html
index 2071a7b4db..cc84d00f71 100644
--- a/docs/grpc/index.html
+++ b/docs/grpc/index.html
@@ -1679,7 +1679,7 @@
PublicKey
local |
string |
|
- public key - optional since can also be retrieved via url |
+ Deprecated. public key; PEM of RSA public key; prefer `cached` |
@@ -1693,6 +1693,27 @@ PublicKey
+
+
+ Fields with deprecated option
+
+
+
+ | Name |
+ Option |
+
+
+
+
+
+ | local |
+ true |
+
+
+
+
+
+
diff --git a/docs/openapi/policy/attributes/attributes.swagger.json b/docs/openapi/policy/attributes/attributes.swagger.json
index 01d68183d2..195eaa9e8a 100644
--- a/docs/openapi/policy/attributes/attributes.swagger.json
+++ b/docs/openapi/policy/attributes/attributes.swagger.json
@@ -1091,7 +1091,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/docs/openapi/policy/kasregistry/key_access_server_registry.swagger.json b/docs/openapi/policy/kasregistry/key_access_server_registry.swagger.json
index af67abf55a..2b269b788a 100644
--- a/docs/openapi/policy/kasregistry/key_access_server_registry.swagger.json
+++ b/docs/openapi/policy/kasregistry/key_access_server_registry.swagger.json
@@ -444,7 +444,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/docs/openapi/policy/namespaces/namespaces.swagger.json b/docs/openapi/policy/namespaces/namespaces.swagger.json
index aad8b5f1ad..95d3e07cdc 100644
--- a/docs/openapi/policy/namespaces/namespaces.swagger.json
+++ b/docs/openapi/policy/namespaces/namespaces.swagger.json
@@ -492,7 +492,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json b/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json
index 63e2b9ae9d..7c5ae24d92 100644
--- a/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json
+++ b/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json
@@ -457,7 +457,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json b/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json
index c32d59a988..41847340a4 100644
--- a/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json
+++ b/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json
@@ -659,7 +659,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/docs/openapi/policy/unsafe/unsafe.swagger.json b/docs/openapi/policy/unsafe/unsafe.swagger.json
index a917b49d1f..ccde3740da 100644
--- a/docs/openapi/policy/unsafe/unsafe.swagger.json
+++ b/docs/openapi/policy/unsafe/unsafe.swagger.json
@@ -605,7 +605,7 @@
},
"local": {
"type": "string",
- "title": "public key - optional since can also be retrieved via url"
+ "title": "public key; PEM of RSA public key; prefer `cached`"
},
"cached": {
"$ref": "#/definitions/policyKasPublicKeySet",
diff --git a/examples/cmd/attributes.go b/examples/cmd/attributes.go
index 1c9f8bb941..7720d4ab7c 100644
--- a/examples/cmd/attributes.go
+++ b/examples/cmd/attributes.go
@@ -21,10 +21,10 @@ import (
var (
ns string
attr string
- kas string
+ kases []string
longformat bool
rule string
- values string
+ values []string
unsafeBool bool
)
@@ -43,7 +43,7 @@ func init() {
}
add.Flags().StringVarP(&attr, "attr", "a", "", "attribute prefix, e.g. http://name.space/attr/name")
add.Flags().StringVarP(&rule, "rule", "", "allof", "attribute type, either allof, anyof, or hierarchy")
- add.Flags().StringVarP(&values, "values", "v", "", "list of attribute values")
+ add.Flags().StringSliceVarP(&values, "values", "v", []string{}, "list of attribute values")
attributes.AddCommand(add)
assign := &cobra.Command{
@@ -54,8 +54,8 @@ func init() {
},
}
assign.Flags().StringVarP(&attr, "attr", "a", "", "attribute prefix, e.g. https://name.space/attr/name")
- assign.Flags().StringVarP(&kas, "kas", "k", "", "which kas to assign")
- assign.Flags().StringVarP(&values, "values", "v", "", "any attribute values to include; if empty, applies to all")
+ assign.Flags().StringSliceVarP(&kases, "kas", "k", []string{}, "which kas to assign")
+ assign.Flags().StringSliceVarP(&values, "values", "v", []string{}, "any attribute values to include; if empty, applies to all")
attributes.AddCommand(assign)
list := &cobra.Command{
@@ -80,7 +80,7 @@ func init() {
},
}
remove.Flags().StringVarP(&attr, "attr", "a", "", "attribute prefix, e.g. http://name.space/attr/name")
- remove.Flags().StringVarP(&values, "values", "v", "", "list of attribute values to remove; if absent, removes all")
+ remove.Flags().StringSliceVarP(&values, "values", "v", []string{}, "list of attribute values to remove; if absent, removes all")
remove.Flags().BoolVarP(&unsafeBool, "unsafe", "f", false, "delete for real; otherwise deactivate (soft delete)")
attributes.AddCommand(remove)
@@ -92,8 +92,8 @@ func init() {
},
}
unassign.Flags().StringVarP(&attr, "attr", "a", "", "attribute prefix, e.g. https://name.space/attr/name")
- unassign.Flags().StringVarP(&kas, "kas", "k", "", "which kas to assign")
- unassign.Flags().StringVarP(&values, "values", "v", "", "any attribute values to include; if empty, applies to all")
+ unassign.Flags().StringSliceVarP(&kases, "kas", "k", []string{}, "which kases to assign")
+ unassign.Flags().StringSliceVarP(&values, "values", "v", []string{}, "any attribute values to include; if empty, applies to all")
attributes.AddCommand(unassign)
ExamplesCmd.AddCommand(attributes)
@@ -245,7 +245,7 @@ func addAttribute(cmd *cobra.Command) error {
slog.Error("url.PathUnescape(attr)", "err", err, "attr", m[2])
return err
}
- aid, err := upsertAttr(cmd.Context(), s, nsu, attr, strings.Split(values, " "))
+ aid, err := upsertAttr(cmd.Context(), s, nsu, attr, values)
if err != nil {
return err
}
@@ -275,7 +275,7 @@ func removeAttribute(cmd *cobra.Command) error {
if err != nil {
return err
}
- if values == "" {
+ if len(values) == 0 {
if unsafeBool {
resp, err := s.Unsafe.UnsafeDeleteAttribute(cmd.Context(), &unsafe.UnsafeDeleteAttributeRequest{
Id: auuid,
@@ -298,7 +298,7 @@ func removeAttribute(cmd *cobra.Command) error {
slog.Info("deactivated attribute", "attr", attr, "resp", resp)
return nil
} else {
- for _, v := range strings.Split(values, " ") {
+ for _, v := range values {
avu, err := avuuid(cmd.Context(), s, auuid, v)
if err != nil {
return err
@@ -359,16 +359,18 @@ func assignAttribute(cmd *cobra.Command, assign bool) error {
var kasids []string
switch {
- case kas != "":
- kasid, err := upsertKasRegistration(cmd.Context(), s, kas, nil)
- if err != nil {
- return err
+ case len(kases) != 0:
+ for _, kas := range kases {
+ kasid, err := upsertKasRegistration(cmd.Context(), s, kas, nil)
+ if err != nil {
+ return err
+ }
+ kasids = append(kasids, kasid)
+ kasById[kasid] = kas
}
- kasids = append(kasids, kasid)
- kasById[kasid] = kas
case assign:
return fmt.Errorf("assign must take a `--kas` parameter")
- case values == "":
+ case len(values) == 0:
// look up all kasids associated with the attribute
ar, err := s.Attributes.GetAttribute(cmd.Context(), &attributes.GetAttributeRequest{Id: auuid})
if err != nil {
@@ -378,12 +380,11 @@ func assignAttribute(cmd *cobra.Command, assign bool) error {
kasids = append(kasids, b.GetId())
kasById[b.GetId()] = b.GetUri()
}
+ case len(values) > 1:
+ return fmt.Errorf("TODO: unassign from multiple values at a time")
default:
// look up all kasids associated with the value
- if strings.Index(values, " ") >= 0 {
- return fmt.Errorf("TODO: unassign from multiple values at a time")
- }
- avu, err := avuuid(cmd.Context(), s, auuid, values)
+ avu, err := avuuid(cmd.Context(), s, auuid, values[0])
if err != nil {
return err
}
@@ -398,7 +399,7 @@ func assignAttribute(cmd *cobra.Command, assign bool) error {
}
for _, kasid := range kasids {
- if values == "" {
+ if len(values) == 0 {
if assign {
r, err := s.Attributes.AssignKeyAccessServerToAttribute(cmd.Context(), &attributes.AssignKeyAccessServerToAttributeRequest{
AttributeKeyAccessServer: &attributes.AttributeKeyAccessServer{
@@ -423,7 +424,7 @@ func assignAttribute(cmd *cobra.Command, assign bool) error {
cmd.Printf("successfully unassigned [%s] from [%s] (binding %v)\n", attr, kasById[kasid], *r.GetAttributeKeyAccessServer())
}
} else {
- for _, v := range strings.Split(values, " ") {
+ for _, v := range values {
avu, err := avuuid(cmd.Context(), s, auuid, v)
if err != nil {
return err
diff --git a/examples/cmd/kas.go b/examples/cmd/kas.go
index 54474e47ef..ee80745440 100644
--- a/examples/cmd/kas.go
+++ b/examples/cmd/kas.go
@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
-var key string
+var algorithm, kas, key, keyIdentifier string
func init() {
kasc := &cobra.Command{
@@ -28,8 +28,12 @@ func init() {
return updateKas(cmd)
},
}
+ // Note we currently only store one pk at a time. must be fixed for nano tests
+ update.Flags().StringVarP(&algorithm, "algorithm", "", "", "algorithm used with the public key")
update.Flags().StringVarP(&kas, "kas", "k", "", "kas uri")
update.Flags().StringVarP(&key, "public-key", "", "", "public key value, e.g. $( 1 {
splitID = genSplitID()
}
for _, o := range v.values {
- p = append(p, SplitStep{KAS: o.kas, SplitID: splitID})
+ p = append(p, keySplitStep{KAS: o.kas, SplitID: splitID})
}
}
return p, nil
}
-func (r Granter) constructAttributeBoolean() *attributeBooleanExpression {
+func (r granter) constructAttributeBoolean() *attributeBooleanExpression {
prefixes := make(map[string]*singleAttributeClause)
sortedPrefixes := make([]string, 0)
for _, aP := range r.policy {
@@ -447,7 +451,7 @@ func ruleToOperator(e policy.AttributeRuleTypeEnum) string {
return ""
}
-func (r *Granter) insertKeysForAttribute(e attributeBooleanExpression) (booleanKeyExpression, error) {
+func (r *granter) insertKeysForAttribute(e attributeBooleanExpression) (booleanKeyExpression, error) {
kcs := make([]keyClause, 0, len(e.must))
for _, clause := range e.must {
kcv := make([]publicKeyInfo, 0, len(clause.values))
diff --git a/sdk/internal/autoconfigure/granter_test.go b/sdk/granter_test.go
similarity index 88%
rename from sdk/internal/autoconfigure/granter_test.go
rename to sdk/granter_test.go
index 3a4b76bc77..bd01e53f0b 100644
--- a/sdk/internal/autoconfigure/granter_test.go
+++ b/sdk/granter_test.go
@@ -1,4 +1,4 @@
-package autoconfigure
+package sdk
import (
"fmt"
@@ -13,13 +13,13 @@ import (
)
const (
- kasAu = "http://kas.au/"
- kasCa = "http://kas.ca/"
- kasUk = "http://kas.uk/"
- kasNz = "http://kas.nz/"
- kasUs = "http://kas.us/"
- kasUsHCS = "http://hcs.kas.us/"
- kasUsSA = "http://si.kas.us/"
+ kasAu = "https://kas.au/"
+ kasCa = "https://kas.ca/"
+ kasUk = "https://kas.uk/"
+ kasNz = "https://kas.nz/"
+ kasUs = "https://kas.us/"
+ kasUsHCS = "https://hcs.kas.us/"
+ kasUsSA = "https://si.kas.us/"
authority = "https://virtru.com/"
)
@@ -38,7 +38,7 @@ var (
n2kSI, _ = NewAttributeValueFQN("https://virtru.com/attr/Need%20to%20Know/value/SI")
// rel25eye, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/FVEY")
- // rel2aus, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/AUS")
+ rel2aus, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/AUS")
rel2can, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/CAN")
rel2gbr, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/GBR")
rel2nzl, _ = NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/NZL")
@@ -118,6 +118,7 @@ func mockAttributeFor(fqn AttributeNameFQN) *policy.Attribute {
}
return nil
}
+
func mockValueFor(fqn AttributeValueFQN) *policy.Value {
an := fqn.Prefix()
a := mockAttributeFor(an)
@@ -284,7 +285,7 @@ func TestConfigurationServicePutGet(t *testing.T) {
} {
t.Run(tc.n, func(t *testing.T) {
v := valuesToPolicy(tc.policy...)
- grants, err := NewGranterFromAttributes(v...)
+ grants, err := newGranterFromAttributes(v...)
require.NoError(t, err)
assert.Len(t, grants.grants, tc.size)
assert.Subset(t, policyToStringKeys(tc.policy), maps.Keys(grants.grants))
@@ -306,16 +307,16 @@ func TestReasonerConstructAttributeBoolean(t *testing.T) {
policy []AttributeValueFQN
defaults []string
ats, keyed, reduced string
- plan []SplitStep
+ plan []keySplitStep
}{
{
"one actual with default",
[]AttributeValueFQN{clsS, rel2can},
[]string{kasUs},
"https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/CAN",
- "[DEFAULT]&(http://kas.ca/)",
- "(http://kas.ca/)",
- []SplitStep{{kasCa, ""}},
+ "[DEFAULT]&(https://kas.ca/)",
+ "(https://kas.ca/)",
+ []keySplitStep{{kasCa, ""}},
},
{
"one defaulted attr",
@@ -324,7 +325,7 @@ func TestReasonerConstructAttributeBoolean(t *testing.T) {
"https://virtru.com/attr/Classification/value/Secret",
"[DEFAULT]",
"",
- []SplitStep{{kasUs, ""}},
+ []keySplitStep{{kasUs, ""}},
},
{
"empty policy",
@@ -333,7 +334,7 @@ func TestReasonerConstructAttributeBoolean(t *testing.T) {
"∅",
"",
"",
- []SplitStep{{kasUs, ""}},
+ []keySplitStep{{kasUs, ""}},
},
{
"old school splits",
@@ -342,38 +343,38 @@ func TestReasonerConstructAttributeBoolean(t *testing.T) {
"∅",
"",
"",
- []SplitStep{{kasAu, "1"}, {kasCa, "2"}, {kasUs, "3"}},
+ []keySplitStep{{kasAu, "1"}, {kasCa, "2"}, {kasUs, "3"}},
},
{
"simple with all three ops",
[]AttributeValueFQN{clsS, rel2gbr, n2kInt},
[]string{kasUs},
"https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/GBR&https://virtru.com/attr/Need%20to%20Know/value/INT",
- "[DEFAULT]&(http://kas.uk/)&(http://kas.uk/)",
- "(http://kas.uk/)",
- []SplitStep{{kasUk, ""}},
+ "[DEFAULT]&(https://kas.uk/)&(https://kas.uk/)",
+ "(https://kas.uk/)",
+ []keySplitStep{{kasUk, ""}},
},
{
"compartments",
[]AttributeValueFQN{clsS, rel2gbr, rel2usa, n2kHCS, n2kSI},
[]string{kasUs},
"https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
- "[DEFAULT]&(http://kas.uk/⋁http://kas.us/)&(http://hcs.kas.us/⋀http://si.kas.us/)",
- "(http://kas.uk/⋁http://kas.us/)&(http://hcs.kas.us/)&(http://si.kas.us/)",
- []SplitStep{{kasUk, "1"}, {kasUs, "1"}, {kasUsHCS, "2"}, {kasUsSA, "3"}},
+ "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
+ "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
+ []keySplitStep{{kasUk, "1"}, {kasUs, "1"}, {kasUsHCS, "2"}, {kasUsSA, "3"}},
},
{
"compartments - case insensitive",
[]AttributeValueFQN{messUpV(t, clsS), messUpV(t, rel2gbr), messUpV(t, rel2usa), messUpV(t, n2kHCS), messUpV(t, n2kSI)},
[]string{kasUs},
"https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
- "[DEFAULT]&(http://kas.uk/⋁http://kas.us/)&(http://hcs.kas.us/⋀http://si.kas.us/)",
- "(http://kas.uk/⋁http://kas.us/)&(http://hcs.kas.us/)&(http://si.kas.us/)",
- []SplitStep{{kasUk, "1"}, {kasUs, "1"}, {kasUsHCS, "2"}, {kasUsSA, "3"}},
+ "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
+ "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
+ []keySplitStep{{kasUk, "1"}, {kasUs, "1"}, {kasUsHCS, "2"}, {kasUsSA, "3"}},
},
} {
t.Run(tc.n, func(t *testing.T) {
- reasoner, err := NewGranterFromAttributes(valuesToPolicy(tc.policy...)...)
+ reasoner, err := newGranterFromAttributes(valuesToPolicy(tc.policy...)...)
require.NoError(t, err)
actualAB := reasoner.constructAttributeBoolean()
@@ -387,7 +388,7 @@ func TestReasonerConstructAttributeBoolean(t *testing.T) {
assert.Equal(t, tc.reduced, r.String())
i := 0
- plan, err := reasoner.Plan(tc.defaults, func() string {
+ plan, err := reasoner.plan(tc.defaults, func() string {
i++
return fmt.Sprintf("%d", i)
})
diff --git a/sdk/nanotdf_config.go b/sdk/nanotdf_config.go
index 7a4092c0f5..9f3543bdb2 100644
--- a/sdk/nanotdf_config.go
+++ b/sdk/nanotdf_config.go
@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/opentdf/platform/lib/ocrypto"
- "github.com/opentdf/platform/sdk/internal/autoconfigure"
)
// ============================================================================================================
@@ -20,7 +19,7 @@ import (
type NanoTDFConfig struct {
keyPair ocrypto.ECKeyPair
kasPublicKey *ecdh.PublicKey
- attributes []autoconfigure.AttributeValueFQN
+ attributes []AttributeValueFQN
cipher CipherMode
kasURL ResourceLocator
sigCfg signatureConfig
@@ -63,9 +62,9 @@ func (config *NanoTDFConfig) SetKasURL(url string) error {
// SetAttributes - set the attributes to be used for this nanoTDF
func (config *NanoTDFConfig) SetAttributes(attributes []string) error {
- config.attributes = make([]autoconfigure.AttributeValueFQN, len(attributes))
+ config.attributes = make([]AttributeValueFQN, len(attributes))
for i, a := range attributes {
- v, err := autoconfigure.NewAttributeValueFQN(a)
+ v, err := NewAttributeValueFQN(a)
if err != nil {
return err
}
@@ -83,7 +82,7 @@ func (config *NanoTDFConfig) EnableECDSAPolicyBinding() {
func WithNanoDataAttributes(attributes ...string) NanoTDFOption {
return func(c *NanoTDFConfig) error {
for _, a := range attributes {
- v, err := autoconfigure.NewAttributeValueFQN(a)
+ v, err := NewAttributeValueFQN(a)
if err != nil {
return err
}
diff --git a/sdk/tdf.go b/sdk/tdf.go
index df2306b06f..463923afa4 100644
--- a/sdk/tdf.go
+++ b/sdk/tdf.go
@@ -15,7 +15,6 @@ import (
"github.com/opentdf/platform/lib/ocrypto"
"github.com/opentdf/platform/sdk/auth"
"github.com/opentdf/platform/sdk/internal/archive"
- "github.com/opentdf/platform/sdk/internal/autoconfigure"
"google.golang.org/grpc"
)
@@ -132,18 +131,18 @@ func (s SDK) CreateTDFContext(ctx context.Context, writer io.Writer, reader io.R
}
if tdfConfig.autoconfigure {
- var g autoconfigure.Granter
+ var g granter
if len(tdfConfig.attributeValues) > 0 {
- g, err = autoconfigure.NewGranterFromAttributes(tdfConfig.attributeValues...)
+ g, err = newGranterFromAttributes(tdfConfig.attributeValues...)
} else if len(tdfConfig.attributes) > 0 {
- g, err = autoconfigure.NewGranterFromService(ctx, s.Attributes, tdfConfig.attributes...)
+ g, err = newGranterFromService(ctx, s.kasKeyCache, s.Attributes, tdfConfig.attributes...)
}
if err != nil {
return nil, err
}
dk := s.defaultKases(tdfConfig)
- tdfConfig.splitPlan, err = g.Plan(dk, func() string {
+ tdfConfig.splitPlan, err = g.plan(dk, func() string {
return uuid.New().String()
})
if err != nil {
@@ -355,7 +354,7 @@ func (s SDK) prepareManifest(ctx context.Context, t *TDFObject, tdfConfig TDFCon
latestKASInfo := make(map[string]KASInfo)
if len(tdfConfig.splitPlan) == 0 {
// Default split plan: Split keys across all kases
- tdfConfig.splitPlan = make([]autoconfigure.SplitStep, len(tdfConfig.kasInfoList))
+ tdfConfig.splitPlan = make([]keySplitStep, len(tdfConfig.kasInfoList))
for i, kasInfo := range tdfConfig.kasInfoList {
tdfConfig.splitPlan[i].KAS = kasInfo.URL
if len(tdfConfig.kasInfoList) > 1 {
@@ -441,7 +440,7 @@ func (s SDK) prepareManifest(ctx context.Context, t *TDFObject, tdfConfig TDFCon
for _, kasInfo := range conjunction[splitID] {
if len(kasInfo.PublicKey) == 0 {
- return errKasPubKeyMissing
+ return fmt.Errorf("splitID:[%s], kas:[%s]: %w", splitID, kasInfo.URL, errKasPubKeyMissing)
}
// wrap the key with kas public key
@@ -491,7 +490,7 @@ func (s SDK) prepareManifest(ctx context.Context, t *TDFObject, tdfConfig TDFCon
}
// create policy object
-func createPolicyObject(attributes []autoconfigure.AttributeValueFQN) (PolicyObject, error) {
+func createPolicyObject(attributes []AttributeValueFQN) (PolicyObject, error) {
uuidObj, err := uuid.NewUUID()
if err != nil {
return PolicyObject{}, fmt.Errorf("uuid.NewUUID failed: %w", err)
@@ -802,7 +801,7 @@ func (r *Reader) doPayloadKeyUnwrap(ctx context.Context) error { //nolint:gocogn
var payloadKey [kKeySize]byte
knownSplits := make(map[string]bool)
foundSplits := make(map[string]bool)
- skippedSplits := make(map[autoconfigure.SplitStep]error)
+ skippedSplits := make(map[keySplitStep]error)
mixedSplits := len(r.manifest.KeyAccessObjs) > 1 && r.manifest.KeyAccessObjs[0].SplitID != ""
for _, keyAccessObj := range r.manifest.EncryptionInformation.KeyAccessObjs {
@@ -811,7 +810,7 @@ func (r *Reader) doPayloadKeyUnwrap(ctx context.Context) error { //nolint:gocogn
return fmt.Errorf("newKASClient failed:%w", err)
}
- ss := autoconfigure.SplitStep{KAS: keyAccessObj.KasURL, SplitID: keyAccessObj.SplitID}
+ ss := keySplitStep{KAS: keyAccessObj.KasURL, SplitID: keyAccessObj.SplitID}
var wrappedKey []byte
if !mixedSplits {
diff --git a/sdk/tdf_config.go b/sdk/tdf_config.go
index 0829d67a21..cd025d7176 100644
--- a/sdk/tdf_config.go
+++ b/sdk/tdf_config.go
@@ -5,7 +5,6 @@ import (
"github.com/opentdf/platform/lib/ocrypto"
"github.com/opentdf/platform/protocol/go/policy"
- "github.com/opentdf/platform/sdk/internal/autoconfigure"
)
const (
@@ -58,10 +57,10 @@ type TDFConfig struct {
integrityAlgorithm IntegrityAlgorithm
segmentIntegrityAlgorithm IntegrityAlgorithm
assertions []AssertionConfig
- attributes []autoconfigure.AttributeValueFQN
+ attributes []AttributeValueFQN
attributeValues []*policy.Value
kasInfoList []KASInfo
- splitPlan []autoconfigure.SplitStep
+ splitPlan []keySplitStep
}
func newTDFConfig(opt ...TDFOption) (*TDFConfig, error) {
@@ -106,7 +105,7 @@ func WithDataAttributes(attributes ...string) TDFOption {
return func(c *TDFConfig) error {
c.attributeValues = nil
for _, a := range attributes {
- v, err := autoconfigure.NewAttributeValueFQN(a)
+ v, err := NewAttributeValueFQN(a)
if err != nil {
return err
}
@@ -123,11 +122,11 @@ func WithDataAttributes(attributes ...string) TDFOption {
// it to the `CreateTDF` method with this option.
func WithDataAttributeValues(attributes ...*policy.Value) TDFOption {
return func(c *TDFConfig) error {
- c.attributes = make([]autoconfigure.AttributeValueFQN, len(attributes))
+ c.attributes = make([]AttributeValueFQN, len(attributes))
c.attributeValues = make([]*policy.Value, len(attributes))
for i, a := range attributes {
c.attributeValues[i] = a
- afqn, err := autoconfigure.NewAttributeValueFQN(a.GetFqn())
+ afqn, err := NewAttributeValueFQN(a.GetFqn())
if err != nil {
// TODO: update service to validate and encode FQNs properly
return err
@@ -154,9 +153,9 @@ func WithKasInformation(kasInfoList ...KASInfo) TDFOption {
}
}
-func withSplitPlan(p ...autoconfigure.SplitStep) TDFOption {
+func withSplitPlan(p ...keySplitStep) TDFOption {
return func(c *TDFConfig) error {
- c.splitPlan = make([]autoconfigure.SplitStep, len(p))
+ c.splitPlan = make([]keySplitStep, len(p))
copy(c.splitPlan, p)
c.autoconfigure = false
return nil
diff --git a/sdk/tdf_test.go b/sdk/tdf_test.go
index 2aee76969c..fe86ee40ae 100644
--- a/sdk/tdf_test.go
+++ b/sdk/tdf_test.go
@@ -21,10 +21,8 @@ import (
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/opentdf/platform/lib/ocrypto"
kaspb "github.com/opentdf/platform/protocol/go/kas"
- "github.com/opentdf/platform/protocol/go/policy"
attributespb "github.com/opentdf/platform/protocol/go/policy/attributes"
wellknownpb "github.com/opentdf/platform/protocol/go/wellknownconfiguration"
- "github.com/opentdf/platform/sdk/internal/autoconfigure"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -54,8 +52,8 @@ type tdfTest struct {
tdfFileSize float64
checksum string
mimeType string
- splitPlan []autoconfigure.SplitStep
- policy []autoconfigure.AttributeValueFQN
+ splitPlan []keySplitStep
+ policy []AttributeValueFQN
expectedPlanSize int
}
@@ -978,7 +976,7 @@ func (s *TDFSuite) Test_KeySplits() {
fileSize: 5,
tdfFileSize: 2664,
checksum: "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2",
- splitPlan: []autoconfigure.SplitStep{
+ splitPlan: []keySplitStep{
{KAS: "https://a.kas/", SplitID: "a"},
{KAS: "https://b.kas/", SplitID: "a"},
{KAS: `https://c.kas/`, SplitID: "a"},
@@ -989,7 +987,7 @@ func (s *TDFSuite) Test_KeySplits() {
fileSize: 5,
tdfFileSize: 2664,
checksum: "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2",
- splitPlan: []autoconfigure.SplitStep{
+ splitPlan: []keySplitStep{
{KAS: "https://a.kas/", SplitID: "a"},
{KAS: "https://b.kas/", SplitID: "b"},
{KAS: "https://c.kas/", SplitID: "c"},
@@ -1000,7 +998,7 @@ func (s *TDFSuite) Test_KeySplits() {
fileSize: 5,
tdfFileSize: 3211,
checksum: "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2",
- splitPlan: []autoconfigure.SplitStep{
+ splitPlan: []keySplitStep{
{KAS: "https://a.kas/", SplitID: "a"},
{KAS: "https://b.kas/", SplitID: "a"},
{KAS: "https://b.kas/", SplitID: "b"},
@@ -1043,7 +1041,7 @@ func (s *TDFSuite) Test_Autoconfigure() {
fileSize: 5,
tdfFileSize: 1733,
checksum: "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2",
- policy: []autoconfigure.AttributeValueFQN{clsAllowed},
+ policy: []AttributeValueFQN{clsA},
expectedPlanSize: 1,
},
{
@@ -1051,7 +1049,7 @@ func (s *TDFSuite) Test_Autoconfigure() {
fileSize: 5,
tdfFileSize: 2517,
checksum: "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2",
- policy: []autoconfigure.AttributeValueFQN{rel2aus, rel2usa},
+ policy: []AttributeValueFQN{rel2aus, rel2usa},
expectedPlanSize: 2,
},
} {
@@ -1069,6 +1067,7 @@ func (s *TDFSuite) Test_Autoconfigure() {
_ = os.Remove(plaintTextFileName)
_ = os.Remove(tdfFileName)
}()
+ s.sdk.kasKeyCache.store(KASInfo{})
// test encrypt
tdo := s.testEncrypt(s.sdk, kasInfoList, plaintTextFileName, tdfFileName, test)
@@ -1248,7 +1247,7 @@ func (s *TDFSuite) startBackend() {
{"https://c.kas/", mockRSAPrivateKey3, mockRSAPublicKey3},
{kasAu, mockRSAPrivateKey1, mockRSAPublicKey1},
{kasCa, mockRSAPrivateKey2, mockRSAPublicKey2},
- {lasUk, mockRSAPrivateKey2, mockRSAPublicKey2},
+ {kasUk, mockRSAPrivateKey2, mockRSAPublicKey2},
{kasNz, mockRSAPrivateKey3, mockRSAPublicKey3},
{kasUs, mockRSAPrivateKey1, mockRSAPublicKey1},
} {
@@ -1312,117 +1311,6 @@ func (f *FakeWellKnown) GetWellKnownConfiguration(_ context.Context, _ *wellknow
}, nil
}
-const (
- kasAu = "https://kas.au/"
- kasCa = "https://kas.ca/"
- lasUk = "https://kas.uk/"
- kasNz = "https://kas.nz/"
- kasUs = "https://kas.us/"
- kasUsHcs = "https://hcs.kas.us/"
- kasUsSI = "https://si.kas.us/"
- authority = "https://virtru.com/"
-)
-
-var (
- CLS, _ = autoconfigure.NewAttributeNameFQN("https://virtru.com/attr/Classification")
- N2K, _ = autoconfigure.NewAttributeNameFQN("https://virtru.com/attr/Need%20to%20Know")
- REL, _ = autoconfigure.NewAttributeNameFQN("https://virtru.com/attr/Releasable%20To")
-
- clsAllowed, _ = autoconfigure.NewAttributeValueFQN("https://virtru.com/attr/Classification/value/Allowed")
-
- rel2aus, _ = autoconfigure.NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/AUS")
- rel2usa, _ = autoconfigure.NewAttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/USA")
-)
-
-func mockAttributeFor(fqn autoconfigure.AttributeNameFQN) *policy.Attribute {
- ns := policy.Namespace{
- Id: "v",
- Name: "virtru.com",
- Fqn: "https://virtru.com",
- }
- switch fqn {
- case CLS:
- return &policy.Attribute{
- Id: "CLS",
- Namespace: &ns,
- Name: "Classification",
- Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY,
- Fqn: fqn.String(),
- }
- case N2K:
- return &policy.Attribute{
- Id: "N2K",
- Namespace: &ns,
- Name: "Need to Know",
- Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF,
- Fqn: fqn.String(),
- }
- case REL:
- return &policy.Attribute{
- Id: "REL",
- Namespace: &ns,
- Name: "Releasable To",
- Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF,
- Fqn: fqn.String(),
- }
- }
- return nil
-}
-
-func mockValueFor(fqn autoconfigure.AttributeValueFQN) *policy.Value {
- an := fqn.Prefix()
- a := mockAttributeFor(an)
- v := fqn.Value()
- p := policy.Value{
- Id: a.GetId() + ":" + v,
- Attribute: a,
- Value: v,
- Fqn: fqn.String(),
- }
-
- switch an {
- case N2K:
- switch fqn.Value() {
- case "INT":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: lasUk}
- case "HCS":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasUsHcs}
- case "SI":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasUsSI}
- }
-
- case REL:
- switch fqn.Value() {
- case "FVEY":
- p.Grants = make([]*policy.KeyAccessServer, 5)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasAu}
- p.Grants[1] = &policy.KeyAccessServer{Uri: kasCa}
- p.Grants[2] = &policy.KeyAccessServer{Uri: lasUk}
- p.Grants[3] = &policy.KeyAccessServer{Uri: kasNz}
- p.Grants[4] = &policy.KeyAccessServer{Uri: kasUs}
- case "AUS":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasAu}
- case "CAN":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasCa}
- case "GBR":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: lasUk}
- case "NZL":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasNz}
- case "USA":
- p.Grants = make([]*policy.KeyAccessServer, 1)
- p.Grants[0] = &policy.KeyAccessServer{Uri: kasUs}
- }
- }
- return &p
-}
-
type FakeAttributes struct {
attributespb.UnimplementedAttributesServiceServer
}
@@ -1430,7 +1318,7 @@ type FakeAttributes struct {
func (f *FakeAttributes) GetAttributeValuesByFqns(_ context.Context, in *attributespb.GetAttributeValuesByFqnsRequest) (*attributespb.GetAttributeValuesByFqnsResponse, error) {
r := make(map[string]*attributespb.GetAttributeValuesByFqnsResponse_AttributeAndValue)
for _, fqn := range in.GetFqns() {
- av, err := autoconfigure.NewAttributeValueFQN(fqn)
+ av, err := NewAttributeValueFQN(fqn)
if err != nil {
slog.Error("invalid fqn", "notfqn", fqn, "error", err)
return nil, status.New(codes.InvalidArgument, fmt.Sprintf("invalid attribute fqn [%s]", fqn)).Err()
diff --git a/service/integration/kas_registry_test.go b/service/integration/kas_registry_test.go
index 727f413f5c..9f9c73c6d5 100644
--- a/service/integration/kas_registry_test.go
+++ b/service/integration/kas_registry_test.go
@@ -59,7 +59,7 @@ func (s *KasRegistrySuite) Test_ListKeyAccessServers() {
if item.GetPublicKey().GetRemote() != "" {
s.Equal(fixture.PubKey.Remote, item.GetPublicKey().GetRemote())
} else {
- s.Equal(fixture.PubKey.Local, item.GetPublicKey().GetLocal())
+ s.Equal(fixture.PubKey.Cached, item.GetPublicKey().GetCached())
}
s.Equal(fixture.URI, item.GetUri())
}
@@ -83,7 +83,7 @@ func (s *KasRegistrySuite) Test_GetKeyAccessServer() {
s.NotNil(local)
s.Equal(localFixture.ID, local.GetId())
s.Equal(localFixture.URI, local.GetUri())
- s.Equal(localFixture.PubKey.Local, local.GetPublicKey().GetLocal())
+ s.Equal(localFixture.PubKey.Cached, local.GetPublicKey().GetCached())
}
func (s *KasRegistrySuite) Test_GetKeyAccessServer_WithNonExistentId_Fails() {
@@ -231,7 +231,8 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_Everything() {
s.Equal(created.GetId(), got.GetId())
s.Equal(updatedURI, got.GetUri())
s.Equal(updatedPubKeyRemote, got.GetPublicKey().GetRemote())
- s.Zero(got.GetPublicKey().GetLocal())
+ s.Zero(got.GetPublicKey().GetLocal()) //nolint:staticcheck // deprecated but this is a test
+ s.Zero(got.GetPublicKey().GetCached())
s.Equal(fixedLabel, got.GetMetadata().GetLabels()["fixed"])
s.Equal(updatedLabel, got.GetMetadata().GetLabels()["update"])
s.Equal(newLabel, got.GetMetadata().GetLabels()["new"])
@@ -275,7 +276,7 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_Metadata_DoesNotAlterOther
s.Equal(created.GetId(), got.GetId())
s.Equal(uri, got.GetUri())
s.Equal(pubKeyRemote, got.GetPublicKey().GetRemote())
- s.Zero(got.GetPublicKey().GetLocal())
+ s.Zero(got.GetPublicKey().GetCached())
s.Equal("new label", got.GetMetadata().GetLabels()["new"])
}
@@ -310,7 +311,8 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_Uri_DoesNotAlterOtherValue
s.Equal(created.GetId(), got.GetId())
s.Equal(updatedURI, got.GetUri())
s.Equal(pubKeyRemote, got.GetPublicKey().GetRemote())
- s.Zero(got.GetPublicKey().GetLocal())
+ s.Zero(got.GetPublicKey().GetLocal()) //nolint:staticcheck // deprecated but this is a test
+ s.Zero(got.GetPublicKey().GetCached())
s.Nil(got.GetMetadata().GetLabels())
}
@@ -318,7 +320,20 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_Uri_DoesNotAlterOtherValue
func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_PublicKey_DoesNotAlterOtherValues() {
uri := "before_pubkey_only.com"
pubKeyRemote := "https://remote.com/key"
- updatedPubKeyLocal := "my_key"
+ updatedKeySet := &policy.KasPublicKeySet{
+ Keys: []*policy.KasPublicKey{
+ {
+ Pem: "some-pem-data",
+ Alg: policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048,
+ Kid: "r1",
+ },
+ },
+ }
+ updatedPubKey := &policy.PublicKey{
+ PublicKey: &policy.PublicKey_Cached{
+ Cached: updatedKeySet,
+ },
+ }
// create a test KAS
created, err := s.db.PolicyClient.CreateKeyAccessServer(s.ctx, &kasregistry.CreateKeyAccessServerRequest{
@@ -339,11 +354,7 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_PublicKey_DoesNotAlterOthe
// update it with new key
updated, err := s.db.PolicyClient.UpdateKeyAccessServer(s.ctx, created.GetId(), &kasregistry.UpdateKeyAccessServerRequest{
- PublicKey: &policy.PublicKey{
- PublicKey: &policy.PublicKey_Local{
- Local: updatedPubKeyLocal,
- },
- },
+ PublicKey: updatedPubKey,
})
s.Require().NoError(err)
s.NotNil(updated)
@@ -354,7 +365,7 @@ func (s *KasRegistrySuite) Test_UpdateKeyAccessServer_PublicKey_DoesNotAlterOthe
s.NotNil(got)
s.Equal(created.GetId(), got.GetId())
s.Equal(uri, got.GetUri())
- s.Equal(updatedPubKeyLocal, got.GetPublicKey().GetLocal())
+ s.Equal(updatedKeySet, got.GetPublicKey().GetCached())
s.Zero(got.GetPublicKey().GetRemote())
s.Equal("unchanged label", got.GetMetadata().GetLabels()["unchanged"])
}
diff --git a/service/internal/fixtures/fixtures.go b/service/internal/fixtures/fixtures.go
index 240090f4c7..d4eb049a5f 100644
--- a/service/internal/fixtures/fixtures.go
+++ b/service/internal/fixtures/fixtures.go
@@ -6,6 +6,7 @@ import (
"log/slog"
"os"
+ policypb "github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/service/policy"
"gopkg.in/yaml.v2"
)
@@ -93,8 +94,8 @@ type FixtureDataKasRegistry struct {
ID string `yaml:"id"`
URI string `yaml:"uri"`
PubKey struct {
- Remote string `yaml:"remote" json:"remote,omitempty"`
- Local string `yaml:"local" json:"local,omitempty"`
+ Remote string `yaml:"remote" json:"remote,omitempty"`
+ Cached *policypb.KasPublicKeySet `yaml:"cached" json:"cached,omitempty"`
} `yaml:"public_key" json:"public_key"`
}
diff --git a/service/internal/fixtures/policy_fixtures.yaml b/service/internal/fixtures/policy_fixtures.yaml
index f540131670..538baa6786 100644
--- a/service/internal/fixtures/policy_fixtures.yaml
+++ b/service/internal/fixtures/policy_fixtures.yaml
@@ -424,4 +424,8 @@ kas_registry:
id: e36640a6-61c5-4d4c-a45b-0e0a26d1c45f
uri: https://local.kas.com:3000
public_key:
- local: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ6ekNDQVhXZ0F3SUJBZ0lVT1J1VjNhdlU5QUU2enNCNlp4eWxsSHBpNWQ0d0NnWUlLb1pJemowRUF3SXcKUFRFTE1Ba0dBMVVFQmhNQ2RYTXhDekFKQmdOVkJBZ01BbU4wTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NalF3TVRBeU1UWTFOalUyV2hjTk1qVXdNVEF4TVRZMU5qVTJXakE5Ck1Rc3dDUVlEVlFRR0V3SjFjekVMTUFrR0ExVUVDQXdDWTNReElUQWZCZ05WQkFvTUdFbHVkR1Z5Ym1WMElGZHAKWkdkcGRITWdVSFI1SUV4MFpEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJMVjlmQ0pIRC9rYwpyWHJVSFF3QVp4ME1jMGRQdkxqc0ovb2pFdE1NbjBST2RlT3g4eWd4Z2NRVEZGQXh5Q3RCdWFkaEFkbS9pVkh0CjhnMkVNejVkTzNXalV6QlJNQjBHQTFVZERnUVdCQlFZTmt1aytKSXVSV3luK2JFOHNCaFJ3MjdPVlRBZkJnTlYKSFNNRUdEQVdnQlFZTmt1aytKSXVSV3luK2JFOHNCaFJ3MjdPVlRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvRwpDQ3FHU000OUJBTUNBMGdBTUVVQ0lRQ0FCMmppWWU4QVk2TUo0QURQU1FHRTQ3K2Eza1dGTGNHc0pob1pieHRnClV3SWdjZklJdVBmaDRmYmN2OGNUaTJCbEkzazdzV1B1QW1JRlZyaUkyZDNVeDVRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+ cached:
+ keys:
+ - pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ6ekNDQVhXZ0F3SUJBZ0lVT1J1VjNhdlU5QUU2enNCNlp4eWxsSHBpNWQ0d0NnWUlLb1pJemowRUF3SXcKUFRFTE1Ba0dBMVVFQmhNQ2RYTXhDekFKQmdOVkJBZ01BbU4wTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NalF3TVRBeU1UWTFOalUyV2hjTk1qVXdNVEF4TVRZMU5qVTJXakE5Ck1Rc3dDUVlEVlFRR0V3SjFjekVMTUFrR0ExVUVDQXdDWTNReElUQWZCZ05WQkFvTUdFbHVkR1Z5Ym1WMElGZHAKWkdkcGRITWdVSFI1SUV4MFpEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJMVjlmQ0pIRC9rYwpyWHJVSFF3QVp4ME1jMGRQdkxqc0ovb2pFdE1NbjBST2RlT3g4eWd4Z2NRVEZGQXh5Q3RCdWFkaEFkbS9pVkh0CjhnMkVNejVkTzNXalV6QlJNQjBHQTFVZERnUVdCQlFZTmt1aytKSXVSV3luK2JFOHNCaFJ3MjdPVlRBZkJnTlYKSFNNRUdEQVdnQlFZTmt1aytKSXVSV3luK2JFOHNCaFJ3MjdPVlRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvRwpDQ3FHU000OUJBTUNBMGdBTUVVQ0lRQ0FCMmppWWU4QVk2TUo0QURQU1FHRTQ3K2Eza1dGTGNHc0pob1pieHRnClV3SWdjZklJdVBmaDRmYmN2OGNUaTJCbEkzazdzV1B1QW1JRlZyaUkyZDNVeDVRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+ kid: r1
+ alg: 1
diff --git a/service/policy/objects.proto b/service/policy/objects.proto
index 10da55d418..675b041e88 100644
--- a/service/policy/objects.proto
+++ b/service/policy/objects.proto
@@ -305,8 +305,10 @@ message PublicKey {
expression: "this.matches('^https://[a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?(\\\\.[a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?)*(/.*)?$')"
}];
- // public key - optional since can also be retrieved via url
- string local = 2;
+ // public key; PEM of RSA public key; prefer `cached`
+ string local = 2 [
+ deprecated = true
+ ];
// public key with additional information. Current preferred version
KasPublicKeySet cached = 3;
diff --git a/test/policy-service.bats b/test/policy-service.bats
index f038c1e3d7..f08c042f1f 100755
--- a/test/policy-service.bats
+++ b/test/policy-service.bats
@@ -16,7 +16,7 @@
[[ $output = *"listing namespaces"* ]]
[ $status = 0 ]
- run go run ./examples --creds opentdf:secret attributes add -a https://example.io/attr/IntellectualProperty -v "TradeSecret Proprietary BusinessSensitive Open" --rule hierarchy
+ run go run ./examples --creds opentdf:secret attributes add -a https://example.io/attr/IntellectualProperty -v "TradeSecret,Proprietary,BusinessSensitive,Open" --rule hierarchy
echo "$output"
[[ $output = *"created attribute"* ]]
[ $status = 0 ]
@@ -43,6 +43,11 @@
[[ $output = *"registered kas"* ]]
[ $status = 0 ]
+ run go run ./examples --creds opentdf:secret kas add -k https://example.io --public-key MY_PUBLIC_KEY --kid my-public-key --algorithm rsa:2048
+ echo "$output"
+ [[ $output = *"registered kas"* ]]
+ [ $status = 0 ]
+
run go run ./examples --creds opentdf:secret kas ls
echo "$output"
[[ $output = *"https://example.io"* ]]
@@ -66,7 +71,7 @@
[[ $output = *"https://c.example.io"* ]]
[ $status = 0 ]
- go run ./examples --creds opentdf:secret attributes add -a https://grant.example.io/attr/test -v "a b c"
+ go run ./examples --creds opentdf:secret attributes add -a https://grant.example.io/attr/test -v "a,b,c"
go run ./examples --creds opentdf:secret attributes assign -a https://grant.example.io/attr/test -v a -k https://a.example.io
go run ./examples --creds opentdf:secret attributes assign -a https://grant.example.io/attr/test -v b -k https://b.example.io
diff --git a/test/tdf-roundtrips.bats b/test/tdf-roundtrips.bats
index 75bcea3bbc..b1605ea91e 100755
--- a/test/tdf-roundtrips.bats
+++ b/test/tdf-roundtrips.bats
@@ -27,6 +27,35 @@
printf '%s\n' "$output" | grep "Hello Zero Trust"
}
+@test "examples: roundtrip Z-TDF with extra unnecessary, invalid kas" {
+ # TODO: add subject mapping here to remove reliance on `provision fixtures`
+ echo "[INFO] configure attribute with grant for local kas"
+ go run ./examples --creds opentdf:secret kas add --kas http://localhost:8080 --public-key "$(<${BATS_TEST_DIRNAME}/../kas-cert.pem)"
+ go run ./examples --creds opentdf:secret kas add --kas http://localhost:9090 --algorithm "rsa:2048" --kid r2 --public-key "$(<${BATS_TEST_DIRNAME}/../kas-cert.pem)"
+ go run ./examples --creds opentdf:secret attributes unassign -a https://example.com/attr/attr1 -v value1
+ go run ./examples --creds opentdf:secret attributes unassign -a https://example.com/attr/attr1
+ go run ./examples --creds opentdf:secret attributes assign -a https://example.com/attr/attr1 -v value1 -k "http://localhost:8080,http://localhost:9090"
+
+ echo "[INFO] create a tdf3 format file"
+ run go run ./examples encrypt "Hello multikao split"
+ echo "[INFO] echoing output; if successful, this is just the manifest"
+ echo "$output"
+
+ echo "[INFO] Validate the manifest lists the expected kid in its KAO"
+ u1=$(jq -r '.encryptionInformation.keyAccess[0].url' <<<"${output}")
+ u2=$(jq -r '.encryptionInformation.keyAccess[1].url' <<<"${output}")
+ sid1=$(jq -r '.encryptionInformation.keyAccess[0].sid' <<<"${output}")
+ sid2=$(jq -r '.encryptionInformation.keyAccess[1].sid' <<<"${output}")
+ echo "${u1},${sid1} ?= ${u2},${sid2}"
+ [ $u1 != $u2 ]
+ [ $sid1 = $sid2 ]
+
+ echo "[INFO] decrypting..."
+ run go run ./examples decrypt sensitive.txt.tdf
+ echo "$output"
+ printf '%s\n' "$output" | grep "Hello multikao split"
+}
+
@test "examples: roundtrip nanoTDF" {
echo "[INFO] creating nanotdf file"
go run ./examples encrypt -o sensitive.txt.ntdf --nano "Hello NanoTDF"