diff --git a/docs/grpc/index.html b/docs/grpc/index.html
index 30670c641..dea63f4b0 100644
--- a/docs/grpc/index.html
+++ b/docs/grpc/index.html
@@ -438,10 +438,30 @@
Table of Contents
MInfoResponse
+
+ MKeyAccess
+
+
+
+ MKeyAccessRewrapResult
+
+
+
+ MKeyAccessRewrapResult.MetadataEntry
+
+
MLegacyPublicKeyRequest
+
+ MPolicyBinding
+
+
+
+ MPolicyRewrapResult
+
+
MPublicKeyRequest
@@ -462,6 +482,22 @@ Table of Contents
MRewrapResponse.MetadataEntry
+
+ MUnsignedRewrapRequest
+
+
+
+ MUnsignedRewrapRequest.WithKeyAccessObject
+
+
+
+ MUnsignedRewrapRequest.WithPolicy
+
+
+
+ MUnsignedRewrapRequest.WithPolicyRequest
+
+
@@ -3203,6 +3239,169 @@ InfoResponse
+ KeyAccess
+
+
+
+
+
+ Field | Type | Label | Description |
+
+
+
+
+ encrypted_metadata |
+ string |
+ |
+ |
+
+
+
+ policy_binding |
+ PolicyBinding |
+ |
+ |
+
+
+
+ protocol |
+ string |
+ |
+ |
+
+
+
+ key_type |
+ string |
+ |
+ |
+
+
+
+ kas_url |
+ string |
+ |
+ |
+
+
+
+ kid |
+ string |
+ |
+ |
+
+
+
+ split_id |
+ string |
+ |
+ |
+
+
+
+ wrapped_key |
+ bytes |
+ |
+ |
+
+
+
+ header |
+ bytes |
+ |
+ header is only used for NanoTDFs |
+
+
+
+
+
+
+
+
+
+ KeyAccessRewrapResult
+
+
+
+
+
+
+
+
+
+ KeyAccessRewrapResult.MetadataEntry
+
+
+
+
+
+
+
+
+
LegacyPublicKeyRequest
@@ -3227,6 +3426,68 @@ LegacyPublicKeyRequest
+ PolicyBinding
+
+
+
+
+
+ Field | Type | Label | Description |
+
+
+
+
+ algorithm |
+ string |
+ |
+ |
+
+
+
+ hash |
+ string |
+ |
+ |
+
+
+
+
+
+
+
+
+
+ PolicyRewrapResult
+
+
+
+
+
+
+
+
+
PublicKeyRequest
@@ -3334,14 +3595,14 @@ RewrapResponse
metadata |
RewrapResponse.MetadataEntry |
repeated |
- |
+ Deprecated. |
entity_wrapped_key |
bytes |
|
- |
+ Deprecated. |
@@ -3355,13 +3616,51 @@ RewrapResponse
schema_version |
string |
|
- |
+ Deprecated. |
+
+
+
+ responses |
+ PolicyRewrapResult |
+ repeated |
+ New Rewrap API changes |
+
+
+ Fields with deprecated option
+
+
+
+ Name |
+ Option |
+
+
+
+
+
+ metadata |
+ true |
+
+
+
+ entity_wrapped_key |
+ true |
+
+
+
+ schema_version |
+ true |
+
+
+
+
+
+
@@ -3396,6 +3695,137 @@ RewrapResponse.MetadataEntry
+ UnsignedRewrapRequest
+
+
+
+
+
+
+
+
+
+ UnsignedRewrapRequest.WithKeyAccessObject
+
+
+
+
+
+ Field | Type | Label | Description |
+
+
+
+
+ key_access_object_id |
+ string |
+ |
+ |
+
+
+
+ key_access_object |
+ KeyAccess |
+ |
+ |
+
+
+
+
+
+
+
+
+
+ UnsignedRewrapRequest.WithPolicy
+
+
+
+
+
+ Field | Type | Label | Description |
+
+
+
+
+ id |
+ string |
+ |
+ |
+
+
+
+ body |
+ string |
+ |
+ |
+
+
+
+
+
+
+
+
+
+ UnsignedRewrapRequest.WithPolicyRequest
+
+
+
+
+
+
+
+
+
diff --git a/docs/openapi/kas/kas.swagger.json b/docs/openapi/kas/kas.swagger.json
index 485207629..d422537e3 100644
--- a/docs/openapi/kas/kas.swagger.json
+++ b/docs/openapi/kas/kas.swagger.json
@@ -130,6 +130,43 @@
}
},
"definitions": {
+ "kasKeyAccessRewrapResult": {
+ "type": "object",
+ "properties": {
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {}
+ },
+ "keyAccessObjectId": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "kasWrappedKey": {
+ "type": "string",
+ "format": "byte"
+ },
+ "error": {
+ "type": "string"
+ }
+ }
+ },
+ "kasPolicyRewrapResult": {
+ "type": "object",
+ "properties": {
+ "policyId": {
+ "type": "string"
+ },
+ "results": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "$ref": "#/definitions/kasKeyAccessRewrapResult"
+ }
+ }
+ }
+ },
"kasPublicKeyResponse": {
"type": "object",
"properties": {
@@ -165,6 +202,14 @@
},
"schemaVersion": {
"type": "string"
+ },
+ "responses": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "$ref": "#/definitions/kasPolicyRewrapResult"
+ },
+ "title": "New Rewrap API changes"
}
}
},
diff --git a/examples/cmd/benchmark.go b/examples/cmd/benchmark.go
index 3909cb1ff..b61dff2ee 100644
--- a/examples/cmd/benchmark.go
+++ b/examples/cmd/benchmark.go
@@ -204,7 +204,10 @@ func runBenchmark(cmd *cobra.Command, args []string) error {
}
totalTime := time.Since(startTime)
- averageLatency := totalDuration / time.Duration(successCount)
+ var averageLatency time.Duration
+ if successCount > 0 {
+ averageLatency = totalDuration / time.Duration(successCount)
+ }
throughput := float64(successCount) / totalTime.Seconds()
// Print results
@@ -214,7 +217,9 @@ func runBenchmark(cmd *cobra.Command, args []string) error {
cmd.Printf("Failed Requests: %d\n", errorCount)
cmd.Printf("Concurrent Requests: %d\n", config.ConcurrentRequests)
cmd.Printf("Total Time: %s\n", totalTime)
- cmd.Printf("Average Latency: %s\n", averageLatency)
+ if successCount > 0 {
+ cmd.Printf("Average Latency: %s\n", averageLatency)
+ }
cmd.Printf("Throughput: %.2f requests/second\n", throughput)
if errorCount > 0 {
diff --git a/examples/cmd/benchmark_bulk.go b/examples/cmd/benchmark_bulk.go
new file mode 100644
index 000000000..c989142c7
--- /dev/null
+++ b/examples/cmd/benchmark_bulk.go
@@ -0,0 +1,169 @@
+package cmd
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/opentdf/platform/sdk"
+ "github.com/spf13/cobra"
+)
+
+func init() {
+ benchmarkCmd := &cobra.Command{
+ Use: "benchmark-bulk",
+ Short: "OpenTDF benchmark tool",
+ Long: `A OpenTDF benchmark tool to measure Bulk Rewrap.`,
+ RunE: runBenchmarkBulk,
+ }
+
+ benchmarkCmd.Flags().IntVar(&config.RequestCount, "count", 100, "Total number of requests")
+ benchmarkCmd.Flags().Var(&config.TDFFormat, "tdf", "TDF format (tdf3 or nanotdf)")
+ ExamplesCmd.AddCommand(benchmarkCmd)
+}
+
+func runBenchmarkBulk(cmd *cobra.Command, args []string) error {
+ in := strings.NewReader("Hello, World!")
+
+ // Create new offline client
+ client, err := newSDK()
+ if err != nil {
+ return err
+ }
+
+ out := os.Stdout
+ if outputName != "-" {
+ out, err = os.Create("sensitive.txt.tdf")
+ if err != nil {
+ return err
+ }
+ }
+ defer func() {
+ if outputName != "-" {
+ out.Close()
+ }
+ }()
+
+ dataAttributes := []string{"https://example.com/attr/attr1/value/value1"}
+ if config.TDFFormat == NanoTDF {
+ nanoTDFConfig, err := client.NewNanoTDFConfig()
+ if err != nil {
+ return err
+ }
+ nanoTDFConfig.SetAttributes(dataAttributes)
+ nanoTDFConfig.EnableECDSAPolicyBinding()
+ err = nanoTDFConfig.SetKasURL(fmt.Sprintf("http://%s/kas", "localhost:8080"))
+ if err != nil {
+ return err
+ }
+
+ _, err = client.CreateNanoTDF(out, in, *nanoTDFConfig)
+ if err != nil {
+ return err
+ }
+
+ if outputName != "-" {
+ err = cat(cmd, outputName)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ tdf, err :=
+ client.CreateTDF(
+ out, in,
+ sdk.WithDataAttributes(dataAttributes...),
+ sdk.WithKasInformation(
+ sdk.KASInfo{
+ URL: fmt.Sprintf("http://%s", "localhost:8080"),
+ PublicKey: "",
+ }),
+ sdk.WithAutoconfigure(false))
+ if err != nil {
+ return err
+ }
+
+ manifestJSON, err := json.MarshalIndent(tdf.Manifest(), "", " ")
+ if err != nil {
+ return err
+ }
+ cmd.Println(string(manifestJSON))
+ }
+
+ var errors []error
+ var requestFailure error
+
+ // Function to perform the operation
+ operation := func() {
+ file, err := os.Open("sensitive.txt.tdf")
+ if err != nil {
+ requestFailure = fmt.Errorf("file open error: %v", err)
+ return
+ }
+ defer file.Close()
+ cipher, _ := io.ReadAll(file)
+
+ file.Seek(0, 0)
+ format := sdk.Nano
+ var bulkTdfs []*sdk.BulkTDF
+ if config.TDFFormat == "tdf3" {
+ format = sdk.Standard
+ }
+ for i := 0; i < config.RequestCount; i++ {
+ bulkTdfs = append(bulkTdfs, &sdk.BulkTDF{Reader: bytes.NewReader(cipher), Writer: io.Discard})
+ }
+ err = client.BulkDecrypt(context.Background(), sdk.WithTDFs(bulkTdfs...), sdk.WithTDFType(format))
+ if err != nil {
+ if errList, ok := sdk.FromBulkErrors(err); ok {
+ errors = errList
+ } else {
+ requestFailure = err
+ }
+ }
+
+ }
+
+ // Start the benchmark
+ startTime := time.Now()
+ operation()
+ totalTime := time.Since(startTime)
+
+ // Count errors and collect error messages
+ errorCount := 0
+ successCount := 0
+ if requestFailure != nil {
+ errorCount = config.RequestCount
+ errors = append(errors, requestFailure)
+ } else {
+ errorCount = len(errors)
+ successCount = config.RequestCount - errorCount
+ }
+ throughput := float64(successCount) / totalTime.Seconds()
+
+ errorMsgs := make(map[string]int)
+ for _, err := range errors {
+ errorMsgs[err.Error()] += 1
+ }
+
+ // Print results
+ cmd.Printf("\nBenchmark Results:\n")
+ cmd.Printf("Total Decrypts: %d\n", config.RequestCount)
+ cmd.Printf("Successful Decrypts: %d\n", successCount)
+ cmd.Printf("Failed Decrypts: %d\n", errorCount)
+ cmd.Printf("Total Time: %s\n", totalTime)
+ cmd.Printf("Throughput: %.2f requests/second\n", throughput)
+
+ if errorCount > 0 {
+ cmd.Printf("\nError Summary:\n")
+ for errMsg, count := range errorMsgs {
+ cmd.Printf("%s: %d occurrences\n", errMsg, count)
+ }
+ }
+
+ return nil
+}
diff --git a/protocol/go/kas/kas.pb.go b/protocol/go/kas/kas.pb.go
index eee98539a..7451da9c9 100644
--- a/protocol/go/kas/kas.pb.go
+++ b/protocol/go/kas/kas.pb.go
@@ -157,6 +157,228 @@ func (x *LegacyPublicKeyRequest) GetAlgorithm() string {
return ""
}
+type PolicyBinding struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Algorithm string `protobuf:"bytes,1,opt,name=algorithm,json=alg,proto3" json:"algorithm,omitempty"`
+ Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
+}
+
+func (x *PolicyBinding) Reset() {
+ *x = PolicyBinding{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PolicyBinding) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PolicyBinding) ProtoMessage() {}
+
+func (x *PolicyBinding) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PolicyBinding.ProtoReflect.Descriptor instead.
+func (*PolicyBinding) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *PolicyBinding) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *PolicyBinding) GetHash() string {
+ if x != nil {
+ return x.Hash
+ }
+ return ""
+}
+
+type KeyAccess struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ EncryptedMetadata string `protobuf:"bytes,1,opt,name=encrypted_metadata,json=encryptedMetadata,proto3" json:"encrypted_metadata,omitempty"`
+ PolicyBinding *PolicyBinding `protobuf:"bytes,2,opt,name=policy_binding,json=policyBinding,proto3" json:"policy_binding,omitempty"`
+ Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
+ KeyType string `protobuf:"bytes,4,opt,name=key_type,json=type,proto3" json:"key_type,omitempty"`
+ KasUrl string `protobuf:"bytes,5,opt,name=kas_url,json=url,proto3" json:"kas_url,omitempty"`
+ Kid string `protobuf:"bytes,6,opt,name=kid,proto3" json:"kid,omitempty"`
+ SplitId string `protobuf:"bytes,7,opt,name=split_id,json=sid,proto3" json:"split_id,omitempty"`
+ WrappedKey []byte `protobuf:"bytes,8,opt,name=wrapped_key,json=wrappedKey,proto3" json:"wrapped_key,omitempty"`
+ // header is only used for NanoTDFs
+ Header []byte `protobuf:"bytes,9,opt,name=header,proto3" json:"header,omitempty"`
+}
+
+func (x *KeyAccess) Reset() {
+ *x = KeyAccess{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *KeyAccess) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KeyAccess) ProtoMessage() {}
+
+func (x *KeyAccess) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KeyAccess.ProtoReflect.Descriptor instead.
+func (*KeyAccess) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *KeyAccess) GetEncryptedMetadata() string {
+ if x != nil {
+ return x.EncryptedMetadata
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetPolicyBinding() *PolicyBinding {
+ if x != nil {
+ return x.PolicyBinding
+ }
+ return nil
+}
+
+func (x *KeyAccess) GetProtocol() string {
+ if x != nil {
+ return x.Protocol
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetKeyType() string {
+ if x != nil {
+ return x.KeyType
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetKasUrl() string {
+ if x != nil {
+ return x.KasUrl
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetKid() string {
+ if x != nil {
+ return x.Kid
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetSplitId() string {
+ if x != nil {
+ return x.SplitId
+ }
+ return ""
+}
+
+func (x *KeyAccess) GetWrappedKey() []byte {
+ if x != nil {
+ return x.WrappedKey
+ }
+ return nil
+}
+
+func (x *KeyAccess) GetHeader() []byte {
+ if x != nil {
+ return x.Header
+ }
+ return nil
+}
+
+type UnsignedRewrapRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ClientPublicKey string `protobuf:"bytes,1,opt,name=client_public_key,json=clientPublicKey,proto3" json:"client_public_key,omitempty"`
+ Requests []*UnsignedRewrapRequest_WithPolicyRequest `protobuf:"bytes,2,rep,name=requests,proto3" json:"requests,omitempty"`
+}
+
+func (x *UnsignedRewrapRequest) Reset() {
+ *x = UnsignedRewrapRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsignedRewrapRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsignedRewrapRequest) ProtoMessage() {}
+
+func (x *UnsignedRewrapRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsignedRewrapRequest.ProtoReflect.Descriptor instead.
+func (*UnsignedRewrapRequest) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *UnsignedRewrapRequest) GetClientPublicKey() string {
+ if x != nil {
+ return x.ClientPublicKey
+ }
+ return ""
+}
+
+func (x *UnsignedRewrapRequest) GetRequests() []*UnsignedRewrapRequest_WithPolicyRequest {
+ if x != nil {
+ return x.Requests
+ }
+ return nil
+}
+
type PublicKeyRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -170,7 +392,7 @@ type PublicKeyRequest struct {
func (x *PublicKeyRequest) Reset() {
*x = PublicKeyRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_kas_kas_proto_msgTypes[3]
+ mi := &file_kas_kas_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -183,7 +405,7 @@ func (x *PublicKeyRequest) String() string {
func (*PublicKeyRequest) ProtoMessage() {}
func (x *PublicKeyRequest) ProtoReflect() protoreflect.Message {
- mi := &file_kas_kas_proto_msgTypes[3]
+ mi := &file_kas_kas_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -196,7 +418,7 @@ func (x *PublicKeyRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use PublicKeyRequest.ProtoReflect.Descriptor instead.
func (*PublicKeyRequest) Descriptor() ([]byte, []int) {
- return file_kas_kas_proto_rawDescGZIP(), []int{3}
+ return file_kas_kas_proto_rawDescGZIP(), []int{6}
}
func (x *PublicKeyRequest) GetAlgorithm() string {
@@ -232,7 +454,7 @@ type PublicKeyResponse struct {
func (x *PublicKeyResponse) Reset() {
*x = PublicKeyResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_kas_kas_proto_msgTypes[4]
+ mi := &file_kas_kas_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -245,7 +467,7 @@ func (x *PublicKeyResponse) String() string {
func (*PublicKeyResponse) ProtoMessage() {}
func (x *PublicKeyResponse) ProtoReflect() protoreflect.Message {
- mi := &file_kas_kas_proto_msgTypes[4]
+ mi := &file_kas_kas_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -258,7 +480,7 @@ func (x *PublicKeyResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use PublicKeyResponse.ProtoReflect.Descriptor instead.
func (*PublicKeyResponse) Descriptor() ([]byte, []int) {
- return file_kas_kas_proto_rawDescGZIP(), []int{4}
+ return file_kas_kas_proto_rawDescGZIP(), []int{7}
}
func (x *PublicKeyResponse) GetPublicKey() string {
@@ -286,7 +508,7 @@ type RewrapRequest struct {
func (x *RewrapRequest) Reset() {
*x = RewrapRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_kas_kas_proto_msgTypes[5]
+ mi := &file_kas_kas_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -299,7 +521,7 @@ func (x *RewrapRequest) String() string {
func (*RewrapRequest) ProtoMessage() {}
func (x *RewrapRequest) ProtoReflect() protoreflect.Message {
- mi := &file_kas_kas_proto_msgTypes[5]
+ mi := &file_kas_kas_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -312,7 +534,7 @@ func (x *RewrapRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use RewrapRequest.ProtoReflect.Descriptor instead.
func (*RewrapRequest) Descriptor() ([]byte, []int) {
- return file_kas_kas_proto_rawDescGZIP(), []int{5}
+ return file_kas_kas_proto_rawDescGZIP(), []int{8}
}
func (x *RewrapRequest) GetSignedRequestToken() string {
@@ -322,21 +544,186 @@ func (x *RewrapRequest) GetSignedRequestToken() string {
return ""
}
+type KeyAccessRewrapResult struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Metadata map[string]*structpb.Value `protobuf:"bytes,1,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ KeyAccessObjectId string `protobuf:"bytes,2,opt,name=key_access_object_id,json=keyAccessObjectId,proto3" json:"key_access_object_id,omitempty"`
+ Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
+ // Types that are assignable to Result:
+ //
+ // *KeyAccessRewrapResult_KasWrappedKey
+ // *KeyAccessRewrapResult_Error
+ Result isKeyAccessRewrapResult_Result `protobuf_oneof:"result"`
+}
+
+func (x *KeyAccessRewrapResult) Reset() {
+ *x = KeyAccessRewrapResult{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *KeyAccessRewrapResult) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KeyAccessRewrapResult) ProtoMessage() {}
+
+func (x *KeyAccessRewrapResult) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KeyAccessRewrapResult.ProtoReflect.Descriptor instead.
+func (*KeyAccessRewrapResult) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *KeyAccessRewrapResult) GetMetadata() map[string]*structpb.Value {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *KeyAccessRewrapResult) GetKeyAccessObjectId() string {
+ if x != nil {
+ return x.KeyAccessObjectId
+ }
+ return ""
+}
+
+func (x *KeyAccessRewrapResult) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (m *KeyAccessRewrapResult) GetResult() isKeyAccessRewrapResult_Result {
+ if m != nil {
+ return m.Result
+ }
+ return nil
+}
+
+func (x *KeyAccessRewrapResult) GetKasWrappedKey() []byte {
+ if x, ok := x.GetResult().(*KeyAccessRewrapResult_KasWrappedKey); ok {
+ return x.KasWrappedKey
+ }
+ return nil
+}
+
+func (x *KeyAccessRewrapResult) GetError() string {
+ if x, ok := x.GetResult().(*KeyAccessRewrapResult_Error); ok {
+ return x.Error
+ }
+ return ""
+}
+
+type isKeyAccessRewrapResult_Result interface {
+ isKeyAccessRewrapResult_Result()
+}
+
+type KeyAccessRewrapResult_KasWrappedKey struct {
+ KasWrappedKey []byte `protobuf:"bytes,4,opt,name=kas_wrapped_key,json=kasWrappedKey,proto3,oneof"`
+}
+
+type KeyAccessRewrapResult_Error struct {
+ Error string `protobuf:"bytes,5,opt,name=error,proto3,oneof"`
+}
+
+func (*KeyAccessRewrapResult_KasWrappedKey) isKeyAccessRewrapResult_Result() {}
+
+func (*KeyAccessRewrapResult_Error) isKeyAccessRewrapResult_Result() {}
+
+type PolicyRewrapResult struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ PolicyId string `protobuf:"bytes,1,opt,name=policy_id,json=policyId,proto3" json:"policy_id,omitempty"`
+ Results []*KeyAccessRewrapResult `protobuf:"bytes,2,rep,name=results,proto3" json:"results,omitempty"`
+}
+
+func (x *PolicyRewrapResult) Reset() {
+ *x = PolicyRewrapResult{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PolicyRewrapResult) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PolicyRewrapResult) ProtoMessage() {}
+
+func (x *PolicyRewrapResult) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PolicyRewrapResult.ProtoReflect.Descriptor instead.
+func (*PolicyRewrapResult) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *PolicyRewrapResult) GetPolicyId() string {
+ if x != nil {
+ return x.PolicyId
+ }
+ return ""
+}
+
+func (x *PolicyRewrapResult) GetResults() []*KeyAccessRewrapResult {
+ if x != nil {
+ return x.Results
+ }
+ return nil
+}
+
type RewrapResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Metadata map[string]*structpb.Value `protobuf:"bytes,1,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
- EntityWrappedKey []byte `protobuf:"bytes,2,opt,name=entity_wrapped_key,json=entityWrappedKey,proto3" json:"entity_wrapped_key,omitempty"`
- SessionPublicKey string `protobuf:"bytes,3,opt,name=session_public_key,json=sessionPublicKey,proto3" json:"session_public_key,omitempty"`
- SchemaVersion string `protobuf:"bytes,4,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
+ // Deprecated: Marked as deprecated in kas/kas.proto.
+ Metadata map[string]*structpb.Value `protobuf:"bytes,1,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // Deprecated: Marked as deprecated in kas/kas.proto.
+ EntityWrappedKey []byte `protobuf:"bytes,2,opt,name=entity_wrapped_key,json=entityWrappedKey,proto3" json:"entity_wrapped_key,omitempty"`
+ SessionPublicKey string `protobuf:"bytes,3,opt,name=session_public_key,json=sessionPublicKey,proto3" json:"session_public_key,omitempty"`
+ // Deprecated: Marked as deprecated in kas/kas.proto.
+ SchemaVersion string `protobuf:"bytes,4,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
+ // New Rewrap API changes
+ Responses []*PolicyRewrapResult `protobuf:"bytes,5,rep,name=responses,proto3" json:"responses,omitempty"`
}
func (x *RewrapResponse) Reset() {
*x = RewrapResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_kas_kas_proto_msgTypes[6]
+ mi := &file_kas_kas_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -349,7 +736,7 @@ func (x *RewrapResponse) String() string {
func (*RewrapResponse) ProtoMessage() {}
func (x *RewrapResponse) ProtoReflect() protoreflect.Message {
- mi := &file_kas_kas_proto_msgTypes[6]
+ mi := &file_kas_kas_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -362,9 +749,10 @@ func (x *RewrapResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use RewrapResponse.ProtoReflect.Descriptor instead.
func (*RewrapResponse) Descriptor() ([]byte, []int) {
- return file_kas_kas_proto_rawDescGZIP(), []int{6}
+ return file_kas_kas_proto_rawDescGZIP(), []int{11}
}
+// Deprecated: Marked as deprecated in kas/kas.proto.
func (x *RewrapResponse) GetMetadata() map[string]*structpb.Value {
if x != nil {
return x.Metadata
@@ -372,6 +760,7 @@ func (x *RewrapResponse) GetMetadata() map[string]*structpb.Value {
return nil
}
+// Deprecated: Marked as deprecated in kas/kas.proto.
func (x *RewrapResponse) GetEntityWrappedKey() []byte {
if x != nil {
return x.EntityWrappedKey
@@ -386,6 +775,7 @@ func (x *RewrapResponse) GetSessionPublicKey() string {
return ""
}
+// Deprecated: Marked as deprecated in kas/kas.proto.
func (x *RewrapResponse) GetSchemaVersion() string {
if x != nil {
return x.SchemaVersion
@@ -393,6 +783,186 @@ func (x *RewrapResponse) GetSchemaVersion() string {
return ""
}
+func (x *RewrapResponse) GetResponses() []*PolicyRewrapResult {
+ if x != nil {
+ return x.Responses
+ }
+ return nil
+}
+
+type UnsignedRewrapRequest_WithPolicy struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
+}
+
+func (x *UnsignedRewrapRequest_WithPolicy) Reset() {
+ *x = UnsignedRewrapRequest_WithPolicy{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsignedRewrapRequest_WithPolicy) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsignedRewrapRequest_WithPolicy) ProtoMessage() {}
+
+func (x *UnsignedRewrapRequest_WithPolicy) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsignedRewrapRequest_WithPolicy.ProtoReflect.Descriptor instead.
+func (*UnsignedRewrapRequest_WithPolicy) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{5, 0}
+}
+
+func (x *UnsignedRewrapRequest_WithPolicy) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *UnsignedRewrapRequest_WithPolicy) GetBody() string {
+ if x != nil {
+ return x.Body
+ }
+ return ""
+}
+
+type UnsignedRewrapRequest_WithKeyAccessObject struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ KeyAccessObjectId string `protobuf:"bytes,1,opt,name=key_access_object_id,json=keyAccessObjectId,proto3" json:"key_access_object_id,omitempty"`
+ KeyAccessObject *KeyAccess `protobuf:"bytes,2,opt,name=key_access_object,json=keyAccessObject,proto3" json:"key_access_object,omitempty"`
+}
+
+func (x *UnsignedRewrapRequest_WithKeyAccessObject) Reset() {
+ *x = UnsignedRewrapRequest_WithKeyAccessObject{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsignedRewrapRequest_WithKeyAccessObject) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsignedRewrapRequest_WithKeyAccessObject) ProtoMessage() {}
+
+func (x *UnsignedRewrapRequest_WithKeyAccessObject) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsignedRewrapRequest_WithKeyAccessObject.ProtoReflect.Descriptor instead.
+func (*UnsignedRewrapRequest_WithKeyAccessObject) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{5, 1}
+}
+
+func (x *UnsignedRewrapRequest_WithKeyAccessObject) GetKeyAccessObjectId() string {
+ if x != nil {
+ return x.KeyAccessObjectId
+ }
+ return ""
+}
+
+func (x *UnsignedRewrapRequest_WithKeyAccessObject) GetKeyAccessObject() *KeyAccess {
+ if x != nil {
+ return x.KeyAccessObject
+ }
+ return nil
+}
+
+type UnsignedRewrapRequest_WithPolicyRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ KeyAccessObjects []*UnsignedRewrapRequest_WithKeyAccessObject `protobuf:"bytes,1,rep,name=key_access_objects,json=keyAccessObjects,proto3" json:"key_access_objects,omitempty"`
+ Policy *UnsignedRewrapRequest_WithPolicy `protobuf:"bytes,2,opt,name=policy,proto3" json:"policy,omitempty"`
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) Reset() {
+ *x = UnsignedRewrapRequest_WithPolicyRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_kas_kas_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsignedRewrapRequest_WithPolicyRequest) ProtoMessage() {}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_kas_kas_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsignedRewrapRequest_WithPolicyRequest.ProtoReflect.Descriptor instead.
+func (*UnsignedRewrapRequest_WithPolicyRequest) Descriptor() ([]byte, []int) {
+ return file_kas_kas_proto_rawDescGZIP(), []int{5, 2}
+}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) GetKeyAccessObjects() []*UnsignedRewrapRequest_WithKeyAccessObject {
+ if x != nil {
+ return x.KeyAccessObjects
+ }
+ return nil
+}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) GetPolicy() *UnsignedRewrapRequest_WithPolicy {
+ if x != nil {
+ return x.Policy
+ }
+ return nil
+}
+
+func (x *UnsignedRewrapRequest_WithPolicyRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
var File_kas_kas_proto protoreflect.FileDescriptor
var file_kas_kas_proto_rawDesc = []byte{
@@ -413,82 +983,169 @@ var file_kas_kas_proto_rawDesc = []byte{
0x61, 0x63, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68,
- 0x6d, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69,
- 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0x92, 0x41, 0x30, 0x32, 0x2e,
- 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x72,
- 0x73, 0x61, 0x3a, 0x3c, 0x6b, 0x65, 0x79, 0x73, 0x69, 0x7a, 0x65, 0x3e, 0x20, 0x6f, 0x72, 0x20,
- 0x65, 0x63, 0x3a, 0x3c, 0x63, 0x75, 0x72, 0x76, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x52, 0x09,
- 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x26, 0x0a, 0x03, 0x66, 0x6d, 0x74,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0x92, 0x41, 0x11, 0x32, 0x0f, 0x72, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x03, 0x66, 0x6d,
- 0x74, 0x12, 0x22, 0x0a, 0x01, 0x76, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0x92, 0x41,
- 0x11, 0x32, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
- 0x6f, 0x6e, 0x52, 0x01, 0x76, 0x22, 0x44, 0x0a, 0x11, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
- 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75,
- 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
- 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x69, 0x64,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x0d, 0x52,
- 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14,
- 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74,
- 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e,
- 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4a, 0x04,
- 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x22, 0xa7, 0x02, 0x0a,
- 0x0e, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
- 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x21, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2c,
+ 0x6d, 0x22, 0x3b, 0x0a, 0x0d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x69, 0x6e, 0x64, 0x69,
+ 0x6e, 0x67, 0x12, 0x16, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x6c, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61,
+ 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xa1,
+ 0x02, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x12,
+ 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x0d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42,
+ 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+ 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+ 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x07, 0x6b, 0x61,
+ 0x73, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c,
+ 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+ 0x69, 0x64, 0x12, 0x15, 0x0a, 0x08, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x72, 0x61,
+ 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
+ 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65,
+ 0x61, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64,
+ 0x65, 0x72, 0x22, 0x95, 0x04, 0x0a, 0x15, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52,
+ 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11,
+ 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6b, 0x61, 0x73,
+ 0x2e, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x73, 0x1a, 0x30, 0x0a, 0x0a, 0x57, 0x69, 0x74, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
+ 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x62, 0x6f, 0x64, 0x79, 0x1a, 0x82, 0x01, 0x0a, 0x13, 0x57, 0x69, 0x74, 0x68, 0x4b, 0x65, 0x79,
+ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2f, 0x0a, 0x14,
+ 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63,
+ 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6b, 0x65, 0x79, 0x41,
+ 0x63, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x3a, 0x0a,
+ 0x11, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6f, 0x62, 0x6a, 0x65,
+ 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x4b,
+ 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x0f, 0x6b, 0x65, 0x79, 0x41, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0xce, 0x01, 0x0a, 0x11, 0x57, 0x69,
+ 0x74, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x5c, 0x0a, 0x12, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6f, 0x62,
+ 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6b, 0x61,
+ 0x73, 0x2e, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x41,
+ 0x63, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x10, 0x6b, 0x65, 0x79,
+ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x3d, 0x0a,
+ 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e,
+ 0x6b, 0x61, 0x73, 0x2e, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x77, 0x72,
+ 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x50, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09,
+ 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x50,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x51, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x33, 0x92, 0x41, 0x30, 0x32, 0x2e, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x68, 0x6d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x72, 0x73, 0x61, 0x3a, 0x3c, 0x6b, 0x65, 0x79,
+ 0x73, 0x69, 0x7a, 0x65, 0x3e, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x63, 0x3a, 0x3c, 0x63, 0x75, 0x72,
+ 0x76, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x68, 0x6d, 0x12, 0x26, 0x0a, 0x03, 0x66, 0x6d, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x14, 0x92, 0x41, 0x11, 0x32, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x66,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x03, 0x66, 0x6d, 0x74, 0x12, 0x22, 0x0a, 0x01, 0x76, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0x92, 0x41, 0x11, 0x32, 0x0f, 0x72, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x01, 0x76, 0x22, 0x44,
+ 0x0a, 0x11, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
+ 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x0d, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f,
+ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x62,
+ 0x65, 0x61, 0x72, 0x65, 0x72, 0x22, 0xc7, 0x02, 0x0a, 0x15, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
+ 0x44, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x28, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x14, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x11, 0x6b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x62,
+ 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28,
+ 0x0a, 0x0f, 0x6b, 0x61, 0x73, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65,
+ 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6b, 0x61, 0x73, 0x57, 0x72,
+ 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f,
+ 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
+ 0x1a, 0x53, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
+ 0x67, 0x0a, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52,
+ 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f,
+ 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x49, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x02, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
+ 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xea, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x77,
+ 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e,
+ 0x6b, 0x61, 0x73, 0x2e, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30,
0x0a, 0x12, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64,
- 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x65, 0x6e, 0x74, 0x69,
- 0x74, 0x79, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12,
- 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
- 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
- 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x63,
- 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
- 0x6e, 0x1a, 0x53, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
- 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xce, 0x02, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73,
- 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c,
- 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c,
- 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6b,
- 0x61, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30,
- 0x12, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x76,
- 0x32, 0x2f, 0x6b, 0x61, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79,
- 0x90, 0x02, 0x01, 0x12, 0x78, 0x0a, 0x0f, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x50, 0x75, 0x62,
- 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x4c, 0x65, 0x67,
- 0x61, 0x63, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75,
- 0x65, 0x22, 0x2a, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x00, 0x82,
- 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x6b, 0x61, 0x73, 0x5f,
- 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x90, 0x02, 0x01, 0x12, 0x58, 0x0a,
- 0x06, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x12, 0x12, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x52, 0x65,
- 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6b, 0x61,
- 0x73, 0x2e, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x22, 0x25, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x00, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x76, 0x32,
- 0x2f, 0x72, 0x65, 0x77, 0x72, 0x61, 0x70, 0x42, 0xe2, 0x01, 0x92, 0x41, 0x73, 0x12, 0x71, 0x0a,
- 0x1a, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x44, 0x46, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x41, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2a, 0x4c, 0x0a, 0x12, 0x42,
- 0x53, 0x44, 0x20, 0x33, 0x2d, 0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x43, 0x6c, 0x65, 0x61,
- 0x72, 0x12, 0x36, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75,
- 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x62, 0x61,
- 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65,
- 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x35, 0x2e, 0x30,
- 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x6b, 0x61, 0x73, 0x42, 0x08, 0x4b, 0x61, 0x73, 0x50, 0x72,
- 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
- 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f,
- 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x6b,
- 0x61, 0x73, 0xa2, 0x02, 0x03, 0x4b, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x4b, 0x61, 0x73, 0xca, 0x02,
- 0x03, 0x4b, 0x61, 0x73, 0xe2, 0x02, 0x0f, 0x4b, 0x61, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
- 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x4b, 0x61, 0x73, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
+ 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x10,
+ 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79,
+ 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x6c,
+ 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65,
+ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x29,
+ 0x0a, 0x0e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65,
+ 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6b,
+ 0x61, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52,
+ 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+ 0x1a, 0x53, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xce, 0x02, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69,
+ 0x63, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69,
+ 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6b, 0x61,
+ 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12,
+ 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x76, 0x32,
+ 0x2f, 0x6b, 0x61, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x90,
+ 0x02, 0x01, 0x12, 0x78, 0x0a, 0x0f, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x50, 0x75, 0x62, 0x6c,
+ 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x4c, 0x65, 0x67, 0x61,
+ 0x63, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
+ 0x22, 0x2a, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x00, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x6b, 0x61, 0x73, 0x5f, 0x70,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x90, 0x02, 0x01, 0x12, 0x58, 0x0a, 0x06,
+ 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x12, 0x12, 0x2e, 0x6b, 0x61, 0x73, 0x2e, 0x52, 0x65, 0x77,
+ 0x72, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6b, 0x61, 0x73,
+ 0x2e, 0x52, 0x65, 0x77, 0x72, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x25, 0x92, 0x41, 0x09, 0x4a, 0x07, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x00, 0x82, 0xd3, 0xe4,
+ 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x6b, 0x61, 0x73, 0x2f, 0x76, 0x32, 0x2f,
+ 0x72, 0x65, 0x77, 0x72, 0x61, 0x70, 0x42, 0xe2, 0x01, 0x92, 0x41, 0x73, 0x12, 0x71, 0x0a, 0x1a,
+ 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x44, 0x46, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x41, 0x63, 0x63, 0x65,
+ 0x73, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2a, 0x4c, 0x0a, 0x12, 0x42, 0x53,
+ 0x44, 0x20, 0x33, 0x2d, 0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x43, 0x6c, 0x65, 0x61, 0x72,
+ 0x12, 0x36, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x62, 0x61, 0x63,
+ 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72,
+ 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x0a,
+ 0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x6b, 0x61, 0x73, 0x42, 0x08, 0x4b, 0x61, 0x73, 0x50, 0x72, 0x6f,
+ 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
+ 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x6b, 0x61,
+ 0x73, 0xa2, 0x02, 0x03, 0x4b, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x4b, 0x61, 0x73, 0xca, 0x02, 0x03,
+ 0x4b, 0x61, 0x73, 0xe2, 0x02, 0x0f, 0x4b, 0x61, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x4b, 0x61, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
@@ -503,33 +1160,51 @@ func file_kas_kas_proto_rawDescGZIP() []byte {
return file_kas_kas_proto_rawDescData
}
-var file_kas_kas_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
+var file_kas_kas_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
var file_kas_kas_proto_goTypes = []interface{}{
- (*InfoRequest)(nil), // 0: kas.InfoRequest
- (*InfoResponse)(nil), // 1: kas.InfoResponse
- (*LegacyPublicKeyRequest)(nil), // 2: kas.LegacyPublicKeyRequest
- (*PublicKeyRequest)(nil), // 3: kas.PublicKeyRequest
- (*PublicKeyResponse)(nil), // 4: kas.PublicKeyResponse
- (*RewrapRequest)(nil), // 5: kas.RewrapRequest
- (*RewrapResponse)(nil), // 6: kas.RewrapResponse
- nil, // 7: kas.RewrapResponse.MetadataEntry
- (*structpb.Value)(nil), // 8: google.protobuf.Value
- (*wrapperspb.StringValue)(nil), // 9: google.protobuf.StringValue
+ (*InfoRequest)(nil), // 0: kas.InfoRequest
+ (*InfoResponse)(nil), // 1: kas.InfoResponse
+ (*LegacyPublicKeyRequest)(nil), // 2: kas.LegacyPublicKeyRequest
+ (*PolicyBinding)(nil), // 3: kas.PolicyBinding
+ (*KeyAccess)(nil), // 4: kas.KeyAccess
+ (*UnsignedRewrapRequest)(nil), // 5: kas.UnsignedRewrapRequest
+ (*PublicKeyRequest)(nil), // 6: kas.PublicKeyRequest
+ (*PublicKeyResponse)(nil), // 7: kas.PublicKeyResponse
+ (*RewrapRequest)(nil), // 8: kas.RewrapRequest
+ (*KeyAccessRewrapResult)(nil), // 9: kas.KeyAccessRewrapResult
+ (*PolicyRewrapResult)(nil), // 10: kas.PolicyRewrapResult
+ (*RewrapResponse)(nil), // 11: kas.RewrapResponse
+ (*UnsignedRewrapRequest_WithPolicy)(nil), // 12: kas.UnsignedRewrapRequest.WithPolicy
+ (*UnsignedRewrapRequest_WithKeyAccessObject)(nil), // 13: kas.UnsignedRewrapRequest.WithKeyAccessObject
+ (*UnsignedRewrapRequest_WithPolicyRequest)(nil), // 14: kas.UnsignedRewrapRequest.WithPolicyRequest
+ nil, // 15: kas.KeyAccessRewrapResult.MetadataEntry
+ nil, // 16: kas.RewrapResponse.MetadataEntry
+ (*structpb.Value)(nil), // 17: google.protobuf.Value
+ (*wrapperspb.StringValue)(nil), // 18: google.protobuf.StringValue
}
var file_kas_kas_proto_depIdxs = []int32{
- 7, // 0: kas.RewrapResponse.metadata:type_name -> kas.RewrapResponse.MetadataEntry
- 8, // 1: kas.RewrapResponse.MetadataEntry.value:type_name -> google.protobuf.Value
- 3, // 2: kas.AccessService.PublicKey:input_type -> kas.PublicKeyRequest
- 2, // 3: kas.AccessService.LegacyPublicKey:input_type -> kas.LegacyPublicKeyRequest
- 5, // 4: kas.AccessService.Rewrap:input_type -> kas.RewrapRequest
- 4, // 5: kas.AccessService.PublicKey:output_type -> kas.PublicKeyResponse
- 9, // 6: kas.AccessService.LegacyPublicKey:output_type -> google.protobuf.StringValue
- 6, // 7: kas.AccessService.Rewrap:output_type -> kas.RewrapResponse
- 5, // [5:8] is the sub-list for method output_type
- 2, // [2:5] is the sub-list for method input_type
- 2, // [2:2] is the sub-list for extension type_name
- 2, // [2:2] is the sub-list for extension extendee
- 0, // [0:2] is the sub-list for field type_name
+ 3, // 0: kas.KeyAccess.policy_binding:type_name -> kas.PolicyBinding
+ 14, // 1: kas.UnsignedRewrapRequest.requests:type_name -> kas.UnsignedRewrapRequest.WithPolicyRequest
+ 15, // 2: kas.KeyAccessRewrapResult.metadata:type_name -> kas.KeyAccessRewrapResult.MetadataEntry
+ 9, // 3: kas.PolicyRewrapResult.results:type_name -> kas.KeyAccessRewrapResult
+ 16, // 4: kas.RewrapResponse.metadata:type_name -> kas.RewrapResponse.MetadataEntry
+ 10, // 5: kas.RewrapResponse.responses:type_name -> kas.PolicyRewrapResult
+ 4, // 6: kas.UnsignedRewrapRequest.WithKeyAccessObject.key_access_object:type_name -> kas.KeyAccess
+ 13, // 7: kas.UnsignedRewrapRequest.WithPolicyRequest.key_access_objects:type_name -> kas.UnsignedRewrapRequest.WithKeyAccessObject
+ 12, // 8: kas.UnsignedRewrapRequest.WithPolicyRequest.policy:type_name -> kas.UnsignedRewrapRequest.WithPolicy
+ 17, // 9: kas.KeyAccessRewrapResult.MetadataEntry.value:type_name -> google.protobuf.Value
+ 17, // 10: kas.RewrapResponse.MetadataEntry.value:type_name -> google.protobuf.Value
+ 6, // 11: kas.AccessService.PublicKey:input_type -> kas.PublicKeyRequest
+ 2, // 12: kas.AccessService.LegacyPublicKey:input_type -> kas.LegacyPublicKeyRequest
+ 8, // 13: kas.AccessService.Rewrap:input_type -> kas.RewrapRequest
+ 7, // 14: kas.AccessService.PublicKey:output_type -> kas.PublicKeyResponse
+ 18, // 15: kas.AccessService.LegacyPublicKey:output_type -> google.protobuf.StringValue
+ 11, // 16: kas.AccessService.Rewrap:output_type -> kas.RewrapResponse
+ 14, // [14:17] is the sub-list for method output_type
+ 11, // [11:14] is the sub-list for method input_type
+ 11, // [11:11] is the sub-list for extension type_name
+ 11, // [11:11] is the sub-list for extension extendee
+ 0, // [0:11] is the sub-list for field type_name
}
func init() { file_kas_kas_proto_init() }
@@ -575,7 +1250,7 @@ func file_kas_kas_proto_init() {
}
}
file_kas_kas_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PublicKeyRequest); i {
+ switch v := v.(*PolicyBinding); i {
case 0:
return &v.state
case 1:
@@ -587,7 +1262,7 @@ func file_kas_kas_proto_init() {
}
}
file_kas_kas_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PublicKeyResponse); i {
+ switch v := v.(*KeyAccess); i {
case 0:
return &v.state
case 1:
@@ -599,7 +1274,7 @@ func file_kas_kas_proto_init() {
}
}
file_kas_kas_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*RewrapRequest); i {
+ switch v := v.(*UnsignedRewrapRequest); i {
case 0:
return &v.state
case 1:
@@ -611,6 +1286,66 @@ func file_kas_kas_proto_init() {
}
}
file_kas_kas_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PublicKeyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PublicKeyResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RewrapRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*KeyAccessRewrapResult); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PolicyRewrapResult); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RewrapResponse); i {
case 0:
return &v.state
@@ -622,6 +1357,46 @@ func file_kas_kas_proto_init() {
return nil
}
}
+ file_kas_kas_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnsignedRewrapRequest_WithPolicy); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnsignedRewrapRequest_WithKeyAccessObject); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_kas_kas_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnsignedRewrapRequest_WithPolicyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_kas_kas_proto_msgTypes[9].OneofWrappers = []interface{}{
+ (*KeyAccessRewrapResult_KasWrappedKey)(nil),
+ (*KeyAccessRewrapResult_Error)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -629,7 +1404,7 @@ func file_kas_kas_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_kas_kas_proto_rawDesc,
NumEnums: 0,
- NumMessages: 8,
+ NumMessages: 17,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/sdk/bulk.go b/sdk/bulk.go
new file mode 100644
index 000000000..f878ec27f
--- /dev/null
+++ b/sdk/bulk.go
@@ -0,0 +1,154 @@
+package sdk
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/opentdf/platform/protocol/go/kas"
+)
+
+// BulkTDF: Reader is TDF Content. Writer writes encrypted data. Error is the error that occurs if decrypting fails.
+type BulkTDF struct {
+ Reader io.ReadSeeker
+ Writer io.Writer
+ Error error
+}
+
+type BulkDecryptRequest struct {
+ TDFs []*BulkTDF
+ TDFType TdfType
+}
+
+// BulkErrors List of Errors that Failed during Bulk Decryption
+type BulkErrors []error
+
+func (b BulkErrors) Unwrap() []error {
+ return b
+}
+
+func (b BulkErrors) Error() string {
+ return fmt.Sprintf("Some TDFs could not be Decrypted: %s", errors.Join(b...).Error())
+}
+
+// FromBulkErrors Returns List of Decrypt Failures and true if is decryption failures
+func FromBulkErrors(err error) ([]error, bool) {
+ var list BulkErrors
+ ok := errors.As(err, &list)
+ return list, ok
+}
+
+type BulkDecryptOption func(request *BulkDecryptRequest)
+
+// WithTDFs Adds Lists of TDFs to be decrypted
+func WithTDFs(tdfs ...*BulkTDF) BulkDecryptOption {
+ return func(request *BulkDecryptRequest) {
+ request.appendTDFs(tdfs...)
+ }
+}
+
+// WithTDFType Type of TDFs to be decrypted
+func WithTDFType(tdfType TdfType) BulkDecryptOption {
+ return func(request *BulkDecryptRequest) {
+ request.TDFType = tdfType
+ }
+}
+
+func createBulkRewrapRequest(options ...BulkDecryptOption) *BulkDecryptRequest {
+ req := &BulkDecryptRequest{}
+ for _, opt := range options {
+ opt(req)
+ }
+ return req
+}
+
+func (s SDK) createDecryptor(tdf *BulkTDF, tdfType TdfType) (decryptor, error) {
+ switch tdfType {
+ case Nano:
+ decryptor := createNanoTDFDecryptHandler(tdf.Reader, tdf.Writer)
+ return decryptor, nil
+ case Standard:
+ return s.createTDF3DecryptHandler(tdf.Writer, tdf.Reader)
+ case Invalid:
+ }
+ return nil, fmt.Errorf("unknown tdf type: %s", tdfType)
+}
+
+// BulkDecrypt Decrypts a list of BulkTDF and if a partial failure of TDFs unable to be decrypted, BulkErrors would be returned.
+func (s SDK) BulkDecrypt(ctx context.Context, opts ...BulkDecryptOption) error {
+ bulkReq := createBulkRewrapRequest(opts...)
+ kasRewrapRequests := make(map[string][]*kas.UnsignedRewrapRequest_WithPolicyRequest)
+ tdfDecryptors := make(map[string]decryptor)
+ policyTDF := make(map[string]*BulkTDF)
+
+ for i, tdf := range bulkReq.TDFs {
+ policyID := fmt.Sprintf("policy-%d", i)
+ decryptor, err := s.createDecryptor(tdf, bulkReq.TDFType)
+ if err != nil {
+ tdf.Error = err
+ continue
+ }
+
+ req, err := decryptor.CreateRewrapRequest(ctx)
+ if err != nil {
+ tdf.Error = err
+ continue
+ }
+ tdfDecryptors[policyID] = decryptor
+ policyTDF[policyID] = tdf
+ for kasURL, r := range req {
+ r.Policy.Id = policyID
+ kasRewrapRequests[kasURL] = append(kasRewrapRequests[kasURL], r)
+ }
+ }
+
+ kasClient := newKASClient(s.dialOptions, s.tokenSource, s.kasSessionKey)
+ allRewrapResp := make(map[string][]kaoResult)
+ var err error
+ for _, rewrapRequests := range kasRewrapRequests {
+ var rewrapResp map[string][]kaoResult
+ switch bulkReq.TDFType {
+ case Nano:
+ rewrapResp, err = kasClient.nanoUnwrap(ctx, rewrapRequests...)
+ case Standard, Invalid:
+ rewrapResp, err = kasClient.unwrap(ctx, rewrapRequests...)
+ }
+
+ for id, res := range rewrapResp {
+ allRewrapResp[id] = append(allRewrapResp[id], res...)
+ }
+ }
+ if err != nil {
+ return fmt.Errorf("bulk rewrap failed: %w", err)
+ }
+
+ var errList []error
+ for id, tdf := range policyTDF {
+ kaoRes, ok := allRewrapResp[id]
+ if !ok {
+ tdf.Error = fmt.Errorf("rewrap did not create a response for this TDF")
+ errList = append(errList, tdf.Error)
+ continue
+ }
+ decryptor := tdfDecryptors[id]
+ if _, err = decryptor.Decrypt(ctx, kaoRes); err != nil {
+ tdf.Error = err
+ errList = append(errList, tdf.Error)
+ continue
+ }
+ }
+
+ if len(errList) != 0 {
+ return BulkErrors(errList)
+ }
+
+ return nil
+}
+
+func (b *BulkDecryptRequest) appendTDFs(tdfs ...*BulkTDF) {
+ b.TDFs = append(
+ b.TDFs,
+ tdfs...,
+ )
+}
diff --git a/sdk/kas_client.go b/sdk/kas_client.go
index 5d1fe065f..e74e125d0 100644
--- a/sdk/kas_client.go
+++ b/sdk/kas_client.go
@@ -2,12 +2,14 @@ package sdk
import (
"context"
- "encoding/json"
+ "errors"
"fmt"
"net"
"net/url"
"time"
+ "google.golang.org/protobuf/encoding/protojson"
+
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/opentdf/platform/lib/ocrypto"
@@ -20,25 +22,21 @@ const (
secondsPerMinute = 60
)
-type RequestBody struct {
- KeyAccess `json:"keyAccess"`
- ClientPublicKey string `json:"clientPublicKey"`
- Policy string `json:"policy"`
-}
-
type KASClient struct {
accessTokenSource auth.AccessTokenSource
dialOptions []grpc.DialOption
sessionKey *ocrypto.RsaKeyPair
}
-// once the backend moves over we should use the same type that the golang backend uses here
-type rewrapRequestBody struct {
- KeyAccess KeyAccess `json:"keyAccess"`
- Policy string `json:"policy,omitempty"`
- Algorithm string `json:"algorithm,omitempty"`
- ClientPublicKey string `json:"clientPublicKey"`
- SchemaVersion string `json:"schemaVersion,omitempty"`
+type kaoResult struct {
+ SymmetricKey []byte
+ Error error
+ KeyAccessObjectID string
+}
+
+type decryptor interface {
+ CreateRewrapRequest(ctx context.Context) (map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest, error)
+ Decrypt(ctx context.Context, results []kaoResult) (uint32, error)
}
func newKASClient(dialOptions []grpc.DialOption, accessTokenSource auth.AccessTokenSource, sessionKey *ocrypto.RsaKeyPair) *KASClient {
@@ -50,12 +48,12 @@ func newKASClient(dialOptions []grpc.DialOption, accessTokenSource auth.AccessTo
}
// there is no connection caching as of now
-func (k *KASClient) makeRewrapRequest(ctx context.Context, keyAccess KeyAccess, policy string) (*kas.RewrapResponse, error) {
- rewrapRequest, err := k.getRewrapRequest(keyAccess, policy)
+func (k *KASClient) makeRewrapRequest(ctx context.Context, requests []*kas.UnsignedRewrapRequest_WithPolicyRequest, pubKey string) (*kas.RewrapResponse, error) {
+ rewrapRequest, err := k.getRewrapRequest(requests, pubKey)
if err != nil {
return nil, err
}
- grpcAddress, err := getGRPCAddress(keyAccess.KasURL)
+ grpcAddress, err := getGRPCAddress(requests[0].GetKeyAccessObjects()[0].GetKeyAccessObject().GetKasUrl())
if err != nil {
return nil, err
}
@@ -76,148 +74,106 @@ func (k *KASClient) makeRewrapRequest(ctx context.Context, keyAccess KeyAccess,
return response, nil
}
-func (k *KASClient) unwrap(ctx context.Context, keyAccess KeyAccess, policy string) ([]byte, error) {
- response, err := k.makeRewrapRequest(ctx, keyAccess, policy)
- if err != nil {
- return nil, fmt.Errorf("error making rewrap request to kas: %w", err)
- }
-
- if k.sessionKey == nil {
- return nil, fmt.Errorf("session key is nil")
- }
- clientPrivateKey, err := k.sessionKey.PrivateKeyInPemFormat()
- if err != nil {
- return nil, fmt.Errorf("ocrypto.PrivateKeyInPemFormat failed: %w", err)
- }
-
- asymDecryption, err := ocrypto.NewAsymDecryption(clientPrivateKey)
+func (k *KASClient) nanoUnwrap(ctx context.Context, requests ...*kas.UnsignedRewrapRequest_WithPolicyRequest) (map[string][]kaoResult, error) {
+ keypair, err := ocrypto.NewECKeyPair(ocrypto.ECCModeSecp256r1)
if err != nil {
- return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err)
+ return nil, fmt.Errorf("ocrypto.NewECKeyPair failed :%w", err)
}
- key, err := asymDecryption.Decrypt(response.GetEntityWrappedKey())
+ publicKeyAsPem, err := keypair.PublicKeyInPemFormat()
if err != nil {
- return nil, fmt.Errorf("error decrypting payload from KAS: %w", err)
- }
-
- return key, nil
-}
-
-func (k *KASClient) getNanoTDFRewrapRequest(header string, kasURL string, pubKey string) (*kas.RewrapRequest, error) {
- kAccess := keyAccess{
- Header: header,
- KeyAccessType: "remote",
- URL: kasURL,
- Protocol: "kas",
- }
-
- requestBody := requestBody{
- Algorithm: "ec:secp256r1",
- KeyAccess: kAccess,
- ClientPublicKey: pubKey,
+ return nil, fmt.Errorf("ocrypto.NewECKeyPair.PublicKeyInPemFormat failed :%w", err)
}
- requestBodyJSON, err := json.Marshal(requestBody)
+ privateKeyAsPem, err := keypair.PrivateKeyInPemFormat()
if err != nil {
- return nil, fmt.Errorf("Error marshaling request body: %w", err)
+ return nil, fmt.Errorf("ocrypto.NewECKeyPair.PrivateKeyInPemFormat failed :%w", err)
}
-
- now := time.Now()
- tok, err := jwt.NewBuilder().
- Claim("requestBody", string(requestBodyJSON)).
- IssuedAt(now).
- Expiration(now.Add(secondsPerMinute * time.Second)).
- Build()
+ response, err := k.makeRewrapRequest(ctx, requests, publicKeyAsPem)
if err != nil {
- return nil, fmt.Errorf("failed to create jwt: %w", err)
+ return nil, err
}
- signedToken, err := k.accessTokenSource.MakeToken(func(key jwk.Key) ([]byte, error) {
- signed, err := jwt.Sign(tok, jwt.WithKey(key.Algorithm(), key))
- if err != nil {
- return nil, fmt.Errorf("error signing DPoP token: %w", err)
- }
-
- return signed, nil
- })
+ sessionKey, err := ocrypto.ComputeECDHKey([]byte(privateKeyAsPem), []byte(response.GetSessionPublicKey()))
if err != nil {
- return nil, fmt.Errorf("failed to sign the token: %w", err)
+ return nil, fmt.Errorf("ocrypto.ComputeECDHKey failed :%w", err)
}
- rewrapRequest := kas.RewrapRequest{
- SignedRequestToken: string(signedToken),
- }
- return &rewrapRequest, nil
-}
-
-func (k *KASClient) makeNanoTDFRewrapRequest(ctx context.Context, header string, kasURL string, pubKey string) (*kas.RewrapResponse, error) {
- rewrapRequest, err := k.getNanoTDFRewrapRequest(header, kasURL, pubKey)
- if err != nil {
- return nil, err
- }
- grpcAddress, err := getGRPCAddress(kasURL)
+ sessionKey, err = ocrypto.CalculateHKDF(versionSalt(), sessionKey)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("ocrypto.CalculateHKDF failed:%w", err)
}
- conn, err := grpc.NewClient(grpcAddress, k.dialOptions...)
+ aesGcm, err := ocrypto.NewAESGcm(sessionKey)
if err != nil {
- return nil, fmt.Errorf("error connecting to kas: %w", err)
+ return nil, fmt.Errorf("ocrypto.NewAESGcm failed:%w", err)
}
- defer conn.Close()
-
- serviceClient := kas.NewAccessServiceClient(conn)
- response, err := serviceClient.Rewrap(ctx, rewrapRequest)
- if err != nil {
- return nil, fmt.Errorf("error making rewrap request: %w", err)
+ policyResults := make(map[string][]kaoResult)
+ for _, results := range response.GetResponses() {
+ var kaoKeys []kaoResult
+ for _, kao := range results.GetResults() {
+ if kao.GetStatus() == "permit" {
+ wrappedKey := kao.GetKasWrappedKey()
+ key, err := aesGcm.Decrypt(wrappedKey)
+ if err != nil {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), Error: err})
+ } else {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), SymmetricKey: key})
+ }
+ } else {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), Error: errors.New(kao.GetError())})
+ }
+ }
+ policyResults[results.GetPolicyId()] = kaoKeys
}
- return response, nil
+ return policyResults, nil
}
-func (k *KASClient) unwrapNanoTDF(ctx context.Context, header string, kasURL string) ([]byte, error) {
- keypair, err := ocrypto.NewECKeyPair(ocrypto.ECCModeSecp256r1)
- if err != nil {
- return nil, fmt.Errorf("ocrypto.NewECKeyPair failed :%w", err)
- }
-
- publicKeyAsPem, err := keypair.PublicKeyInPemFormat()
- if err != nil {
- return nil, fmt.Errorf("ocrypto.NewECKeyPair.PublicKeyInPemFormat failed :%w", err)
- }
-
- privateKeyAsPem, err := keypair.PrivateKeyInPemFormat()
- if err != nil {
- return nil, fmt.Errorf("ocrypto.NewECKeyPair.PrivateKeyInPemFormat failed :%w", err)
+func (k *KASClient) unwrap(ctx context.Context, requests ...*kas.UnsignedRewrapRequest_WithPolicyRequest) (map[string][]kaoResult, error) {
+ if k.sessionKey == nil {
+ return nil, fmt.Errorf("session key is nil")
}
-
- response, err := k.makeNanoTDFRewrapRequest(ctx, header, kasURL, publicKeyAsPem)
+ pubKey, err := k.sessionKey.PublicKeyInPemFormat()
if err != nil {
- return nil, fmt.Errorf("error making nano rewrap request to kas: %w", err)
+ return nil, fmt.Errorf("ocrypto.PublicKeyInPermFormat failed: %w", err)
}
-
- sessionKey, err := ocrypto.ComputeECDHKey([]byte(privateKeyAsPem), []byte(response.GetSessionPublicKey()))
+ response, err := k.makeRewrapRequest(ctx, requests, pubKey)
if err != nil {
- return nil, fmt.Errorf("ocrypto.ComputeECDHKey failed :%w", err)
+ return nil, fmt.Errorf("error making rewrap request to kas: %w", err)
}
- sessionKey, err = ocrypto.CalculateHKDF(versionSalt(), sessionKey)
+ clientPrivateKey, err := k.sessionKey.PrivateKeyInPemFormat()
if err != nil {
- return nil, fmt.Errorf("ocrypto.CalculateHKDF failed:%w", err)
+ return nil, fmt.Errorf("ocrypto.PrivateKeyInPemFormat failed: %w", err)
}
- aesGcm, err := ocrypto.NewAESGcm(sessionKey)
+ asymDecryption, err := ocrypto.NewAsymDecryption(clientPrivateKey)
if err != nil {
- return nil, fmt.Errorf("ocrypto.NewAESGcm failed:%w", err)
+ return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err)
}
- symmetricKey, err := aesGcm.Decrypt(response.GetEntityWrappedKey())
- if err != nil {
- return nil, fmt.Errorf("AesGcm.Decrypt failed:%w", err)
+ policyResults := make(map[string][]kaoResult)
+ for _, results := range response.GetResponses() {
+ var kaoKeys []kaoResult
+ for _, kao := range results.GetResults() {
+ if kao.GetStatus() == "permit" {
+ wrappedKey := kao.GetKasWrappedKey()
+ key, err := asymDecryption.Decrypt(wrappedKey)
+ if err != nil {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), Error: err})
+ } else {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), SymmetricKey: key})
+ }
+ } else {
+ kaoKeys = append(kaoKeys, kaoResult{KeyAccessObjectID: kao.GetKeyAccessObjectId(), Error: errors.New(kao.GetError())})
+ }
+ }
+ policyResults[results.GetPolicyId()] = kaoKeys
}
- return symmetricKey, nil
+ return policyResults, nil
}
func getGRPCAddress(kasURL string) (string, error) {
@@ -240,23 +196,13 @@ func getGRPCAddress(kasURL string) (string, error) {
return net.JoinHostPort(parsedURL.Hostname(), port), nil
}
-func (k *KASClient) getRewrapRequest(keyAccess KeyAccess, policy string) (*kas.RewrapRequest, error) {
- // check if the session key is nil if not return an error
- if k.sessionKey == nil {
- return nil, fmt.Errorf("session key is nil")
- }
-
- clientPublicKey, err := k.sessionKey.PublicKeyInPemFormat()
- if err != nil {
- return nil, fmt.Errorf("ocrypto.PublicKeyInPemFormat failed: %w", err)
+func (k *KASClient) getRewrapRequest(reqs []*kas.UnsignedRewrapRequest_WithPolicyRequest, pubKey string) (*kas.RewrapRequest, error) {
+ requestBody := &kas.UnsignedRewrapRequest{
+ ClientPublicKey: pubKey,
+ Requests: reqs,
}
- requestBody := rewrapRequestBody{
- Policy: policy,
- KeyAccess: keyAccess,
- ClientPublicKey: clientPublicKey,
- }
- requestBodyJSON, err := json.Marshal(requestBody)
+ requestBodyJSON, err := protojson.Marshal(requestBody)
if err != nil {
return nil, fmt.Errorf("Error marshaling request body: %w", err)
}
diff --git a/sdk/kas_client_test.go b/sdk/kas_client_test.go
index dfdb1f5a7..a45f32119 100644
--- a/sdk/kas_client_test.go
+++ b/sdk/kas_client_test.go
@@ -2,7 +2,6 @@ package sdk
import (
"context"
- "encoding/json"
"net/http"
"testing"
@@ -10,11 +9,13 @@ import (
"github.com/lestrrat-go/jwx/v2/jwk"
"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"
"github.com/opentdf/platform/sdk/auth"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
+ "google.golang.org/protobuf/encoding/protojson"
)
type FakeAccessTokenSource struct {
@@ -26,6 +27,7 @@ type FakeAccessTokenSource struct {
func (fake FakeAccessTokenSource) AccessToken(context.Context, *http.Client) (auth.AccessToken, error) {
return auth.AccessToken(fake.accessToken), nil
}
+
func (fake FakeAccessTokenSource) MakeToken(tokenMaker func(jwk.Key) ([]byte, error)) ([]byte, error) {
return tokenMaker(fake.dpopKey)
}
@@ -57,22 +59,34 @@ func TestCreatingRequest(t *testing.T) {
require.NoError(t, err, "error creating RSA Key")
client := newKASClient(dialOption, tokenSource, &kasKey)
+ require.NoError(t, err)
- keyAccess := KeyAccess{
- KeyType: "type1",
- KasURL: "https://kas.example.org",
- Protocol: "protocol one",
- WrappedKey: "wrapped",
- PolicyBinding: PolicyBinding{
- Alg: "HS256",
- Hash: "somehash",
+ keyAccess := []*kaspb.UnsignedRewrapRequest_WithPolicyRequest{
+ {
+ KeyAccessObjects: []*kaspb.UnsignedRewrapRequest_WithKeyAccessObject{
+ {
+ KeyAccessObject: &kaspb.KeyAccess{
+ KeyType: "type1",
+ KasUrl: "https://kas.example.org",
+ Protocol: "protocol one",
+ WrappedKey: []byte("wrapped"),
+ PolicyBinding: &kaspb.PolicyBinding{
+ Hash: "somehash",
+ Algorithm: "HS256",
+ },
+ EncryptedMetadata: "encrypted",
+ },
+ },
+ },
},
- EncryptedMetadata: "encrypted",
}
+ kp, err := ocrypto.NewRSAKeyPair(1024)
+ require.NoError(t, err, "failed to make pub key")
+ pubkey, err := kp.PublicKeyInPemFormat()
+ require.NoError(t, err, "failed to make pub key")
- req, err := client.getRewrapRequest(keyAccess, "a policy")
+ req, err := client.getRewrapRequest(keyAccess, pubkey)
require.NoError(t, err, "failed to create a rewrap request")
-
if req.GetSignedRequestToken() == "" {
t.Fatalf("didn't produce a signed request token")
}
@@ -85,29 +99,24 @@ func TestCreatingRequest(t *testing.T) {
rb, ok := tok.Get("requestBody")
require.True(t, ok, "didn't contain a request body")
requestBodyJSON, _ := rb.(string)
- var requestBody map[string]interface{}
+ var requestBody kaspb.UnsignedRewrapRequest
- require.NoError(t, json.Unmarshal([]byte(requestBodyJSON), &requestBody), "error unmarshaling request body")
+ require.NoError(t, protojson.Unmarshal([]byte(requestBodyJSON), &requestBody), "error unmarshaling request body")
- cpk, ok := requestBody["clientPublicKey"].(string)
- require.True(t, ok)
-
- _, err = ocrypto.NewAsymEncryption(cpk)
+ _, err = ocrypto.NewAsymEncryption(requestBody.GetClientPublicKey())
require.NoError(t, err, "NewAsymEncryption failed, incorrect public key include")
- assert.Equal(t, "a policy", requestBody["policy"])
-
- requestKeyAccess, ok := requestBody["keyAccess"].(map[string]interface{})
- require.True(t, ok)
- policyBinding, ok := requestKeyAccess["policyBinding"].(map[string]interface{})
- require.True(t, ok)
-
- assert.Equal(t, "https://kas.example.org", requestKeyAccess["url"], "incorrect kasURL")
- assert.Equal(t, "protocol one", requestKeyAccess["protocol"], "incorrect protocol")
- assert.Equal(t, "wrapped", requestKeyAccess["wrappedKey"], "incorrect wrapped key")
- assert.Equal(t, "HS256", policyBinding["alg"], "incorrect policy binding")
- assert.Equal(t, "somehash", policyBinding["hash"], "incorrect policy binding")
- assert.Equal(t, "encrypted", requestKeyAccess["encryptedMetadata"], "incorrect encrypted metadata")
+ require.Len(t, requestBody.GetRequests(), 1)
+ require.Len(t, requestBody.GetRequests()[0].GetKeyAccessObjects(), 1)
+ kao := requestBody.GetRequests()[0].GetKeyAccessObjects()[0]
+ policyBinding := kao.GetKeyAccessObject().GetPolicyBinding()
+
+ assert.Equal(t, "https://kas.example.org", kao.GetKeyAccessObject().GetKasUrl(), "incorrect kasURL")
+ assert.Equal(t, "protocol one", kao.GetKeyAccessObject().GetProtocol(), "incorrect protocol")
+ assert.Equal(t, []byte("wrapped"), kao.GetKeyAccessObject().GetWrappedKey(), "incorrect wrapped key")
+ assert.Equal(t, "HS256", policyBinding.GetAlgorithm(), "incorrect policy binding")
+ assert.Equal(t, "somehash", policyBinding.GetHash(), "incorrect policy binding")
+ assert.Equal(t, "encrypted", kao.GetKeyAccessObject().GetEncryptedMetadata(), "incorrect encrypted metadata")
}
func Test_StoreKASKeys(t *testing.T) {
diff --git a/sdk/nanotdf.go b/sdk/nanotdf.go
index cf735f9bd..601068af2 100644
--- a/sdk/nanotdf.go
+++ b/sdk/nanotdf.go
@@ -14,6 +14,8 @@ import (
"sync"
"time"
+ "github.com/opentdf/platform/protocol/go/kas"
+
"github.com/opentdf/platform/lib/ocrypto"
)
@@ -899,44 +901,78 @@ func (s SDK) CreateNanoTDF(writer io.Writer, reader io.Reader, config NanoTDFCon
// NanoTDF Decrypt
// ============================================================================================================
-// ReadNanoTDF - read the nano tdf and return the decrypted data from it
-func (s SDK) ReadNanoTDF(writer io.Writer, reader io.ReadSeeker) (uint32, error) {
- return s.ReadNanoTDFContext(context.Background(), writer, reader)
+type NanoTDFDecryptHandler struct {
+ reader io.ReadSeeker
+ writer io.Writer
+
+ header NanoTDFHeader
+ headerBuf []byte
}
-// ReadNanoTDFContext - allows cancelling the reader
-func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io.ReadSeeker) (uint32, error) {
- header, headerSize, err := NewNanoTDFHeaderFromReader(reader)
- if err != nil {
- return 0, err
+func createNanoTDFDecryptHandler(reader io.ReadSeeker, writer io.Writer) *NanoTDFDecryptHandler {
+ return &NanoTDFDecryptHandler{
+ reader: reader,
+ writer: writer,
}
+}
- _, err = reader.Seek(0, io.SeekStart)
+func (n *NanoTDFDecryptHandler) getRawHeader() []byte {
+ return n.headerBuf
+}
+
+func (n *NanoTDFDecryptHandler) CreateRewrapRequest(_ context.Context) (map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest, error) {
+ var err error
+ var headerSize uint32
+ n.header, headerSize, err = NewNanoTDFHeaderFromReader(n.reader)
if err != nil {
- return 0, fmt.Errorf("readSeeker.Seek failed: %w", err)
+ return nil, err
+ }
+ _, err = n.reader.Seek(0, io.SeekStart)
+ if err != nil {
+ return nil, fmt.Errorf("readSeeker.Seek failed: %w", err)
}
headerBuf := make([]byte, headerSize)
- _, err = reader.Read(headerBuf)
+ _, err = n.reader.Read(headerBuf)
if err != nil {
- return 0, fmt.Errorf("readSeeker.Seek failed: %w", err)
+ return nil, fmt.Errorf("readSeeker.Seek failed: %w", err)
}
-
- kasURL, err := header.kasURL.GetURL()
+ kasURL, err := n.header.kasURL.GetURL()
if err != nil {
- return 0, fmt.Errorf("readSeeker.Seek failed: %w", err)
+ return nil, err
+ }
+
+ req := &kas.UnsignedRewrapRequest_WithPolicyRequest{
+ KeyAccessObjects: []*kas.UnsignedRewrapRequest_WithKeyAccessObject{
+ {
+ KeyAccessObjectId: "kao-0",
+ KeyAccessObject: &kas.KeyAccess{KasUrl: kasURL, Header: headerBuf},
+ },
+ },
+ Policy: &kas.UnsignedRewrapRequest_WithPolicy{
+ Id: "policy",
+ },
+ Algorithm: "ec:secp256r1",
+ }
+ return map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest{kasURL: req}, nil
+}
+
+func (n *NanoTDFDecryptHandler) Decrypt(_ context.Context, result []kaoResult) (uint32, error) {
+ var err error
+ if len(result) != 1 {
+ return 0, fmt.Errorf("improper result from kas")
}
- symmetricKey, err := s.getNanoRewrapKey(ctx, headerBuf, kasURL)
- if err != nil {
- return 0, err
+ if result[0].Error != nil {
+ return 0, result[0].Error
}
+ key := result[0].SymmetricKey
const (
kPayloadLoadLengthBufLength = 4
)
payloadLengthBuf := make([]byte, kPayloadLoadLengthBufLength)
- _, err = reader.Read(payloadLengthBuf[1:])
+ _, err = n.reader.Read(payloadLengthBuf[1:])
if err != nil {
return 0, fmt.Errorf(" io.Reader.Read failed :%w", err)
@@ -946,12 +982,12 @@ func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io
slog.Debug("ReadNanoTDF", slog.Uint64("payloadLength", uint64(payloadLength)))
cipherDate := make([]byte, payloadLength)
- _, err = reader.Read(cipherDate)
+ _, err = n.reader.Read(cipherDate)
if err != nil {
return 0, fmt.Errorf("readSeeker.Seek failed: %w", err)
}
- aesGcm, err := ocrypto.NewAESGcm(symmetricKey)
+ aesGcm, err := ocrypto.NewAESGcm(key)
if err != nil {
return 0, fmt.Errorf("ocrypto.NewAESGcm failed:%w", err)
}
@@ -962,7 +998,7 @@ func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io
iv := cipherDate[:kNanoTDFIvSize]
ivPadded = append(ivPadded, iv...)
- tagSize, err := SizeOfAuthTagForCipher(header.sigCfg.cipher)
+ tagSize, err := SizeOfAuthTagForCipher(n.header.sigCfg.cipher)
if err != nil {
return 0, fmt.Errorf("SizeOfAuthTagForCipher failed:%w", err)
}
@@ -972,7 +1008,7 @@ func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io
return 0, err
}
- writeLen, err := writer.Write(decryptedData)
+ writeLen, err := n.writer.Write(decryptedData)
if err != nil {
return 0, err
}
@@ -980,37 +1016,56 @@ func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io
return uint32(writeLen), nil
}
-func (s SDK) getNanoRewrapKey(ctx context.Context, header []byte, kasURL string) ([]byte, error) {
+// ReadNanoTDF - read the nano tdf and return the decrypted data from it
+func (s SDK) ReadNanoTDF(writer io.Writer, reader io.ReadSeeker) (uint32, error) {
+ return s.ReadNanoTDFContext(context.Background(), writer, reader)
+}
+
+// ReadNanoTDFContext - allows cancelling the reader
+func (s SDK) ReadNanoTDFContext(ctx context.Context, writer io.Writer, reader io.ReadSeeker) (uint32, error) {
+ handler := createNanoTDFDecryptHandler(reader, writer)
+
+ symmetricKey, err := s.getNanoRewrapKey(ctx, handler)
+ if err != nil {
+ return 0, err
+ }
+ return handler.Decrypt(ctx, []kaoResult{{SymmetricKey: symmetricKey}})
+}
+
+func (s SDK) getNanoRewrapKey(ctx context.Context, decryptor *NanoTDFDecryptHandler) ([]byte, error) {
+ req, err := decryptor.CreateRewrapRequest(ctx)
+ if err != nil {
+ return nil, err
+ }
+
if s.collectionStore != nil {
- if key, found := s.collectionStore.get(header); found {
+ if key, found := s.collectionStore.get(decryptor.getRawHeader()); found {
return key, nil
}
}
- encodedHeader := ocrypto.Base64Encode(header)
client := newKASClient(s.dialOptions, s.tokenSource, nil)
+ kasURL, err := decryptor.header.kasURL.GetURL()
+ if err != nil {
+ return nil, err
+ }
- symmetricKey, err := client.unwrapNanoTDF(ctx, string(encodedHeader), kasURL)
+ policyResult, err := client.nanoUnwrap(ctx, req[kasURL])
if err != nil {
- return nil, fmt.Errorf("readSeeker.Seek failed: %w", err)
+ return nil, fmt.Errorf("rewrap failed: %w", err)
}
- if s.collectionStore != nil {
- s.collectionStore.store(header, symmetricKey)
+ result, ok := policyResult["policy"]
+ if !ok || len(result) != 1 {
+ return nil, fmt.Errorf("policy was not found in rewrap response")
+ }
+ if result[0].Error != nil {
+ return nil, result[0].Error
}
- return symmetricKey, nil
-}
-
-type requestBody struct {
- Algorithm string `json:"algorithm,omitempty"`
- KeyAccess keyAccess `json:"keyAccess"`
- ClientPublicKey string `json:"clientPublicKey"`
-}
-type keyAccess struct {
- Header string `json:"header"`
- KeyAccessType string `json:"type"`
- URL string `json:"url"`
- Protocol string `json:"protocol"`
+ if s.collectionStore != nil {
+ s.collectionStore.store(decryptor.getRawHeader(), result[0].SymmetricKey)
+ }
+ return result[0].SymmetricKey, nil
}
func versionSalt() []byte {
diff --git a/sdk/tdf.go b/sdk/tdf.go
index 50fada4b7..420d786f2 100644
--- a/sdk/tdf.go
+++ b/sdk/tdf.go
@@ -9,8 +9,11 @@ import (
"fmt"
"io"
"math"
+ "strconv"
"strings"
+ "github.com/opentdf/platform/protocol/go/kas"
+
"github.com/google/uuid"
"github.com/opentdf/platform/lib/ocrypto"
"github.com/opentdf/platform/sdk/auth"
@@ -72,11 +75,45 @@ type TDFObject struct {
payloadKey [kKeySize]byte
}
+type tdf3DecryptHandler struct {
+ writer io.Writer
+ reader *Reader
+}
+
+func (r *tdf3DecryptHandler) Decrypt(ctx context.Context, results []kaoResult) (uint32, error) {
+ err := r.reader.buildKey(ctx, results)
+ if err != nil {
+ return 0, err
+ }
+ data, err := io.ReadAll(r.reader)
+ if err != nil {
+ return 0, err
+ }
+
+ n, err := r.writer.Write(data)
+ return uint32(n), err
+}
+
+func (r *tdf3DecryptHandler) CreateRewrapRequest(ctx context.Context) (map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest, error) {
+ return createRewrapRequest(ctx, r.reader)
+}
+
+func (s SDK) createTDF3DecryptHandler(writer io.Writer, reader io.ReadSeeker) (*tdf3DecryptHandler, error) {
+ tdfReader, err := s.LoadTDF(reader)
+ if err != nil {
+ return nil, err
+ }
+
+ return &tdf3DecryptHandler{
+ reader: tdfReader,
+ writer: writer,
+ }, nil
+}
+
func (t TDFObject) Size() int64 {
return t.size
}
-// CreateTDF reads plain text from the given reader and saves it to the writer, subject to the given options
func (s SDK) CreateTDF(writer io.Writer, reader io.ReadSeeker, opts ...TDFOption) (*TDFObject, error) {
return s.CreateTDFContext(context.Background(), writer, reader, opts...)
}
@@ -209,8 +246,7 @@ func (s SDK) CreateTDFContext(ctx context.Context, writer io.Writer, reader io.R
EncryptedSize: int64(len(cipherData)),
}
- tdfObject.manifest.EncryptionInformation.IntegrityInformation.Segments =
- append(tdfObject.manifest.EncryptionInformation.IntegrityInformation.Segments, segmentInfo)
+ tdfObject.manifest.EncryptionInformation.IntegrityInformation.Segments = append(tdfObject.manifest.EncryptionInformation.IntegrityInformation.Segments, segmentInfo)
totalSegments--
readPos += readSize
@@ -274,7 +310,7 @@ func (s SDK) CreateTDFContext(ctx context.Context, writer io.Writer, reader io.R
encoded := ocrypto.Base64Encode([]byte(completeHashBuilder.String()))
- var assertionSigningKey = AssertionKey{}
+ assertionSigningKey := AssertionKey{}
// Set default to HS256 and payload key
assertionSigningKey.Alg = AssertionKeyAlgHS256
@@ -633,8 +669,8 @@ func (r *Reader) ReadAt(buf []byte, offset int64) (int, error) { //nolint:funlen
}
defaultSegmentSize := r.manifest.EncryptionInformation.IntegrityInformation.DefaultSegmentSize
- var start = math.Floor(float64(offset) / float64(defaultSegmentSize))
- var end = math.Ceil(float64(offset+int64(len(buf))) / float64(defaultSegmentSize))
+ start := math.Floor(float64(offset) / float64(defaultSegmentSize))
+ end := math.Ceil(float64(offset+int64(len(buf))) / float64(defaultSegmentSize))
firstSegment := int64(start)
lastSegment := int64(end)
@@ -766,7 +802,7 @@ func (r *Reader) DataAttributes() ([]string, error) {
/*
*WARNING:* Using this function is unsafe since KAS will no longer be able to prevent access to the key.
-Retrieve the payload key, either from performing an unwrap or from a previous unwrap,
+Retrieve the payload key, either from performing an buildKey or from a previous buildKey,
and write it to a user buffer.
OUTPUTS:
@@ -784,27 +820,92 @@ func (r *Reader) UnsafePayloadKeyRetrieval() ([]byte, error) {
return r.payloadKey, nil
}
-// Unwraps the payload key, if possible, using the access service
-func (r *Reader) doPayloadKeyUnwrap(ctx context.Context) error { //nolint:gocognit // Better readability keeping it as is
+func createRewrapRequest(_ context.Context, r *Reader) (map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest, error) {
+ kasReqs := make(map[string]*kas.UnsignedRewrapRequest_WithPolicyRequest)
+ for i, kao := range r.manifest.EncryptionInformation.KeyAccessObjs {
+ kaoID := fmt.Sprintf("kao-%d", i)
+ key, err := ocrypto.Base64Decode([]byte(kao.WrappedKey))
+ if err != nil {
+ return nil, fmt.Errorf("could not decode wrapper key: %w", err)
+ }
+ var alg string
+ var hash string
+ invalidPolicy := false
+ switch policyBinding := kao.PolicyBinding.(type) {
+ case string:
+ hash = policyBinding
+ case map[string]interface{}:
+ var ok bool
+ hash, ok = policyBinding["hash"].(string)
+ invalidPolicy = !ok
+ alg, ok = policyBinding["alg"].(string)
+ invalidPolicy = invalidPolicy || !ok
+ case (PolicyBinding):
+ hash = policyBinding.Hash
+ alg = policyBinding.Alg
+ default:
+ invalidPolicy = true
+ }
+ if invalidPolicy {
+ return nil, fmt.Errorf("invalid policy object: %s", kao.PolicyBinding)
+ }
+ kaoReq := &kas.UnsignedRewrapRequest_WithKeyAccessObject{
+ KeyAccessObjectId: kaoID,
+ KeyAccessObject: &kas.KeyAccess{
+ KeyType: kao.KeyType,
+ KasUrl: kao.KasURL,
+ Kid: kao.KID,
+ Protocol: kao.Protocol,
+ PolicyBinding: &kas.PolicyBinding{
+ Hash: hash,
+ Algorithm: alg,
+ },
+ SplitId: kao.SplitID,
+ WrappedKey: key,
+ },
+ }
+ if req, ok := kasReqs[kao.KasURL]; ok {
+ req.KeyAccessObjects = append(req.KeyAccessObjects, kaoReq)
+ } else {
+ rewrapReq := kas.UnsignedRewrapRequest_WithPolicyRequest{
+ Policy: &kas.UnsignedRewrapRequest_WithPolicy{
+ Body: r.manifest.EncryptionInformation.Policy,
+ Id: "policy",
+ },
+ KeyAccessObjects: []*kas.UnsignedRewrapRequest_WithKeyAccessObject{kaoReq},
+ }
+ kasReqs[kao.KasURL] = &rewrapReq
+ }
+ }
+
+ return kasReqs, nil
+}
+
+func getIdx(kaoID string) int {
+ idx, _ := strconv.Atoi(strings.Split(kaoID, "-")[1])
+ return idx
+}
+
+func (r *Reader) buildKey(_ context.Context, results []kaoResult) error {
var unencryptedMetadata []byte
var payloadKey [kKeySize]byte
knownSplits := make(map[string]bool)
foundSplits := make(map[string]bool)
skippedSplits := make(map[keySplitStep]error)
- for _, keyAccessObj := range r.manifest.EncryptionInformation.KeyAccessObjs {
- client := newKASClient(r.dialOptions, r.tokenSource, &r.kasSessionKey)
-
+ for _, kaoRes := range results {
+ idx := getIdx(kaoRes.KeyAccessObjectID)
+ keyAccessObj := r.manifest.KeyAccessObjs[idx]
ss := keySplitStep{KAS: keyAccessObj.KasURL, SplitID: keyAccessObj.SplitID}
- var err error
- var wrappedKey []byte
+ wrappedKey := kaoRes.SymmetricKey
+ err := kaoRes.Error
knownSplits[ss.SplitID] = true
if foundSplits[ss.SplitID] {
// already found
continue
}
- wrappedKey, err = client.unwrap(ctx, keyAccessObj, r.manifest.EncryptionInformation.Policy)
+
if err != nil {
errToReturn := fmt.Errorf("kao unwrap failed for split %v: %w", ss, err)
if strings.Contains(err.Error(), codes.InvalidArgument.String()) {
@@ -956,6 +1057,40 @@ func (r *Reader) doPayloadKeyUnwrap(ctx context.Context) error { //nolint:gocogn
return nil
}
+// Unwraps the payload key, if possible, using the access service
+func (r *Reader) doPayloadKeyUnwrap(ctx context.Context) error { //nolint:gocognit // Better readability keeping it as is
+ kasClient := newKASClient(r.dialOptions, r.tokenSource, &r.kasSessionKey)
+
+ var kaoResults []kaoResult
+ reqFail := func(err error, req *kas.UnsignedRewrapRequest_WithPolicyRequest) {
+ for _, kao := range req.GetKeyAccessObjects() {
+ kaoResults = append(kaoResults, kaoResult{
+ KeyAccessObjectID: kao.GetKeyAccessObjectId(),
+ Error: err,
+ })
+ }
+ }
+
+ reqs, err := createRewrapRequest(ctx, r)
+ if err != nil {
+ return err
+ }
+ for _, req := range reqs {
+ policyRes, err := kasClient.unwrap(ctx, req)
+ if err != nil {
+ reqFail(err, req)
+ }
+ result, ok := policyRes["policy"]
+ if !ok {
+ err = fmt.Errorf("could not find policy in rewrap response")
+ reqFail(err, req)
+ }
+ kaoResults = append(kaoResults, result...)
+ }
+
+ return r.buildKey(ctx, kaoResults)
+}
+
// calculateSignature calculate signature of data of the given algorithm.
func calculateSignature(data []byte, secret []byte, alg IntegrityAlgorithm) (string, error) {
if alg == HS256 {
diff --git a/sdk/tdf_test.go b/sdk/tdf_test.go
index dd2bce58d..2c55de0e1 100644
--- a/sdk/tdf_test.go
+++ b/sdk/tdf_test.go
@@ -6,7 +6,6 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
- "encoding/json"
"fmt"
"io"
"log/slog"
@@ -18,6 +17,8 @@ import (
"testing"
"time"
+ "google.golang.org/protobuf/encoding/protojson"
+
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/opentdf/platform/lib/ocrypto"
kaspb "github.com/opentdf/platform/protocol/go/kas"
@@ -1215,7 +1216,7 @@ func (s *TDFSuite) testDecryptWithReader(sdk *SDK, tdfFile, decryptedTdfFileName
r, err := sdk.LoadTDF(readSeeker)
s.Require().NoError(err)
- ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(60*time.Millisecond))
+ ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(300*time.Minute))
defer cancel()
err = r.Init(ctx)
s.Require().NoError(err)
@@ -1427,40 +1428,53 @@ func (f *FakeKas) Rewrap(_ context.Context, in *kaspb.RewrapRequest) (*kaspb.Rew
if !ok {
return nil, fmt.Errorf("requestBody not a string")
}
- entityWrappedKey := f.getRewrappedKey(requestBodyStr)
+ result := f.getRewrapResponse(requestBodyStr)
- return &kaspb.RewrapResponse{EntityWrappedKey: entityWrappedKey}, nil
+ return result, nil
}
func (f *FakeKas) PublicKey(_ context.Context, _ *kaspb.PublicKeyRequest) (*kaspb.PublicKeyResponse, error) {
return &kaspb.PublicKeyResponse{PublicKey: f.KASInfo.PublicKey, Kid: f.KID}, nil
}
-func (f *FakeKas) getRewrappedKey(rewrapRequest string) []byte {
- bodyData := RequestBody{}
- err := json.Unmarshal([]byte(rewrapRequest), &bodyData)
+func (f *FakeKas) getRewrapResponse(rewrapRequest string) *kaspb.RewrapResponse {
+ bodyData := kaspb.UnsignedRewrapRequest{}
+ err := protojson.Unmarshal([]byte(rewrapRequest), &bodyData)
f.s.Require().NoError(err, "json.Unmarshal failed")
+ resp := &kaspb.RewrapResponse{}
+
+ for _, req := range bodyData.GetRequests() {
+ results := &kaspb.PolicyRewrapResult{PolicyId: req.GetPolicy().GetId()}
+ resp.Responses = append(resp.Responses, results)
+ for _, kaoReq := range req.GetKeyAccessObjects() {
+ kao := kaoReq.GetKeyAccessObject()
+ wrappedKey := kaoReq.GetKeyAccessObject().GetWrappedKey()
+
+ kasPrivateKey := strings.ReplaceAll(f.privateKey, "\n\t", "\n")
+ if kao.GetKid() != "" && kao.GetKid() != f.KID {
+ // old kid
+ lk, ok := f.legakeys[kaoReq.GetKeyAccessObject().GetKid()]
+ f.s.Require().True(ok, "unable to find key [%s]", kao.GetKid())
+ kasPrivateKey = strings.ReplaceAll(lk.private, "\n\t", "\n")
+ }
- wrappedKey, err := ocrypto.Base64Decode([]byte(bodyData.WrappedKey))
- f.s.Require().NoError(err, "ocrypto.Base64Decode failed")
-
- kasPrivateKey := strings.ReplaceAll(f.privateKey, "\n\t", "\n")
- if bodyData.KID != "" && bodyData.KID != f.KID {
- // old kid
- lk, ok := f.legakeys[bodyData.KID]
- f.s.Require().True(ok, "unable to find key [%s]", bodyData.KID)
- kasPrivateKey = strings.ReplaceAll(lk.private, "\n\t", "\n")
+ asymDecrypt, err := ocrypto.NewAsymDecryption(kasPrivateKey)
+ f.s.Require().NoError(err, "ocrypto.NewAsymDecryption failed")
+ symmetricKey, err := asymDecrypt.Decrypt(wrappedKey)
+ f.s.Require().NoError(err, "ocrypto.Decrypt failed")
+ asymEncrypt, err := ocrypto.NewAsymEncryption(bodyData.GetClientPublicKey())
+ f.s.Require().NoError(err, "ocrypto.NewAsymEncryption failed")
+ entityWrappedKey, err := asymEncrypt.Encrypt(symmetricKey)
+ f.s.Require().NoError(err, "ocrypto.encrypt failed")
+ kaoResult := &kaspb.KeyAccessRewrapResult{
+ Result: &kaspb.KeyAccessRewrapResult_KasWrappedKey{KasWrappedKey: entityWrappedKey},
+ Status: "permit",
+ KeyAccessObjectId: kaoReq.GetKeyAccessObjectId(),
+ }
+ results.Results = append(results.Results, kaoResult)
+ }
}
-
- asymDecrypt, err := ocrypto.NewAsymDecryption(kasPrivateKey)
- f.s.Require().NoError(err, "ocrypto.NewAsymDecryption failed")
- symmetricKey, err := asymDecrypt.Decrypt(wrappedKey)
- f.s.Require().NoError(err, "ocrypto.Decrypt failed")
- asymEncrypt, err := ocrypto.NewAsymEncryption(bodyData.ClientPublicKey)
- f.s.Require().NoError(err, "ocrypto.NewAsymEncryption failed")
- entityWrappedKey, err := asymEncrypt.Encrypt(symmetricKey)
- f.s.Require().NoError(err, "ocrypto.encrypt failed")
- return entityWrappedKey
+ return resp
}
func (s *TDFSuite) checkIdentical(file, checksum string) bool {
diff --git a/service/kas/access/accessPdp.go b/service/kas/access/accessPdp.go
index 04e7553cf..8bdfb87e7 100644
--- a/service/kas/access/accessPdp.go
+++ b/service/kas/access/accessPdp.go
@@ -3,6 +3,7 @@ package access
import (
"context"
"errors"
+ "fmt"
"github.com/opentdf/platform/protocol/go/authorization"
"github.com/opentdf/platform/protocol/go/policy"
@@ -14,30 +15,51 @@ const (
ErrDecisionCountUnexpected = Error("authorization decision count unexpected")
)
-func (p *Provider) canAccess(ctx context.Context, token *authorization.Token, policy Policy) (bool, error) {
- if len(policy.Body.Dissem) > 0 {
- // TODO: Move dissems check to the getdecisions endpoint
- p.Logger.Error("Dissems check is not enabled in v2 platform kas")
- }
- if len(policy.Body.DataAttributes) > 0 {
- attrAccess, err := p.checkAttributes(ctx, policy.Body.DataAttributes, token)
- if err != nil {
- return false, err
+type PDPAccessResult struct {
+ Access bool
+ Error error
+ Policy *Policy
+}
+
+func (p *Provider) canAccess(ctx context.Context, token *authorization.Token, policies []*Policy) ([]PDPAccessResult, error) {
+ var res []PDPAccessResult
+ var rasList []*authorization.ResourceAttribute
+ idPolicyMap := make(map[string]*Policy)
+ for i, policy := range policies {
+ if len(policy.Body.Dissem) > 0 {
+ // TODO: Move dissems check to the getdecisions endpoint
+ p.Logger.Error("Dissems check is not enabled in v2 platform kas")
+ }
+ if len(policy.Body.DataAttributes) > 0 {
+ id := fmt.Sprintf("rewrap-%d", i)
+ ras := &authorization.ResourceAttribute{ResourceAttributesId: id}
+ for _, attr := range policy.Body.DataAttributes {
+ ras.AttributeValueFqns = append(ras.AttributeValueFqns, attr.URI)
+ }
+ rasList = append(rasList, ras)
+ idPolicyMap[id] = policy
+ } else {
+ res = append(res, PDPAccessResult{Access: true, Policy: policy})
}
- return attrAccess, nil
}
- // if no dissem and no attributes then allow
- return true, nil
-}
-func (p *Provider) checkAttributes(ctx context.Context, dataAttrs []Attribute, ent *authorization.Token) (bool, error) {
- ras := []*authorization.ResourceAttribute{{
- AttributeValueFqns: make([]string, 0),
- }}
+ dr, err := p.checkAttributes(ctx, rasList, token)
- for _, attr := range dataAttrs {
- ras[0].AttributeValueFqns = append(ras[0].GetAttributeValueFqns(), attr.URI)
+ if err != nil {
+ return nil, err
}
+ for _, resp := range dr.GetDecisionResponses() {
+ policy, ok := idPolicyMap[resp.GetResourceAttributesId()]
+ if !ok { // this really should not happen
+ continue
+ }
+ res = append(res, PDPAccessResult{Policy: policy, Access: resp.GetDecision() == authorization.DecisionResponse_DECISION_PERMIT})
+ }
+
+ return res, nil
+}
+
+func (p *Provider) checkAttributes(ctx context.Context, ras []*authorization.ResourceAttribute, ent *authorization.Token) (*authorization.GetDecisionsByTokenResponse, error) {
in := authorization.GetDecisionsByTokenRequest{
DecisionRequests: []*authorization.TokenDecisionRequest{
{
@@ -52,14 +74,7 @@ func (p *Provider) checkAttributes(ctx context.Context, dataAttrs []Attribute, e
dr, err := p.SDK.Authorization.GetDecisionsByToken(ctx, &in)
if err != nil {
p.Logger.ErrorContext(ctx, "Error received from GetDecisionsByToken", "err", err)
- return false, errors.Join(ErrDecisionUnexpected, err)
- }
- if len(dr.GetDecisionResponses()) != 1 {
- p.Logger.ErrorContext(ctx, ErrDecisionCountUnexpected.Error(), "count", len(dr.GetDecisionResponses()))
- return false, ErrDecisionCountUnexpected
- }
- if dr.GetDecisionResponses()[0].GetDecision() == authorization.DecisionResponse_DECISION_PERMIT {
- return true, nil
+ return nil, errors.Join(ErrDecisionUnexpected, err)
}
- return false, nil
+ return dr, nil
}
diff --git a/service/kas/access/attribute.go b/service/kas/access/attribute.go
index 75e9c7113..27c088d90 100644
--- a/service/kas/access/attribute.go
+++ b/service/kas/access/attribute.go
@@ -4,8 +4,6 @@ import (
"crypto"
)
-const schemaVersion = "1.1.0"
-
type Attribute struct {
URI string `json:"attribute"` // attribute
PublicKey crypto.PublicKey `json:"pubKey"` // pubKey
diff --git a/service/kas/access/policy_test.go b/service/kas/access/policy_test.go
deleted file mode 100644
index 09bb5922e..000000000
--- a/service/kas/access/policy_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package access
diff --git a/service/kas/access/rewrap.go b/service/kas/access/rewrap.go
index ea4e53821..d57a34cdb 100644
--- a/service/kas/access/rewrap.go
+++ b/service/kas/access/rewrap.go
@@ -17,7 +17,6 @@ import (
"fmt"
"log/slog"
"net/http"
- "strings"
"time"
"connectrpc.com/connect"
@@ -27,6 +26,7 @@ import (
"github.com/opentdf/platform/lib/ocrypto"
"github.com/opentdf/platform/protocol/go/authorization"
"go.opentelemetry.io/otel/trace"
+ "google.golang.org/protobuf/encoding/protojson"
kaspb "github.com/opentdf/platform/protocol/go/kas"
"github.com/opentdf/platform/sdk"
@@ -38,6 +38,13 @@ import (
"google.golang.org/grpc/status"
)
+const (
+ kTDF3Algorithm = "rsa:2048"
+ kNanoAlgorithm = "ec:secp256r1"
+ kFailedStatus = "fail"
+ kPermitStatus = "permit"
+)
+
type SignedRequestBody struct {
RequestBody string `json:"requestBody"`
}
@@ -58,6 +65,14 @@ type entityInfo struct {
Token string `json:"-"`
}
+type kaoResult struct {
+ ID string
+ Key []byte
+ Error error
+}
+
+type policyKAOResults map[string]map[string]kaoResult
+
const (
kNanoTDFGMACLength = 8
ErrUser = Error("request error")
@@ -121,7 +136,47 @@ func justRequestBody(ctx context.Context, token jwt.Token, logger logger.Logger)
return rbString, nil
}
-func extractSRTBody(ctx context.Context, headers http.Header, in *kaspb.RewrapRequest, logger logger.Logger) (*RequestBody, error) {
+func extractAndConvertV1SRTBody(body []byte) (kaspb.UnsignedRewrapRequest, error) {
+ var requestBody RequestBody
+ if err := json.Unmarshal(body, &requestBody); err != nil {
+ return kaspb.UnsignedRewrapRequest{}, err
+ }
+
+ kao := requestBody.KeyAccess
+ // ignore errors, maybe nanoTDF
+ binding, _ := extractPolicyBinding(kao.PolicyBinding)
+
+ reqs := []*kaspb.UnsignedRewrapRequest_WithPolicyRequest{
+ {
+ KeyAccessObjects: []*kaspb.UnsignedRewrapRequest_WithKeyAccessObject{
+ {KeyAccessObjectId: "kao-0", KeyAccessObject: &kaspb.KeyAccess{
+ EncryptedMetadata: kao.EncryptedMetadata,
+ PolicyBinding: &kaspb.PolicyBinding{Hash: binding, Algorithm: kao.Algorithm},
+ Protocol: kao.Protocol,
+ KeyType: kao.Type,
+ KasUrl: kao.URL,
+ Kid: kao.KID,
+ SplitId: kao.SID,
+ WrappedKey: kao.WrappedKey,
+ Header: kao.Header,
+ }},
+ },
+ Algorithm: requestBody.Algorithm,
+ Policy: &kaspb.UnsignedRewrapRequest_WithPolicy{
+ Id: "policy-1",
+ Body: requestBody.Policy,
+ },
+ },
+ }
+
+ return kaspb.UnsignedRewrapRequest{
+ ClientPublicKey: requestBody.ClientPublicKey,
+ Requests: reqs,
+ }, nil
+}
+
+func extractSRTBody(ctx context.Context, headers http.Header, in *kaspb.RewrapRequest, logger logger.Logger) (*kaspb.UnsignedRewrapRequest, bool, error) {
+ isV1 := false
// First load legacy method for verifying SRT
if vpk, ok := headers["X-Virtrupubkey"]; ok && len(vpk) == 1 {
logger.InfoContext(ctx, "Legacy Client: Processing X-Virtrupubkey")
@@ -142,79 +197,63 @@ func extractSRTBody(ctx context.Context, headers http.Header, in *kaspb.RewrapRe
rbString, err = noverify(ctx, srt, logger)
if err != nil {
logger.ErrorContext(ctx, "unable to load RSA verifier", "err", err)
- return nil, err
+ return nil, false, err
}
} else {
// verify and validate the request token
var err error
rbString, err = verifySRT(ctx, srt, dpopJWK, logger)
if err != nil {
- return nil, err
+ return nil, false, err
}
}
- var requestBody RequestBody
- err = json.Unmarshal([]byte(rbString), &requestBody)
- if err != nil {
- logger.WarnContext(ctx, "invalid request body")
- return nil, err400("invalid request body")
+ var requestBody kaspb.UnsignedRewrapRequest
+ err = protojson.Unmarshal([]byte(rbString), &requestBody)
+ // if there are no requests then it could be a v1 request
+ if err != nil || len(requestBody.GetRequests()) == 0 {
+ logger.WarnContext(ctx, "invalid request body! checking v1 SRT")
+ requestBody, err = extractAndConvertV1SRTBody([]byte(rbString))
+ if err != nil {
+ return nil, false, err400("invalid request body")
+ }
+ isV1 = true
}
- logger.DebugContext(ctx, "extracted request body", slog.Any("requestBody", requestBody))
+ logger.DebugContext(ctx, "extracted request body", slog.Any("requestBody", requestBody.String()))
- logger.DebugContext(ctx, "extract public key", "requestBody.ClientPublicKey", requestBody.ClientPublicKey)
- block, _ := pem.Decode([]byte(requestBody.ClientPublicKey))
+ logger.DebugContext(ctx, "extract public key", "requestBody.ClientPublicKey", requestBody.GetClientPublicKey())
+ block, _ := pem.Decode([]byte(requestBody.GetClientPublicKey()))
if block == nil {
logger.WarnContext(ctx, "missing clientPublicKey")
- return nil, err400("clientPublicKey failure")
+ return nil, isV1, err400("clientPublicKey failure")
}
// Try to parse the clientPublicKey
clientPublicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
logger.WarnContext(ctx, "failure to parse clientPublicKey", "err", err)
- return nil, err400("clientPublicKey parse failure")
+ return nil, isV1, err400("clientPublicKey parse failure")
}
// Check to make sure the clientPublicKey is a supported key type
- switch publicKey := clientPublicKey.(type) {
+ switch clientPublicKey.(type) {
case *rsa.PublicKey:
- requestBody.PublicKey = publicKey
- return &requestBody, nil
+ return &requestBody, isV1, nil
case *ecdsa.PublicKey:
- requestBody.PublicKey = publicKey
- return &requestBody, nil
+ return &requestBody, isV1, nil
default:
logger.WarnContext(ctx, fmt.Sprintf("clientPublicKey not a supported key, was [%T]", clientPublicKey))
- return nil, err400("clientPublicKey unsupported type")
- }
-}
-
-func extractPolicyBinding(policyBinding interface{}) (string, error) {
- switch v := policyBinding.(type) {
- case string:
- return v, nil
- case map[string]interface{}:
- if hash, ok := v["hash"].(string); ok {
- return hash, nil
- }
- return "", fmt.Errorf("invalid policy binding object, missing 'hash' field")
- default:
- return "", fmt.Errorf("unsupported policy binding type")
+ return nil, isV1, err400("clientPublicKey unsupported type")
}
}
-func verifyAndParsePolicy(ctx context.Context, requestBody *RequestBody, k []byte, logger logger.Logger) (*Policy, error) {
- actualHMAC, err := generateHMACDigest(ctx, []byte(requestBody.Policy), k, logger)
+func verifyPolicyBinding(ctx context.Context, policy []byte, kao *kaspb.UnsignedRewrapRequest_WithKeyAccessObject, symKey []byte, logger logger.Logger) error {
+ actualHMAC, err := generateHMACDigest(ctx, policy, symKey, logger)
if err != nil {
logger.WarnContext(ctx, "unable to generate policy hmac", "err", err)
- return nil, err400("bad request")
- }
-
- policyBinding, err := extractPolicyBinding(requestBody.KeyAccess.PolicyBinding)
- if err != nil {
- logger.WarnContext(ctx, "invalid policy binding", "err", err)
- return nil, err400("bad request")
+ return err400("bad request")
}
+ policyBinding := kao.GetKeyAccessObject().GetPolicyBinding().GetHash()
expectedHMAC := make([]byte, base64.StdEncoding.DecodedLen(len(policyBinding)))
n, err := base64.StdEncoding.Decode(expectedHMAC, []byte(policyBinding))
if err == nil {
@@ -223,25 +262,28 @@ func verifyAndParsePolicy(ctx context.Context, requestBody *RequestBody, k []byt
expectedHMAC = expectedHMAC[:n]
if err != nil {
logger.WarnContext(ctx, "invalid policy binding", "err", err)
- return nil, err400("bad request")
+ return err400("bad request")
}
if !hmac.Equal(actualHMAC, expectedHMAC) {
logger.WarnContext(ctx, "policy hmac mismatch", "policyBinding", policyBinding)
- return nil, err400("bad request")
+ return err400("bad request")
}
- sDecPolicy, err := base64.StdEncoding.DecodeString(requestBody.Policy)
- if err != nil {
- logger.WarnContext(ctx, "unable to decode policy", "err", err)
- return nil, err400("bad request")
- }
- decoder := json.NewDecoder(strings.NewReader(string(sDecPolicy)))
- var policy Policy
- err = decoder.Decode(&policy)
- if err != nil {
- logger.WarnContext(ctx, "unable to decode policy", "err", err)
- return nil, err400("bad request")
+
+ return nil
+}
+
+func extractPolicyBinding(policyBinding interface{}) (string, error) {
+ switch v := policyBinding.(type) {
+ case string:
+ return v, nil
+ case map[string]interface{}:
+ if hash, ok := v["hash"].(string); ok {
+ return hash, nil
+ }
+ return "", fmt.Errorf("invalid policy binding object, missing 'hash' field")
+ default:
+ return "", fmt.Errorf("unsupported policy binding type")
}
- return &policy, nil
}
func getEntityInfo(ctx context.Context, logger *logger.Logger) (*entityInfo, error) {
@@ -268,11 +310,51 @@ func getEntityInfo(ctx context.Context, logger *logger.Logger) (*entityInfo, err
return info, nil
}
+func failedKAORewrap(res map[string]kaoResult, kao *kaspb.UnsignedRewrapRequest_WithKeyAccessObject, err error) {
+ res[kao.GetKeyAccessObjectId()] = kaoResult{
+ ID: kao.GetKeyAccessObjectId(),
+ Error: err,
+ }
+}
+
+func addResultsToResponse(response *kaspb.RewrapResponse, result policyKAOResults) {
+ for policyID, policyMap := range result {
+ policyResults := &kaspb.PolicyRewrapResult{
+ PolicyId: policyID,
+ }
+ for kaoID, kaoRes := range policyMap {
+ kaoResult := &kaspb.KeyAccessRewrapResult{
+ KeyAccessObjectId: kaoID,
+ }
+ switch {
+ case kaoRes.Error != nil:
+ kaoResult.Status = kFailedStatus
+ kaoResult.Result = &kaspb.KeyAccessRewrapResult_Error{Error: kaoRes.Error.Error()}
+ case kaoRes.Key != nil:
+ kaoResult.Status = kPermitStatus
+ kaoResult.Result = &kaspb.KeyAccessRewrapResult_KasWrappedKey{KasWrappedKey: kaoRes.Key}
+ default:
+ kaoResult.Status = kFailedStatus
+ kaoResult.Result = &kaspb.KeyAccessRewrapResult_Error{Error: "kao not processed by kas"}
+ }
+ policyResults.Results = append(policyResults.Results, kaoResult)
+ }
+ response.Responses = append(response.Responses, policyResults)
+ }
+}
+
+func getMapValue[Map ~map[K]V, K comparable, V any](m Map) *V {
+ for _, v := range m {
+ return &v
+ }
+ return nil
+}
+
func (p *Provider) Rewrap(ctx context.Context, req *connect.Request[kaspb.RewrapRequest]) (*connect.Response[kaspb.RewrapResponse], error) {
in := req.Msg
p.Logger.DebugContext(ctx, "REWRAP")
- body, err := extractSRTBody(ctx, req.Header(), in, *p.Logger)
+ body, isV1, err := extractSRTBody(ctx, req.Header(), in, *p.Logger)
if err != nil {
p.Logger.DebugContext(ctx, "unverifiable srt", "err", err)
return nil, err
@@ -284,224 +366,364 @@ func (p *Provider) Rewrap(ctx context.Context, req *connect.Request[kaspb.Rewrap
return nil, err
}
- if body.Algorithm == "" {
- p.Logger.DebugContext(ctx, "default rewrap algorithm")
- body.Algorithm = "rsa:2048"
- }
+ resp := &kaspb.RewrapResponse{}
- if body.Algorithm == "ec:secp256r1" {
- rsp, err := p.nanoTDFRewrap(ctx, body, entityInfo)
- if err != nil {
- p.Logger.ErrorContext(ctx, "rewrap nano", "err", err)
+ var nanoReqs []*kaspb.UnsignedRewrapRequest_WithPolicyRequest
+ var tdf3Reqs []*kaspb.UnsignedRewrapRequest_WithPolicyRequest
+ for _, req := range body.GetRequests() {
+ switch {
+ case req.GetAlgorithm() == kNanoAlgorithm:
+ nanoReqs = append(nanoReqs, req)
+ case req.GetAlgorithm() == "":
+ req.Algorithm = kTDF3Algorithm
+ tdf3Reqs = append(tdf3Reqs, req)
+ default:
+ tdf3Reqs = append(tdf3Reqs, req)
}
- p.Logger.DebugContext(ctx, "rewrap nano", "rsp", rsp)
- return connect.NewResponse(rsp), err
}
- rsp, err := p.tdf3Rewrap(ctx, body, entityInfo)
- if err != nil {
- p.Logger.ErrorContext(ctx, "rewrap tdf3", "err", err)
+ var results policyKAOResults
+ if len(tdf3Reqs) > 0 {
+ results = p.tdf3Rewrap(ctx, tdf3Reqs, body.GetClientPublicKey(), entityInfo)
+ addResultsToResponse(resp, results)
+ } else {
+ resp.SessionPublicKey, results = p.nanoTDFRewrap(ctx, nanoReqs, body.GetClientPublicKey(), entityInfo)
+ addResultsToResponse(resp, results)
}
- return connect.NewResponse(rsp), err
+
+ if isV1 {
+ if len(results) != 1 {
+ return nil, fmt.Errorf("invalid request")
+ }
+ kaoResults := *getMapValue(results)
+ if len(kaoResults) != 1 {
+ return nil, fmt.Errorf("invalid request")
+ }
+ kao := *getMapValue(kaoResults)
+
+ if kao.Error != nil {
+ return nil, kao.Error
+ }
+ resp.EntityWrappedKey = kao.Key //nolint:staticcheck // deprecated but keeping behavior for backwards compatibility
+ }
+
+ return connect.NewResponse(resp), err
}
-func (p *Provider) tdf3Rewrap(ctx context.Context, body *RequestBody, entity *entityInfo) (*kaspb.RewrapResponse, error) {
- if p.Tracer != nil {
- var span trace.Span
- ctx, span = p.Tracer.Start(ctx, "rewrap-tdf3")
- defer span.End()
+func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.UnsignedRewrapRequest_WithPolicyRequest) (*Policy, map[string]kaoResult, error) {
+ results := make(map[string]kaoResult)
+ anyValidKAOs := false
+ p.Logger.DebugContext(ctx, "extracting policy", "requestBody.policy", req.GetPolicy())
+ sDecPolicy, policyErr := base64.StdEncoding.DecodeString(req.GetPolicy().GetBody())
+ policy := &Policy{}
+ if policyErr == nil {
+ policyErr = json.Unmarshal(sDecPolicy, policy)
}
- var kidsToCheck []string
- if body.KeyAccess.KID != "" {
- kidsToCheck = []string{body.KeyAccess.KID}
- } else {
- p.Logger.InfoContext(ctx, "kid free kao")
- for _, k := range p.KASConfig.Keyring {
- if k.Algorithm == security.AlgorithmRSA2048 && k.Legacy {
- kidsToCheck = append(kidsToCheck, k.KID)
+ for _, kao := range req.GetKeyAccessObjects() {
+ if policyErr != nil {
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
+ }
+ var kidsToCheck []string
+ if kao.GetKeyAccessObject().GetKid() != "" {
+ kidsToCheck = []string{kao.GetKeyAccessObject().GetKid()}
+ } else {
+ p.Logger.InfoContext(ctx, "kid free kao")
+ for _, k := range p.KASConfig.Keyring {
+ if k.Algorithm == security.AlgorithmRSA2048 && k.Legacy {
+ kidsToCheck = append(kidsToCheck, k.KID)
+ }
+ }
+ if len(kidsToCheck) == 0 {
+ p.Logger.WarnContext(ctx, "failure to find legacy kids for rsa")
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
}
}
- if len(kidsToCheck) == 0 {
- p.Logger.WarnContext(ctx, "failure to find legacy kids for rsa")
- return nil, err400("bad request")
+
+ symKey, err := p.CryptoProvider.RSADecrypt(crypto.SHA1, kidsToCheck[0], "", kao.GetKeyAccessObject().GetWrappedKey())
+ for _, kid := range kidsToCheck[1:] {
+ p.Logger.WarnContext(ctx, "continue paging through legacy KIDs for kid free kao", "err", err)
+ if err == nil {
+ break
+ }
+ symKey, err = p.CryptoProvider.RSADecrypt(crypto.SHA1, kid, "", kao.GetKeyAccessObject().GetWrappedKey())
}
- }
- symmetricKey, err := p.CryptoProvider.RSADecrypt(crypto.SHA1, kidsToCheck[0], "", body.KeyAccess.WrappedKey)
- for _, kid := range kidsToCheck[1:] {
- p.Logger.WarnContext(ctx, "continue paging through legacy KIDs for kid free kao", "err", err)
- if err == nil {
- break
+ if err != nil {
+ p.Logger.WarnContext(ctx, "failure to decrypt dek", "err", err)
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
}
- symmetricKey, err = p.CryptoProvider.RSADecrypt(crypto.SHA1, kid, "", body.KeyAccess.WrappedKey)
- }
- if err != nil {
- p.Logger.WarnContext(ctx, "failure to decrypt dek", "err", err)
- return nil, err400("bad request")
- }
- p.Logger.DebugContext(ctx, "verifying policy binding", "requestBody.policy", body.Policy)
- policy, err := verifyAndParsePolicy(ctx, body, symmetricKey, *p.Logger)
- if err != nil {
- return nil, err
- }
+ err = verifyPolicyBinding(ctx, []byte(req.GetPolicy().GetBody()), kao, symKey, *p.Logger)
+ if err != nil {
+ failedKAORewrap(results, kao, err)
+ continue
+ }
+ results[kao.GetKeyAccessObjectId()] = kaoResult{
+ ID: kao.GetKeyAccessObjectId(),
+ Key: symKey,
+ }
- p.Logger.DebugContext(ctx, "extracting policy", "requestBody.policy", body.Policy)
- // changed use the entities in the token to get the decisions
- tok := &authorization.Token{
- Id: "rewrap-tok",
- Jwt: entity.Token,
+ anyValidKAOs = true
}
- access, err := p.canAccess(ctx, tok, *policy)
+ if policyErr != nil {
+ return nil, results, policyErr
+ }
- // Audit the TDF3 Rewrap
- kasPolicy := ConvertToAuditKasPolicy(*policy)
+ if !anyValidKAOs {
+ p.Logger.WarnContext(ctx, "no valid KAOs found")
+ return policy, results, fmt.Errorf("no valid KAOs")
+ }
- policyBinding, _ := extractPolicyBinding(body.KeyAccess.PolicyBinding)
+ return policy, results, nil
+}
- auditEventParams := audit.RewrapAuditEventParams{
- Policy: kasPolicy,
- IsSuccess: access,
- TDFFormat: "tdf3",
- Algorithm: body.Algorithm,
- PolicyBinding: policyBinding,
+func (p *Provider) tdf3Rewrap(ctx context.Context, requests []*kaspb.UnsignedRewrapRequest_WithPolicyRequest, clientPublicKey string, entity *entityInfo) policyKAOResults {
+ if p.Tracer != nil {
+ var span trace.Span
+ ctx, span = p.Tracer.Start(ctx, "rewrap-tdf3")
+ defer span.End()
}
- if err != nil {
- p.Logger.WarnContext(ctx, "Could not perform access decision!", "err", err)
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, err403("forbidden")
+ results := make(policyKAOResults)
+ var policies []*Policy
+ policyReqs := make(map[*Policy]*kaspb.UnsignedRewrapRequest_WithPolicyRequest)
+ for _, req := range requests {
+ policy, kaoResults, err := p.verifyRewrapRequests(ctx, req)
+ results[req.GetPolicy().GetId()] = kaoResults
+ if err != nil {
+ continue
+ }
+ policies = append(policies, policy)
+ policyReqs[policy] = req
}
- if !access {
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, err403("forbidden")
+ tok := &authorization.Token{
+ Id: "rewrap-token",
+ Jwt: entity.Token,
+ }
+ pdpAccessResults, accessErr := p.canAccess(ctx, tok, policies)
+ if accessErr != nil {
+ failAllKaos(requests, results, err403("could not perform access"))
+ return results
}
- asymEncrypt, err := ocrypto.NewAsymEncryption(body.ClientPublicKey)
+ asymEncrypt, err := ocrypto.NewAsymEncryption(clientPublicKey)
if err != nil {
p.Logger.WarnContext(ctx, "ocrypto.NewAsymEncryption:", "err", err)
}
- rewrappedKey, err := asymEncrypt.Encrypt(symmetricKey)
- if err != nil {
- p.Logger.WarnContext(ctx, "rewrap: ocrypto.AsymEncryption.encrypt failed", "err", err, "clientPublicKey", &body.ClientPublicKey)
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, err400("bad key for rewrap")
- }
+ for _, pdpAccess := range pdpAccessResults {
+ policy := pdpAccess.Policy
+ req, ok := policyReqs[policy]
+ kaoResults := results[req.GetPolicy().GetId()]
+ if !ok { // this should not happen
+ continue
+ }
+ access := pdpAccess.Access
- p.Logger.Audit.RewrapSuccess(ctx, auditEventParams)
- return &kaspb.RewrapResponse{
- EntityWrappedKey: rewrappedKey,
- SessionPublicKey: "",
- SchemaVersion: schemaVersion,
- }, nil
+ // Audit the TDF3 Rewrap
+ kasPolicy := ConvertToAuditKasPolicy(*policy)
+
+ for _, kao := range req.GetKeyAccessObjects() {
+ kaoRes := kaoResults[kao.GetKeyAccessObjectId()]
+ if kaoRes.Error != nil {
+ continue
+ }
+
+ policyBinding := kao.GetKeyAccessObject().GetPolicyBinding().GetHash()
+ auditEventParams := audit.RewrapAuditEventParams{
+ Policy: kasPolicy,
+ IsSuccess: access,
+ TDFFormat: "tdf3",
+ Algorithm: req.GetAlgorithm(),
+ PolicyBinding: policyBinding,
+ }
+
+ if !access {
+ p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
+ failedKAORewrap(kaoResults, kao, err403("forbidden"))
+ continue
+ }
+
+ rewrappedKey, err := asymEncrypt.Encrypt(kaoRes.Key)
+ if err != nil {
+ p.Logger.WarnContext(ctx, "rewrap: ocrypto.AsymEncryption.encrypt failed", "err", err, "clientPublicKey", clientPublicKey)
+ p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
+ failedKAORewrap(kaoResults, kao, err400("bad key for rewrap"))
+ continue
+ }
+ kaoResults[kao.GetKeyAccessObjectId()] = kaoResult{
+ ID: kao.GetKeyAccessObjectId(),
+ Key: rewrappedKey,
+ }
+
+ p.Logger.Audit.RewrapSuccess(ctx, auditEventParams)
+ }
+ }
+ return results
}
-func (p *Provider) nanoTDFRewrap(ctx context.Context, body *RequestBody, entity *entityInfo) (*kaspb.RewrapResponse, error) {
+func (p *Provider) nanoTDFRewrap(ctx context.Context, requests []*kaspb.UnsignedRewrapRequest_WithPolicyRequest, clientPublicKey string, entity *entityInfo) (string, policyKAOResults) {
+ results := make(policyKAOResults)
if p.Tracer != nil {
var span trace.Span
ctx, span = p.Tracer.Start(ctx, "rewrap-nanotdf")
defer span.End()
}
- headerReader := bytes.NewReader(body.KeyAccess.Header)
+ var policies []*Policy
+ policyReqs := make(map[*Policy]*kaspb.UnsignedRewrapRequest_WithPolicyRequest)
- header, _, err := sdk.NewNanoTDFHeaderFromReader(headerReader)
- if err != nil {
- return nil, fmt.Errorf("failed to parse NanoTDF header: %w", err)
- }
- // Lookup KID from nano header
- kid, err := header.GetKasURL().GetIdentifier()
- if err != nil {
- p.Logger.DebugContext(ctx, "nanoTDFRewrap GetIdentifier", "kid", kid, "err", err)
- // legacy nano with KID
- kid, err = p.lookupKid(ctx, security.AlgorithmECP256R1)
- if err != nil {
- p.Logger.ErrorContext(ctx, "failure to find default kid for ec", "err", err)
- return nil, err400("bad request")
+ for _, req := range requests {
+ policy, kaoResults := p.verifyNanoRewrapRequests(ctx, req)
+ results[req.GetPolicy().GetId()] = kaoResults
+ if policy != nil {
+ policies = append(policies, policy)
+ policyReqs[policy] = req
}
- p.Logger.DebugContext(ctx, "nanoTDFRewrap lookupKid", "kid", kid)
}
- p.Logger.DebugContext(ctx, "nanoTDFRewrap", "kid", kid)
- ecCurve, err := header.ECCurve()
- if err != nil {
- return nil, fmt.Errorf("ECCurve failed: %w", err)
+ // do the access check
+ tok := &authorization.Token{
+ Id: "rewrap-tok",
+ Jwt: entity.Token,
}
- symmetricKey, err := p.CryptoProvider.GenerateNanoTDFSymmetricKey(kid, header.EphemeralKey, ecCurve)
- if err != nil {
- return nil, fmt.Errorf("failed to generate symmetric key: %w", err)
+ pdpAccessResults, accessErr := p.canAccess(ctx, tok, policies)
+ if accessErr != nil {
+ failAllKaos(requests, results, err403("could not perform access"))
+ return "", results
}
- // extract the policy
- policy, err := extractNanoPolicy(symmetricKey, header)
+ privateKeyHandle, publicKeyHandle, err := p.CryptoProvider.GenerateEphemeralKasKeys()
if err != nil {
- return nil, fmt.Errorf("Error extracting policy: %w", err)
+ failAllKaos(requests, results, fmt.Errorf("failed to generate keypair: %w", err))
+ return "", results
}
-
- // check the policy binding
- verify, err := header.VerifyPolicyBinding()
+ sessionKey, err := p.CryptoProvider.GenerateNanoTDFSessionKey(privateKeyHandle, []byte(clientPublicKey))
if err != nil {
- return nil, fmt.Errorf("failed to verify policy binding: %w", err)
+ p.Logger.DebugContext(ctx, "GenerateNanoTDFSessionKey", "err", err)
+ failAllKaos(requests, results, fmt.Errorf("failed to generate session key: %w", err))
+ return "", results
}
- if !verify {
- return nil, fmt.Errorf("policy binding verification failed")
- }
+ for _, pdpAccess := range pdpAccessResults {
+ policy := pdpAccess.Policy
+ req, ok := policyReqs[policy]
+ if !ok { // this should not happen
+ continue
+ }
+ kaoResults := results[req.GetPolicy().GetId()]
+ access := pdpAccess.Access
- // do the access check
- tok := &authorization.Token{
- Id: "rewrap-tok",
- Jwt: entity.Token,
- }
+ // Audit the Nano Rewrap
+ kasPolicy := ConvertToAuditKasPolicy(*policy)
- access, err := p.canAccess(ctx, tok, *policy)
+ for _, kao := range req.GetKeyAccessObjects() {
+ kaoInfo := kaoResults[kao.GetKeyAccessObjectId()]
+ if kaoInfo.Error != nil {
+ continue
+ }
- // Audit the rewrap
- kasPolicy := ConvertToAuditKasPolicy(*policy)
- auditEventParams := audit.RewrapAuditEventParams{
- Policy: kasPolicy,
- TDFFormat: "nano",
- Algorithm: body.Algorithm,
- }
+ auditEventParams := audit.RewrapAuditEventParams{
+ Policy: kasPolicy,
+ IsSuccess: access,
+ TDFFormat: "Nano",
+ Algorithm: req.GetAlgorithm(),
+ }
- if err != nil {
- p.Logger.WarnContext(ctx, "Could not perform access decision!", "err", err)
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, err403("forbidden")
- }
+ if !access {
+ p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
+ failedKAORewrap(kaoResults, kao, err403("forbidden"))
+ continue
+ }
+ cipherText, err := wrapKeyAES(sessionKey, kaoInfo.Key)
+ if err != nil {
+ p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
+ failedKAORewrap(kaoResults, kao, err403("forbidden"))
+ continue
+ }
- if !access {
- p.Logger.WarnContext(ctx, "Access Denied; no reason given")
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, err403("forbidden")
- }
+ kaoResults[kao.GetKeyAccessObjectId()] = kaoResult{
+ ID: kao.GetKeyAccessObjectId(),
+ Key: cipherText,
+ }
- privateKeyHandle, publicKeyHandle, err := p.CryptoProvider.GenerateEphemeralKasKeys()
- if err != nil {
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, fmt.Errorf("failed to generate keypair: %w", err)
- }
- sessionKey, err := p.CryptoProvider.GenerateNanoTDFSessionKey(privateKeyHandle, []byte(body.ClientPublicKey))
- if err != nil {
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, fmt.Errorf("failed to generate session key: %w", err)
+ p.Logger.Audit.RewrapSuccess(ctx, auditEventParams)
+ }
}
+ return string(publicKeyHandle), results
+}
- cipherText, err := wrapKeyAES(sessionKey, symmetricKey)
- if err != nil {
- p.Logger.Audit.RewrapFailure(ctx, auditEventParams)
- return nil, fmt.Errorf("failed to encrypt key: %w", err)
- }
+func (p *Provider) verifyNanoRewrapRequests(ctx context.Context, req *kaspb.UnsignedRewrapRequest_WithPolicyRequest) (*Policy, map[string]kaoResult) {
+ results := make(map[string]kaoResult)
- p.Logger.Audit.RewrapSuccess(ctx, auditEventParams)
+ for _, kao := range req.GetKeyAccessObjects() {
+ // there should never be multiple KAOs in policy
+ if len(req.GetKeyAccessObjects()) != 1 {
+ failedKAORewrap(results, kao, err400("NanoTDFs should not have multiple KAOs per Policy"))
+ continue
+ }
- return &kaspb.RewrapResponse{
- EntityWrappedKey: cipherText,
- SessionPublicKey: string(publicKeyHandle),
- SchemaVersion: schemaVersion,
- }, nil
+ headerReader := bytes.NewReader(kao.GetKeyAccessObject().GetHeader())
+ header, _, err := sdk.NewNanoTDFHeaderFromReader(headerReader)
+ if err != nil {
+ failedKAORewrap(results, kao, fmt.Errorf("failed to parse NanoTDF header: %w", err))
+ return nil, results
+ }
+ // Lookup KID from nano header
+ kid, err := header.GetKasURL().GetIdentifier()
+ if err != nil {
+ p.Logger.DebugContext(ctx, "nanoTDFRewrap GetIdentifier", "kid", kid, "err", err)
+ // legacy nano with KID
+ kid, err = p.lookupKid(ctx, security.AlgorithmECP256R1)
+ if err != nil {
+ p.Logger.ErrorContext(ctx, "failure to find default kid for ec", "err", err)
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
+ }
+ p.Logger.DebugContext(ctx, "nanoTDFRewrap lookupKid", "kid", kid)
+ }
+ p.Logger.DebugContext(ctx, "nanoTDFRewrap", "kid", kid)
+ ecCurve, err := header.ECCurve()
+ if err != nil {
+ failedKAORewrap(results, kao, fmt.Errorf("ECCurve failed: %w", err))
+ return nil, results
+ }
+
+ symmetricKey, err := p.CryptoProvider.GenerateNanoTDFSymmetricKey(kid, header.EphemeralKey, ecCurve)
+ if err != nil {
+ failedKAORewrap(results, kao, fmt.Errorf("failed to generate symmetric key: %w", err))
+ return nil, results
+ }
+
+ // extract the policy
+ policy, err := extractNanoPolicy(symmetricKey, header)
+ if err != nil {
+ failedKAORewrap(results, kao, fmt.Errorf("Error extracting policy: %w", err))
+ return nil, results
+ }
+
+ // check the policy binding
+ verify, err := header.VerifyPolicyBinding()
+ if err != nil {
+ failedKAORewrap(results, kao, fmt.Errorf("failed to verify policy binding: %w", err))
+ return nil, results
+ }
+
+ if !verify {
+ failedKAORewrap(results, kao, fmt.Errorf("policy binding verification failed"))
+ return nil, results
+ }
+ results[kao.GetKeyAccessObjectId()] = kaoResult{
+ ID: kao.GetKeyAccessObjectId(),
+ Key: symmetricKey,
+ }
+ return policy, results
+ }
+ return nil, results
}
func extractNanoPolicy(symmetricKey []byte, header sdk.NanoTDFHeader) (*Policy, error) {
@@ -545,3 +767,11 @@ func wrapKeyAES(sessionKey, dek []byte) ([]byte, error) {
return cipherText, nil
}
+
+func failAllKaos(reqs []*kaspb.UnsignedRewrapRequest_WithPolicyRequest, results policyKAOResults, err error) {
+ for _, req := range reqs {
+ for _, kao := range req.GetKeyAccessObjects() {
+ failedKAORewrap(results[req.GetPolicy().GetId()], kao, err)
+ }
+ }
+}
diff --git a/service/kas/access/rewrap_test.go b/service/kas/access/rewrap_test.go
index a9eff6e97..14ad8b620 100644
--- a/service/kas/access/rewrap_test.go
+++ b/service/kas/access/rewrap_test.go
@@ -12,6 +12,8 @@ import (
"net/http"
"testing"
+ "google.golang.org/protobuf/encoding/protojson"
+
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jws"
@@ -199,7 +201,7 @@ type PolicyBinding struct {
Hash string `json:"hash"`
}
-func keyAccessWrappedRaw(t *testing.T, policyBindingAsString bool) KeyAccess {
+func keyAccessWrappedRaw(t *testing.T, policyBindingAsString bool) kaspb.UnsignedRewrapRequest_WithKeyAccessObject {
policyBytes := fauxPolicyBytes(t)
asym, err := ocrypto.NewAsymEncryption(rsaPublicAlt)
require.NoError(t, err, "rewrap: NewAsymEncryption failed")
@@ -213,23 +215,29 @@ func keyAccessWrappedRaw(t *testing.T, policyBindingAsString bool) KeyAccess {
dst := make([]byte, hex.EncodedLen(len(bindingBytes)))
hex.Encode(dst, bindingBytes)
- var policyBinding interface{}
+ var policyBinding *kaspb.PolicyBinding
if policyBindingAsString {
- policyBinding = base64.StdEncoding.EncodeToString(dst)
- } else {
- policyBinding = PolicyBinding{
- Alg: "HS256",
+ policyBinding = &kaspb.PolicyBinding{
Hash: base64.StdEncoding.EncodeToString(dst),
}
+ } else {
+ policyBinding = &kaspb.PolicyBinding{
+ Algorithm: "HS256",
+ Hash: base64.StdEncoding.EncodeToString(dst),
+ }
}
+ require.NoError(t, err)
- return KeyAccess{
- Type: "wrapped",
- URL: "http://127.0.0.1:4000",
- Protocol: "kas",
- WrappedKey: []byte(base64.StdEncoding.EncodeToString(wrappedKey)),
- PolicyBinding: policyBinding,
+ return kaspb.UnsignedRewrapRequest_WithKeyAccessObject{
+ KeyAccessObjectId: "123",
+ KeyAccessObject: &kaspb.KeyAccess{
+ KeyType: "wrapped",
+ KasUrl: "http://127.0.0.1:4000",
+ Protocol: "kas",
+ WrappedKey: []byte(base64.StdEncoding.EncodeToString(wrappedKey)),
+ PolicyBinding: policyBinding,
+ },
}
}
@@ -276,13 +284,25 @@ func jwtWrongKey(t *testing.T) []byte {
return signedMockJWT(t, entityPrivateKey(t))
}
+func makeRewrapRequests(t *testing.T, policy []byte, bindingAsString bool) []*kaspb.UnsignedRewrapRequest_WithPolicyRequest {
+ kaoReq := keyAccessWrappedRaw(t, bindingAsString)
+ return []*kaspb.UnsignedRewrapRequest_WithPolicyRequest{
+ {
+ KeyAccessObjects: []*kaspb.UnsignedRewrapRequest_WithKeyAccessObject{&kaoReq},
+ Policy: &kaspb.UnsignedRewrapRequest_WithPolicy{
+ Id: "123",
+ Body: string(policy),
+ },
+ },
+ }
+}
+
func makeRewrapBody(t *testing.T, policy []byte, policyBindingAsString bool) []byte {
- mockBody := RequestBody{
- KeyAccess: keyAccessWrappedRaw(t, policyBindingAsString),
- Policy: string(policy),
+ mockBody := &kaspb.UnsignedRewrapRequest{
+ Requests: makeRewrapRequests(t, policy, policyBindingAsString),
ClientPublicKey: rsaPublicAlt,
}
- bodyData, err := json.Marshal(mockBody)
+ bodyData, err := protojson.Marshal(mockBody)
require.NoError(t, err)
tok := jwt.New()
@@ -336,7 +356,7 @@ func TestParseAndVerifyRequest(t *testing.T) {
logger := logger.CreateTestLogger()
- verified, err := extractSRTBody(
+ verified, _, err := extractSRTBody(
ctx,
http.Header{},
&kaspb.RewrapRequest{
@@ -347,14 +367,15 @@ func TestParseAndVerifyRequest(t *testing.T) {
if tt.goodDPoP {
require.NoError(t, err, "failed to parse srt=[%s], tok=[%s]", tt.body, bearer)
require.NotNil(t, verified, "unable to load request body")
- require.NotNil(t, verified.ClientPublicKey, "unable to load public key")
-
- policy, err := verifyAndParsePolicy(context.Background(), verified, []byte(plainKey), *logger)
- if !tt.shouldError {
- require.NoError(t, err, "failed to verify policy body=[%v]", tt.body)
- assert.Len(t, policy.Body.DataAttributes, 2, "incorrect policy body=[%v]", policy.Body)
- } else {
- require.Error(t, err, "failed to fail policy body=[%v]", tt.body)
+ require.NotNil(t, verified.GetClientPublicKey(), "unable to load public key")
+
+ for _, req := range verified.GetRequests() {
+ err := verifyPolicyBinding(context.Background(), []byte(req.GetPolicy().GetBody()), req.GetKeyAccessObjects()[0], []byte(plainKey), *logger)
+ if !tt.shouldError {
+ require.NoError(t, err, "failed to verify policy body=[%v]", tt.body)
+ } else {
+ require.Error(t, err, "failed to fail policy body=[%v]", tt.body)
+ }
}
} else {
require.Error(t, err, "failed to fail srt=[%s], tok=[%s]", tt.body, bearer)
@@ -375,7 +396,7 @@ func Test_SignedRequestBody_When_Bad_Signature_Expect_Failure(t *testing.T) {
md := metadata.New(map[string]string{"token": string(jwtWrongKey(t))})
ctx = metadata.NewIncomingContext(ctx, md)
- verified, err := extractSRTBody(
+ verified, _, err := extractSRTBody(
ctx,
http.Header{},
&kaspb.RewrapRequest{
diff --git a/service/kas/kas.proto b/service/kas/kas.proto
index 8f0528d05..312540360 100644
--- a/service/kas/kas.proto
+++ b/service/kas/kas.proto
@@ -31,6 +31,43 @@ message LegacyPublicKeyRequest {
string algorithm = 1;
}
+message PolicyBinding {
+ string algorithm = 1 [json_name = "alg"];
+ string hash = 2;
+}
+
+message KeyAccess {
+ string encrypted_metadata = 1;
+ PolicyBinding policy_binding = 2;
+ string protocol = 3;
+ string key_type = 4 [json_name = "type"];
+ string kas_url = 5 [json_name = "url"];
+ string kid = 6;
+ string split_id = 7 [json_name = "sid"];
+ bytes wrapped_key = 8;
+ // header is only used for NanoTDFs
+ bytes header = 9;
+}
+
+message UnsignedRewrapRequest {
+ message WithPolicy {
+ string id = 1;
+ string body = 2;
+ }
+ message WithKeyAccessObject {
+ string key_access_object_id = 1;
+ KeyAccess key_access_object = 2;
+ }
+
+ message WithPolicyRequest {
+ repeated WithKeyAccessObject key_access_objects = 1;
+ WithPolicy policy = 2;
+ string algorithm = 3;
+ }
+
+ string client_public_key = 1;
+ repeated WithPolicyRequest requests = 2;
+}
message PublicKeyRequest {
string algorithm = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {description: "algorithm type rsa: or ec:"}];
string fmt = 2 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {description: "response format"}];
@@ -48,11 +85,29 @@ message RewrapRequest {
string signed_request_token = 1;
}
-message RewrapResponse {
+
+message KeyAccessRewrapResult {
map metadata = 1;
- bytes entity_wrapped_key = 2;
+ string key_access_object_id = 2;
+ string status = 3;
+ oneof result {
+ bytes kas_wrapped_key = 4;
+ string error = 5;
+ }
+}
+
+message PolicyRewrapResult {
+ string policy_id = 1;
+ repeated KeyAccessRewrapResult results = 2;
+}
+
+message RewrapResponse {
+ map metadata = 1 [deprecated = true];
+ bytes entity_wrapped_key = 2 [deprecated = true];
string session_public_key = 3;
- string schema_version = 4;
+ string schema_version = 4 [deprecated = true];
+ // New Rewrap API changes
+ repeated PolicyRewrapResult responses = 5;
}
// Get app info from the root path
diff --git a/service/rttests/rt_test.go b/service/rttests/rt_test.go
index 49a43737b..f911fcfc4 100644
--- a/service/rttests/rt_test.go
+++ b/service/rttests/rt_test.go
@@ -123,11 +123,13 @@ func (s *RoundtripSuite) SetupSuite() {
}
func (s *RoundtripSuite) Tests() {
+ var passNames []string
// success tests
for i, attributes := range successAttributeSets {
n := fmt.Sprintf("success roundtrip %d", i)
s.Run(n, func() {
filename := fmt.Sprintf("test-success-%d.tdf", i)
+ passNames = append(passNames, filename)
plaintext := "Running a roundtrip test!"
err := encrypt(s.client, s.TestConfig, plaintext, attributes, filename)
s.Require().NoError(err)
@@ -136,11 +138,13 @@ func (s *RoundtripSuite) Tests() {
})
}
+ var failNames []string
// failure tests
for i, attributes := range failureAttributeSets {
n := fmt.Sprintf("failure roundtrip %d", i)
s.Run(n, func() {
filename := fmt.Sprintf("test-failure-%d.tdf", i)
+ failNames = append(failNames, filename)
plaintext := "Running a roundtrip test!"
err := encrypt(s.client, s.TestConfig, plaintext, attributes, filename)
s.Require().NoError(err)
@@ -148,6 +152,11 @@ func (s *RoundtripSuite) Tests() {
s.ErrorContains(err, "PermissionDenied")
})
}
+
+ // bulk tests
+ s.Run("bulk test", func() {
+ s.Require().NoError(bulk(s.client, passNames, failNames, "Running a roundtrip test!"))
+ })
}
func (s *RoundtripSuite) CreateTestData() error {
@@ -372,3 +381,53 @@ func decrypt(client *sdk.SDK, tdfFile string, plaintext string) error {
return nil
}
+
+func bulk(client *sdk.SDK, tdfSuccess []string, tdfFail []string, plaintext string) error {
+ var passTDF []*sdk.BulkTDF
+ for _, fileName := range tdfSuccess {
+ file, err := os.Open(fileName)
+ if err != nil {
+ return err
+ }
+
+ defer file.Close()
+
+ buf := new(strings.Builder)
+ passTDF = append(passTDF, &sdk.BulkTDF{Writer: buf, Reader: file})
+ }
+
+ var failTDF []*sdk.BulkTDF
+ for _, fileName := range tdfFail {
+ file, err := os.Open(fileName)
+ if err != nil {
+ return err
+ }
+
+ defer file.Close()
+
+ buf := new(strings.Builder)
+ failTDF = append(failTDF, &sdk.BulkTDF{Writer: buf, Reader: file})
+ }
+
+ _ = client.BulkDecrypt(context.Background(), sdk.WithTDFs(passTDF...), sdk.WithTDFs(failTDF...), sdk.WithTDFType(sdk.Standard))
+ for _, tdf := range passTDF {
+ builder, ok := tdf.Writer.(*strings.Builder)
+ if !ok {
+ return fmt.Errorf("bad writer")
+ }
+
+ if tdf.Error != nil {
+ return tdf.Error
+ }
+ if builder.String() != plaintext {
+ return fmt.Errorf("bulk did not equal plaintext")
+ }
+ }
+ for _, tdf := range failTDF {
+ if tdf.Error == nil {
+ return fmt.Errorf("no expected err")
+ }
+ }
+
+ return nil
+}