Implement transit encryption engine with versioned key management
Add complete transit engine supporting symmetric encryption (AES-256-GCM, XChaCha20-Poly1305), asymmetric signing (Ed25519, ECDSA P-256/P-384), and HMAC (SHA-256/SHA-512) with versioned key rotation, min decryption version enforcement, key trimming, batch operations, and rewrap. Includes proto definitions, gRPC handlers, REST routes, and comprehensive tests covering all 18 operations, auth enforcement, and edge cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
|||||||
"git.wntrmute.dev/kyle/metacrypt/internal/db"
|
"git.wntrmute.dev/kyle/metacrypt/internal/db"
|
||||||
"git.wntrmute.dev/kyle/metacrypt/internal/engine"
|
"git.wntrmute.dev/kyle/metacrypt/internal/engine"
|
||||||
"git.wntrmute.dev/kyle/metacrypt/internal/engine/ca"
|
"git.wntrmute.dev/kyle/metacrypt/internal/engine/ca"
|
||||||
|
"git.wntrmute.dev/kyle/metacrypt/internal/engine/transit"
|
||||||
"git.wntrmute.dev/kyle/metacrypt/internal/grpcserver"
|
"git.wntrmute.dev/kyle/metacrypt/internal/grpcserver"
|
||||||
"git.wntrmute.dev/kyle/metacrypt/internal/policy"
|
"git.wntrmute.dev/kyle/metacrypt/internal/policy"
|
||||||
"git.wntrmute.dev/kyle/metacrypt/internal/seal"
|
"git.wntrmute.dev/kyle/metacrypt/internal/seal"
|
||||||
@@ -74,6 +75,7 @@ func runServer(cmd *cobra.Command, args []string) error {
|
|||||||
policyEngine := policy.NewEngine(b)
|
policyEngine := policy.NewEngine(b)
|
||||||
engineRegistry := engine.NewRegistry(b, logger)
|
engineRegistry := engine.NewRegistry(b, logger)
|
||||||
engineRegistry.RegisterFactory(engine.EngineTypeCA, ca.NewCAEngine)
|
engineRegistry.RegisterFactory(engine.EngineTypeCA, ca.NewCAEngine)
|
||||||
|
engineRegistry.RegisterFactory(engine.EngineTypeTransit, transit.NewTransitEngine)
|
||||||
|
|
||||||
srv := server.New(cfg, sealMgr, authenticator, policyEngine, engineRegistry, logger, version)
|
srv := server.New(cfg, sealMgr, authenticator, policyEngine, engineRegistry, logger, version)
|
||||||
grpcSrv := grpcserver.New(cfg, sealMgr, authenticator, policyEngine, engineRegistry, logger)
|
grpcSrv := grpcserver.New(cfg, sealMgr, authenticator, policyEngine, engineRegistry, logger)
|
||||||
|
|||||||
2197
gen/metacrypt/v2/transit.pb.go
Normal file
2197
gen/metacrypt/v2/transit.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
777
gen/metacrypt/v2/transit_grpc.pb.go
Normal file
777
gen/metacrypt/v2/transit_grpc.pb.go
Normal file
@@ -0,0 +1,777 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
|
// - protoc v3.20.3
|
||||||
|
// source: proto/metacrypt/v2/transit.proto
|
||||||
|
|
||||||
|
package metacryptv2
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
TransitService_CreateKey_FullMethodName = "/metacrypt.v2.TransitService/CreateKey"
|
||||||
|
TransitService_DeleteKey_FullMethodName = "/metacrypt.v2.TransitService/DeleteKey"
|
||||||
|
TransitService_GetKey_FullMethodName = "/metacrypt.v2.TransitService/GetKey"
|
||||||
|
TransitService_ListKeys_FullMethodName = "/metacrypt.v2.TransitService/ListKeys"
|
||||||
|
TransitService_RotateKey_FullMethodName = "/metacrypt.v2.TransitService/RotateKey"
|
||||||
|
TransitService_UpdateKeyConfig_FullMethodName = "/metacrypt.v2.TransitService/UpdateKeyConfig"
|
||||||
|
TransitService_TrimKey_FullMethodName = "/metacrypt.v2.TransitService/TrimKey"
|
||||||
|
TransitService_Encrypt_FullMethodName = "/metacrypt.v2.TransitService/Encrypt"
|
||||||
|
TransitService_Decrypt_FullMethodName = "/metacrypt.v2.TransitService/Decrypt"
|
||||||
|
TransitService_Rewrap_FullMethodName = "/metacrypt.v2.TransitService/Rewrap"
|
||||||
|
TransitService_BatchEncrypt_FullMethodName = "/metacrypt.v2.TransitService/BatchEncrypt"
|
||||||
|
TransitService_BatchDecrypt_FullMethodName = "/metacrypt.v2.TransitService/BatchDecrypt"
|
||||||
|
TransitService_BatchRewrap_FullMethodName = "/metacrypt.v2.TransitService/BatchRewrap"
|
||||||
|
TransitService_Sign_FullMethodName = "/metacrypt.v2.TransitService/Sign"
|
||||||
|
TransitService_Verify_FullMethodName = "/metacrypt.v2.TransitService/Verify"
|
||||||
|
TransitService_Hmac_FullMethodName = "/metacrypt.v2.TransitService/Hmac"
|
||||||
|
TransitService_GetPublicKey_FullMethodName = "/metacrypt.v2.TransitService/GetPublicKey"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TransitServiceClient is the client API for TransitService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// TransitService provides typed, authenticated access to transit engine
|
||||||
|
// operations: symmetric encryption, signing, HMAC, and versioned key
|
||||||
|
// management. All RPCs require the service to be unsealed.
|
||||||
|
type TransitServiceClient interface {
|
||||||
|
// CreateKey creates a new named encryption key. Admin only.
|
||||||
|
CreateKey(ctx context.Context, in *CreateTransitKeyRequest, opts ...grpc.CallOption) (*CreateTransitKeyResponse, error)
|
||||||
|
// DeleteKey permanently removes a named key. Admin only.
|
||||||
|
// Only succeeds if allow_deletion is true on the key config.
|
||||||
|
DeleteKey(ctx context.Context, in *DeleteTransitKeyRequest, opts ...grpc.CallOption) (*DeleteTransitKeyResponse, error)
|
||||||
|
// GetKey returns metadata for a named key (no raw material). Auth required.
|
||||||
|
GetKey(ctx context.Context, in *GetTransitKeyRequest, opts ...grpc.CallOption) (*GetTransitKeyResponse, error)
|
||||||
|
// ListKeys returns the names of all configured keys. Auth required.
|
||||||
|
ListKeys(ctx context.Context, in *ListTransitKeysRequest, opts ...grpc.CallOption) (*ListTransitKeysResponse, error)
|
||||||
|
// RotateKey creates a new version of the named key. Admin only.
|
||||||
|
RotateKey(ctx context.Context, in *RotateTransitKeyRequest, opts ...grpc.CallOption) (*RotateTransitKeyResponse, error)
|
||||||
|
// UpdateKeyConfig updates key configuration (e.g. min_decryption_version).
|
||||||
|
// Admin only.
|
||||||
|
UpdateKeyConfig(ctx context.Context, in *UpdateTransitKeyConfigRequest, opts ...grpc.CallOption) (*UpdateTransitKeyConfigResponse, error)
|
||||||
|
// TrimKey deletes versions below min_decryption_version. Admin only.
|
||||||
|
TrimKey(ctx context.Context, in *TrimTransitKeyRequest, opts ...grpc.CallOption) (*TrimTransitKeyResponse, error)
|
||||||
|
// Encrypt encrypts plaintext with the latest key version. Auth required.
|
||||||
|
Encrypt(ctx context.Context, in *TransitEncryptRequest, opts ...grpc.CallOption) (*TransitEncryptResponse, error)
|
||||||
|
// Decrypt decrypts ciphertext. Auth required.
|
||||||
|
Decrypt(ctx context.Context, in *TransitDecryptRequest, opts ...grpc.CallOption) (*TransitDecryptResponse, error)
|
||||||
|
// Rewrap re-encrypts ciphertext with the latest key version without
|
||||||
|
// exposing plaintext. Auth required.
|
||||||
|
Rewrap(ctx context.Context, in *TransitRewrapRequest, opts ...grpc.CallOption) (*TransitRewrapResponse, error)
|
||||||
|
// BatchEncrypt encrypts multiple items in a single request. Auth required.
|
||||||
|
BatchEncrypt(ctx context.Context, in *TransitBatchEncryptRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error)
|
||||||
|
// BatchDecrypt decrypts multiple items in a single request. Auth required.
|
||||||
|
BatchDecrypt(ctx context.Context, in *TransitBatchDecryptRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error)
|
||||||
|
// BatchRewrap re-encrypts multiple items in a single request. Auth required.
|
||||||
|
BatchRewrap(ctx context.Context, in *TransitBatchRewrapRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error)
|
||||||
|
// Sign signs input data with an asymmetric key. Auth required.
|
||||||
|
Sign(ctx context.Context, in *TransitSignRequest, opts ...grpc.CallOption) (*TransitSignResponse, error)
|
||||||
|
// Verify verifies a signature against input data. Auth required.
|
||||||
|
Verify(ctx context.Context, in *TransitVerifyRequest, opts ...grpc.CallOption) (*TransitVerifyResponse, error)
|
||||||
|
// Hmac computes or verifies an HMAC. Auth required.
|
||||||
|
Hmac(ctx context.Context, in *TransitHmacRequest, opts ...grpc.CallOption) (*TransitHmacResponse, error)
|
||||||
|
// GetPublicKey returns the public key for an asymmetric key. Auth required.
|
||||||
|
GetPublicKey(ctx context.Context, in *GetTransitPublicKeyRequest, opts ...grpc.CallOption) (*GetTransitPublicKeyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type transitServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransitServiceClient(cc grpc.ClientConnInterface) TransitServiceClient {
|
||||||
|
return &transitServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) CreateKey(ctx context.Context, in *CreateTransitKeyRequest, opts ...grpc.CallOption) (*CreateTransitKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(CreateTransitKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_CreateKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) DeleteKey(ctx context.Context, in *DeleteTransitKeyRequest, opts ...grpc.CallOption) (*DeleteTransitKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(DeleteTransitKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_DeleteKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) GetKey(ctx context.Context, in *GetTransitKeyRequest, opts ...grpc.CallOption) (*GetTransitKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(GetTransitKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_GetKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) ListKeys(ctx context.Context, in *ListTransitKeysRequest, opts ...grpc.CallOption) (*ListTransitKeysResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(ListTransitKeysResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_ListKeys_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) RotateKey(ctx context.Context, in *RotateTransitKeyRequest, opts ...grpc.CallOption) (*RotateTransitKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(RotateTransitKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_RotateKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) UpdateKeyConfig(ctx context.Context, in *UpdateTransitKeyConfigRequest, opts ...grpc.CallOption) (*UpdateTransitKeyConfigResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(UpdateTransitKeyConfigResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_UpdateKeyConfig_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) TrimKey(ctx context.Context, in *TrimTransitKeyRequest, opts ...grpc.CallOption) (*TrimTransitKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TrimTransitKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_TrimKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Encrypt(ctx context.Context, in *TransitEncryptRequest, opts ...grpc.CallOption) (*TransitEncryptResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitEncryptResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Encrypt_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Decrypt(ctx context.Context, in *TransitDecryptRequest, opts ...grpc.CallOption) (*TransitDecryptResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitDecryptResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Decrypt_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Rewrap(ctx context.Context, in *TransitRewrapRequest, opts ...grpc.CallOption) (*TransitRewrapResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitRewrapResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Rewrap_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) BatchEncrypt(ctx context.Context, in *TransitBatchEncryptRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitBatchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_BatchEncrypt_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) BatchDecrypt(ctx context.Context, in *TransitBatchDecryptRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitBatchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_BatchDecrypt_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) BatchRewrap(ctx context.Context, in *TransitBatchRewrapRequest, opts ...grpc.CallOption) (*TransitBatchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitBatchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_BatchRewrap_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Sign(ctx context.Context, in *TransitSignRequest, opts ...grpc.CallOption) (*TransitSignResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitSignResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Sign_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Verify(ctx context.Context, in *TransitVerifyRequest, opts ...grpc.CallOption) (*TransitVerifyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitVerifyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Verify_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) Hmac(ctx context.Context, in *TransitHmacRequest, opts ...grpc.CallOption) (*TransitHmacResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(TransitHmacResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_Hmac_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *transitServiceClient) GetPublicKey(ctx context.Context, in *GetTransitPublicKeyRequest, opts ...grpc.CallOption) (*GetTransitPublicKeyResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(GetTransitPublicKeyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, TransitService_GetPublicKey_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransitServiceServer is the server API for TransitService service.
|
||||||
|
// All implementations must embed UnimplementedTransitServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
//
|
||||||
|
// TransitService provides typed, authenticated access to transit engine
|
||||||
|
// operations: symmetric encryption, signing, HMAC, and versioned key
|
||||||
|
// management. All RPCs require the service to be unsealed.
|
||||||
|
type TransitServiceServer interface {
|
||||||
|
// CreateKey creates a new named encryption key. Admin only.
|
||||||
|
CreateKey(context.Context, *CreateTransitKeyRequest) (*CreateTransitKeyResponse, error)
|
||||||
|
// DeleteKey permanently removes a named key. Admin only.
|
||||||
|
// Only succeeds if allow_deletion is true on the key config.
|
||||||
|
DeleteKey(context.Context, *DeleteTransitKeyRequest) (*DeleteTransitKeyResponse, error)
|
||||||
|
// GetKey returns metadata for a named key (no raw material). Auth required.
|
||||||
|
GetKey(context.Context, *GetTransitKeyRequest) (*GetTransitKeyResponse, error)
|
||||||
|
// ListKeys returns the names of all configured keys. Auth required.
|
||||||
|
ListKeys(context.Context, *ListTransitKeysRequest) (*ListTransitKeysResponse, error)
|
||||||
|
// RotateKey creates a new version of the named key. Admin only.
|
||||||
|
RotateKey(context.Context, *RotateTransitKeyRequest) (*RotateTransitKeyResponse, error)
|
||||||
|
// UpdateKeyConfig updates key configuration (e.g. min_decryption_version).
|
||||||
|
// Admin only.
|
||||||
|
UpdateKeyConfig(context.Context, *UpdateTransitKeyConfigRequest) (*UpdateTransitKeyConfigResponse, error)
|
||||||
|
// TrimKey deletes versions below min_decryption_version. Admin only.
|
||||||
|
TrimKey(context.Context, *TrimTransitKeyRequest) (*TrimTransitKeyResponse, error)
|
||||||
|
// Encrypt encrypts plaintext with the latest key version. Auth required.
|
||||||
|
Encrypt(context.Context, *TransitEncryptRequest) (*TransitEncryptResponse, error)
|
||||||
|
// Decrypt decrypts ciphertext. Auth required.
|
||||||
|
Decrypt(context.Context, *TransitDecryptRequest) (*TransitDecryptResponse, error)
|
||||||
|
// Rewrap re-encrypts ciphertext with the latest key version without
|
||||||
|
// exposing plaintext. Auth required.
|
||||||
|
Rewrap(context.Context, *TransitRewrapRequest) (*TransitRewrapResponse, error)
|
||||||
|
// BatchEncrypt encrypts multiple items in a single request. Auth required.
|
||||||
|
BatchEncrypt(context.Context, *TransitBatchEncryptRequest) (*TransitBatchResponse, error)
|
||||||
|
// BatchDecrypt decrypts multiple items in a single request. Auth required.
|
||||||
|
BatchDecrypt(context.Context, *TransitBatchDecryptRequest) (*TransitBatchResponse, error)
|
||||||
|
// BatchRewrap re-encrypts multiple items in a single request. Auth required.
|
||||||
|
BatchRewrap(context.Context, *TransitBatchRewrapRequest) (*TransitBatchResponse, error)
|
||||||
|
// Sign signs input data with an asymmetric key. Auth required.
|
||||||
|
Sign(context.Context, *TransitSignRequest) (*TransitSignResponse, error)
|
||||||
|
// Verify verifies a signature against input data. Auth required.
|
||||||
|
Verify(context.Context, *TransitVerifyRequest) (*TransitVerifyResponse, error)
|
||||||
|
// Hmac computes or verifies an HMAC. Auth required.
|
||||||
|
Hmac(context.Context, *TransitHmacRequest) (*TransitHmacResponse, error)
|
||||||
|
// GetPublicKey returns the public key for an asymmetric key. Auth required.
|
||||||
|
GetPublicKey(context.Context, *GetTransitPublicKeyRequest) (*GetTransitPublicKeyResponse, error)
|
||||||
|
mustEmbedUnimplementedTransitServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedTransitServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedTransitServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedTransitServiceServer) CreateKey(context.Context, *CreateTransitKeyRequest) (*CreateTransitKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method CreateKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) DeleteKey(context.Context, *DeleteTransitKeyRequest) (*DeleteTransitKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method DeleteKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) GetKey(context.Context, *GetTransitKeyRequest) (*GetTransitKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method GetKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) ListKeys(context.Context, *ListTransitKeysRequest) (*ListTransitKeysResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method ListKeys not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) RotateKey(context.Context, *RotateTransitKeyRequest) (*RotateTransitKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method RotateKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) UpdateKeyConfig(context.Context, *UpdateTransitKeyConfigRequest) (*UpdateTransitKeyConfigResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method UpdateKeyConfig not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) TrimKey(context.Context, *TrimTransitKeyRequest) (*TrimTransitKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method TrimKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Encrypt(context.Context, *TransitEncryptRequest) (*TransitEncryptResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Encrypt not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Decrypt(context.Context, *TransitDecryptRequest) (*TransitDecryptResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Decrypt not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Rewrap(context.Context, *TransitRewrapRequest) (*TransitRewrapResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Rewrap not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) BatchEncrypt(context.Context, *TransitBatchEncryptRequest) (*TransitBatchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method BatchEncrypt not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) BatchDecrypt(context.Context, *TransitBatchDecryptRequest) (*TransitBatchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method BatchDecrypt not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) BatchRewrap(context.Context, *TransitBatchRewrapRequest) (*TransitBatchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method BatchRewrap not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Sign(context.Context, *TransitSignRequest) (*TransitSignResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Sign not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Verify(context.Context, *TransitVerifyRequest) (*TransitVerifyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Verify not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) Hmac(context.Context, *TransitHmacRequest) (*TransitHmacResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Hmac not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) GetPublicKey(context.Context, *GetTransitPublicKeyRequest) (*GetTransitPublicKeyResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method GetPublicKey not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedTransitServiceServer) mustEmbedUnimplementedTransitServiceServer() {}
|
||||||
|
func (UnimplementedTransitServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeTransitServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to TransitServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeTransitServiceServer interface {
|
||||||
|
mustEmbedUnimplementedTransitServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterTransitServiceServer(s grpc.ServiceRegistrar, srv TransitServiceServer) {
|
||||||
|
// If the following call panics, it indicates UnimplementedTransitServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&TransitService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_CreateKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CreateTransitKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).CreateKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_CreateKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).CreateKey(ctx, req.(*CreateTransitKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_DeleteKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(DeleteTransitKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).DeleteKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_DeleteKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).DeleteKey(ctx, req.(*DeleteTransitKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_GetKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetTransitKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).GetKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_GetKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).GetKey(ctx, req.(*GetTransitKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_ListKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListTransitKeysRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).ListKeys(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_ListKeys_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).ListKeys(ctx, req.(*ListTransitKeysRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_RotateKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(RotateTransitKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).RotateKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_RotateKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).RotateKey(ctx, req.(*RotateTransitKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_UpdateKeyConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(UpdateTransitKeyConfigRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).UpdateKeyConfig(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_UpdateKeyConfig_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).UpdateKeyConfig(ctx, req.(*UpdateTransitKeyConfigRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_TrimKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TrimTransitKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).TrimKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_TrimKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).TrimKey(ctx, req.(*TrimTransitKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Encrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitEncryptRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Encrypt(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Encrypt_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Encrypt(ctx, req.(*TransitEncryptRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Decrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitDecryptRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Decrypt(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Decrypt_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Decrypt(ctx, req.(*TransitDecryptRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Rewrap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitRewrapRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Rewrap(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Rewrap_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Rewrap(ctx, req.(*TransitRewrapRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_BatchEncrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitBatchEncryptRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).BatchEncrypt(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_BatchEncrypt_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).BatchEncrypt(ctx, req.(*TransitBatchEncryptRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_BatchDecrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitBatchDecryptRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).BatchDecrypt(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_BatchDecrypt_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).BatchDecrypt(ctx, req.(*TransitBatchDecryptRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_BatchRewrap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitBatchRewrapRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).BatchRewrap(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_BatchRewrap_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).BatchRewrap(ctx, req.(*TransitBatchRewrapRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Sign_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitSignRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Sign(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Sign_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Sign(ctx, req.(*TransitSignRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Verify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitVerifyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Verify(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Verify_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Verify(ctx, req.(*TransitVerifyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_Hmac_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TransitHmacRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).Hmac(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_Hmac_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).Hmac(ctx, req.(*TransitHmacRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TransitService_GetPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetTransitPublicKeyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TransitServiceServer).GetPublicKey(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: TransitService_GetPublicKey_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TransitServiceServer).GetPublicKey(ctx, req.(*GetTransitPublicKeyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransitService_ServiceDesc is the grpc.ServiceDesc for TransitService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var TransitService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "metacrypt.v2.TransitService",
|
||||||
|
HandlerType: (*TransitServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "CreateKey",
|
||||||
|
Handler: _TransitService_CreateKey_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeleteKey",
|
||||||
|
Handler: _TransitService_DeleteKey_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetKey",
|
||||||
|
Handler: _TransitService_GetKey_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "ListKeys",
|
||||||
|
Handler: _TransitService_ListKeys_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "RotateKey",
|
||||||
|
Handler: _TransitService_RotateKey_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "UpdateKeyConfig",
|
||||||
|
Handler: _TransitService_UpdateKeyConfig_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "TrimKey",
|
||||||
|
Handler: _TransitService_TrimKey_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Encrypt",
|
||||||
|
Handler: _TransitService_Encrypt_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Decrypt",
|
||||||
|
Handler: _TransitService_Decrypt_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Rewrap",
|
||||||
|
Handler: _TransitService_Rewrap_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "BatchEncrypt",
|
||||||
|
Handler: _TransitService_BatchEncrypt_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "BatchDecrypt",
|
||||||
|
Handler: _TransitService_BatchDecrypt_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "BatchRewrap",
|
||||||
|
Handler: _TransitService_BatchRewrap_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Sign",
|
||||||
|
Handler: _TransitService_Sign_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Verify",
|
||||||
|
Handler: _TransitService_Verify_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Hmac",
|
||||||
|
Handler: _TransitService_Hmac_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetPublicKey",
|
||||||
|
Handler: _TransitService_GetPublicKey_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "proto/metacrypt/v2/transit.proto",
|
||||||
|
}
|
||||||
1602
internal/engine/transit/transit.go
Normal file
1602
internal/engine/transit/transit.go
Normal file
File diff suppressed because it is too large
Load Diff
1025
internal/engine/transit/transit_test.go
Normal file
1025
internal/engine/transit/transit_test.go
Normal file
File diff suppressed because it is too large
Load Diff
15
internal/engine/transit/types.go
Normal file
15
internal/engine/transit/types.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package transit
|
||||||
|
|
||||||
|
// TransitConfig is the transit engine configuration stored in the barrier.
|
||||||
|
type TransitConfig struct {
|
||||||
|
MaxKeyVersions int `json:"max_key_versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyConfig is per-key configuration stored in the barrier.
|
||||||
|
type KeyConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"` // aes256-gcm, chacha20-poly, ed25519, ecdsa-p256, ecdsa-p384, hmac-sha256, hmac-sha512
|
||||||
|
CurrentVersion int `json:"current_version"`
|
||||||
|
MinDecryptionVersion int `json:"min_decryption_version"`
|
||||||
|
AllowDeletion bool `json:"allow_deletion"`
|
||||||
|
}
|
||||||
@@ -82,6 +82,7 @@ func (s *GRPCServer) Start() error {
|
|||||||
pb.RegisterCAServiceServer(s.srv, &caServer{s: s})
|
pb.RegisterCAServiceServer(s.srv, &caServer{s: s})
|
||||||
pb.RegisterPolicyServiceServer(s.srv, &policyServer{s: s})
|
pb.RegisterPolicyServiceServer(s.srv, &policyServer{s: s})
|
||||||
pb.RegisterACMEServiceServer(s.srv, &acmeServer{s: s})
|
pb.RegisterACMEServiceServer(s.srv, &acmeServer{s: s})
|
||||||
|
pb.RegisterTransitServiceServer(s.srv, &transitServer{s: s})
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", s.cfg.Server.GRPCAddr)
|
lis, err := net.Listen("tcp", s.cfg.Server.GRPCAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -136,7 +137,24 @@ func sealRequiredMethods() map[string]bool {
|
|||||||
"/metacrypt.v2.ACMEService/CreateEAB": true,
|
"/metacrypt.v2.ACMEService/CreateEAB": true,
|
||||||
"/metacrypt.v2.ACMEService/SetConfig": true,
|
"/metacrypt.v2.ACMEService/SetConfig": true,
|
||||||
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
||||||
"/metacrypt.v2.ACMEService/ListOrders": true,
|
"/metacrypt.v2.ACMEService/ListOrders": true,
|
||||||
|
"/metacrypt.v2.TransitService/CreateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/DeleteKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/GetKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/ListKeys": true,
|
||||||
|
"/metacrypt.v2.TransitService/RotateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
|
||||||
|
"/metacrypt.v2.TransitService/TrimKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/Encrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/Decrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/Rewrap": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchEncrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchDecrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchRewrap": true,
|
||||||
|
"/metacrypt.v2.TransitService/Sign": true,
|
||||||
|
"/metacrypt.v2.TransitService/Verify": true,
|
||||||
|
"/metacrypt.v2.TransitService/Hmac": true,
|
||||||
|
"/metacrypt.v2.TransitService/GetPublicKey": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +184,24 @@ func authRequiredMethods() map[string]bool {
|
|||||||
"/metacrypt.v2.ACMEService/CreateEAB": true,
|
"/metacrypt.v2.ACMEService/CreateEAB": true,
|
||||||
"/metacrypt.v2.ACMEService/SetConfig": true,
|
"/metacrypt.v2.ACMEService/SetConfig": true,
|
||||||
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
||||||
"/metacrypt.v2.ACMEService/ListOrders": true,
|
"/metacrypt.v2.ACMEService/ListOrders": true,
|
||||||
|
"/metacrypt.v2.TransitService/CreateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/DeleteKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/GetKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/ListKeys": true,
|
||||||
|
"/metacrypt.v2.TransitService/RotateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
|
||||||
|
"/metacrypt.v2.TransitService/TrimKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/Encrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/Decrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/Rewrap": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchEncrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchDecrypt": true,
|
||||||
|
"/metacrypt.v2.TransitService/BatchRewrap": true,
|
||||||
|
"/metacrypt.v2.TransitService/Sign": true,
|
||||||
|
"/metacrypt.v2.TransitService/Verify": true,
|
||||||
|
"/metacrypt.v2.TransitService/Hmac": true,
|
||||||
|
"/metacrypt.v2.TransitService/GetPublicKey": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +220,11 @@ func adminRequiredMethods() map[string]bool {
|
|||||||
"/metacrypt.v2.PolicyService/DeletePolicy": true,
|
"/metacrypt.v2.PolicyService/DeletePolicy": true,
|
||||||
"/metacrypt.v2.ACMEService/SetConfig": true,
|
"/metacrypt.v2.ACMEService/SetConfig": true,
|
||||||
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
"/metacrypt.v2.ACMEService/ListAccounts": true,
|
||||||
"/metacrypt.v2.ACMEService/ListOrders": true,
|
"/metacrypt.v2.ACMEService/ListOrders": true,
|
||||||
|
"/metacrypt.v2.TransitService/CreateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/DeleteKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/RotateKey": true,
|
||||||
|
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
|
||||||
|
"/metacrypt.v2.TransitService/TrimKey": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
486
internal/grpcserver/transit.go
Normal file
486
internal/grpcserver/transit.go
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
package grpcserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
pb "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2"
|
||||||
|
"git.wntrmute.dev/kyle/metacrypt/internal/engine"
|
||||||
|
"git.wntrmute.dev/kyle/metacrypt/internal/engine/transit"
|
||||||
|
"git.wntrmute.dev/kyle/metacrypt/internal/policy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type transitServer struct {
|
||||||
|
pb.UnimplementedTransitServiceServer
|
||||||
|
s *GRPCServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) transitHandleRequest(ctx context.Context, mount, operation string, req *engine.Request) (*engine.Response, error) {
|
||||||
|
resp, err := ts.s.engines.HandleRequest(ctx, mount, req)
|
||||||
|
if err != nil {
|
||||||
|
st := codes.Internal
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, engine.ErrMountNotFound):
|
||||||
|
st = codes.NotFound
|
||||||
|
case errors.Is(err, transit.ErrKeyNotFound):
|
||||||
|
st = codes.NotFound
|
||||||
|
case errors.Is(err, transit.ErrKeyExists):
|
||||||
|
st = codes.AlreadyExists
|
||||||
|
case errors.Is(err, transit.ErrUnauthorized):
|
||||||
|
st = codes.Unauthenticated
|
||||||
|
case errors.Is(err, transit.ErrForbidden):
|
||||||
|
st = codes.PermissionDenied
|
||||||
|
case errors.Is(err, transit.ErrDeletionDenied):
|
||||||
|
st = codes.FailedPrecondition
|
||||||
|
case errors.Is(err, transit.ErrUnsupportedOp):
|
||||||
|
st = codes.InvalidArgument
|
||||||
|
case errors.Is(err, transit.ErrDecryptVersion):
|
||||||
|
st = codes.FailedPrecondition
|
||||||
|
case errors.Is(err, transit.ErrInvalidFormat):
|
||||||
|
st = codes.InvalidArgument
|
||||||
|
case errors.Is(err, transit.ErrBatchTooLarge):
|
||||||
|
st = codes.InvalidArgument
|
||||||
|
case errors.Is(err, transit.ErrInvalidMinVer):
|
||||||
|
st = codes.InvalidArgument
|
||||||
|
case strings.Contains(err.Error(), "not found"):
|
||||||
|
st = codes.NotFound
|
||||||
|
case strings.Contains(err.Error(), "forbidden"):
|
||||||
|
st = codes.PermissionDenied
|
||||||
|
}
|
||||||
|
ts.s.logger.Error("grpc: transit "+operation, "mount", mount, "error", err)
|
||||||
|
return nil, status.Error(st, err.Error())
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) callerInfo(ctx context.Context) *engine.CallerInfo {
|
||||||
|
ti := tokenInfoFromContext(ctx)
|
||||||
|
if ti == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &engine.CallerInfo{
|
||||||
|
Username: ti.Username,
|
||||||
|
Roles: ti.Roles,
|
||||||
|
IsAdmin: ti.IsAdmin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) policyChecker(ctx context.Context) engine.PolicyChecker {
|
||||||
|
caller := ts.callerInfo(ctx)
|
||||||
|
if caller == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return func(resource, action string) (string, bool) {
|
||||||
|
pReq := &policy.Request{
|
||||||
|
Username: caller.Username,
|
||||||
|
Roles: caller.Roles,
|
||||||
|
Resource: resource,
|
||||||
|
Action: action,
|
||||||
|
}
|
||||||
|
effect, matched, err := ts.s.policy.Match(ctx, pReq)
|
||||||
|
if err != nil {
|
||||||
|
return string(policy.EffectDeny), false
|
||||||
|
}
|
||||||
|
return string(effect), matched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) CreateKey(ctx context.Context, req *pb.CreateTransitKeyRequest) (*pb.CreateTransitKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "create-key", &engine.Request{
|
||||||
|
Operation: "create-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"name": req.Name,
|
||||||
|
"type": req.Type,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name, _ := resp.Data["name"].(string)
|
||||||
|
keyType, _ := resp.Data["type"].(string)
|
||||||
|
version, _ := resp.Data["version"].(int)
|
||||||
|
ts.s.logger.Info("audit: transit key created", "mount", req.Mount, "key", name, "type", keyType, "username", callerUsername(ctx))
|
||||||
|
return &pb.CreateTransitKeyResponse{Name: name, Type: keyType, Version: int32(version)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) DeleteKey(ctx context.Context, req *pb.DeleteTransitKeyRequest) (*pb.DeleteTransitKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
_, err := ts.transitHandleRequest(ctx, req.Mount, "delete-key", &engine.Request{
|
||||||
|
Operation: "delete-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: map[string]interface{}{"name": req.Name},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ts.s.logger.Info("audit: transit key deleted", "mount", req.Mount, "key", req.Name, "username", callerUsername(ctx))
|
||||||
|
return &pb.DeleteTransitKeyResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) GetKey(ctx context.Context, req *pb.GetTransitKeyRequest) (*pb.GetTransitKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "get-key", &engine.Request{
|
||||||
|
Operation: "get-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: map[string]interface{}{"name": req.Name},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name, _ := resp.Data["name"].(string)
|
||||||
|
keyType, _ := resp.Data["type"].(string)
|
||||||
|
currentVersion, _ := resp.Data["current_version"].(int)
|
||||||
|
minDecryptionVersion, _ := resp.Data["min_decryption_version"].(int)
|
||||||
|
allowDeletion, _ := resp.Data["allow_deletion"].(bool)
|
||||||
|
rawVersions, _ := resp.Data["versions"].([]int)
|
||||||
|
versions := make([]int32, len(rawVersions))
|
||||||
|
for i, v := range rawVersions {
|
||||||
|
versions[i] = int32(v)
|
||||||
|
}
|
||||||
|
return &pb.GetTransitKeyResponse{
|
||||||
|
Name: name,
|
||||||
|
Type: keyType,
|
||||||
|
CurrentVersion: int32(currentVersion),
|
||||||
|
MinDecryptionVersion: int32(minDecryptionVersion),
|
||||||
|
AllowDeletion: allowDeletion,
|
||||||
|
Versions: versions,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) ListKeys(ctx context.Context, req *pb.ListTransitKeysRequest) (*pb.ListTransitKeysResponse, error) {
|
||||||
|
if req.Mount == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount is required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "list-keys", &engine.Request{
|
||||||
|
Operation: "list-keys",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keys := toStringSliceFromInterface(resp.Data["keys"])
|
||||||
|
return &pb.ListTransitKeysResponse{Keys: keys}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) RotateKey(ctx context.Context, req *pb.RotateTransitKeyRequest) (*pb.RotateTransitKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "rotate-key", &engine.Request{
|
||||||
|
Operation: "rotate-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: map[string]interface{}{"name": req.Name},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name, _ := resp.Data["name"].(string)
|
||||||
|
version, _ := resp.Data["version"].(int)
|
||||||
|
ts.s.logger.Info("audit: transit key rotated", "mount", req.Mount, "key", name, "version", version, "username", callerUsername(ctx))
|
||||||
|
return &pb.RotateTransitKeyResponse{Name: name, Version: int32(version)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) UpdateKeyConfig(ctx context.Context, req *pb.UpdateTransitKeyConfigRequest) (*pb.UpdateTransitKeyConfigResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"name": req.Name}
|
||||||
|
if req.MinDecryptionVersion != 0 {
|
||||||
|
data["min_decryption_version"] = float64(req.MinDecryptionVersion)
|
||||||
|
}
|
||||||
|
data["allow_deletion"] = req.AllowDeletion
|
||||||
|
|
||||||
|
_, err := ts.transitHandleRequest(ctx, req.Mount, "update-key-config", &engine.Request{
|
||||||
|
Operation: "update-key-config",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pb.UpdateTransitKeyConfigResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) TrimKey(ctx context.Context, req *pb.TrimTransitKeyRequest) (*pb.TrimTransitKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "trim-key", &engine.Request{
|
||||||
|
Operation: "trim-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: map[string]interface{}{"name": req.Name},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trimmed, _ := resp.Data["trimmed"].(int)
|
||||||
|
return &pb.TrimTransitKeyResponse{Trimmed: int32(trimmed)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Encrypt(ctx context.Context, req *pb.TransitEncryptRequest) (*pb.TransitEncryptResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"key": req.Key,
|
||||||
|
"plaintext": req.Plaintext,
|
||||||
|
}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "encrypt", &engine.Request{
|
||||||
|
Operation: "encrypt",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ct, _ := resp.Data["ciphertext"].(string)
|
||||||
|
return &pb.TransitEncryptResponse{Ciphertext: ct}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Decrypt(ctx context.Context, req *pb.TransitDecryptRequest) (*pb.TransitDecryptResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"key": req.Key,
|
||||||
|
"ciphertext": req.Ciphertext,
|
||||||
|
}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "decrypt", &engine.Request{
|
||||||
|
Operation: "decrypt",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pt, _ := resp.Data["plaintext"].(string)
|
||||||
|
return &pb.TransitDecryptResponse{Plaintext: pt}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Rewrap(ctx context.Context, req *pb.TransitRewrapRequest) (*pb.TransitRewrapResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"key": req.Key,
|
||||||
|
"ciphertext": req.Ciphertext,
|
||||||
|
}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "rewrap", &engine.Request{
|
||||||
|
Operation: "rewrap",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ct, _ := resp.Data["ciphertext"].(string)
|
||||||
|
return &pb.TransitRewrapResponse{Ciphertext: ct}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) BatchEncrypt(ctx context.Context, req *pb.TransitBatchEncryptRequest) (*pb.TransitBatchResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
items := protoItemsToInterface(req.Items)
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "batch-encrypt", &engine.Request{
|
||||||
|
Operation: "batch-encrypt",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: map[string]interface{}{"key": req.Key, "items": items},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toBatchResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) BatchDecrypt(ctx context.Context, req *pb.TransitBatchDecryptRequest) (*pb.TransitBatchResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
items := protoItemsToInterface(req.Items)
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "batch-decrypt", &engine.Request{
|
||||||
|
Operation: "batch-decrypt",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: map[string]interface{}{"key": req.Key, "items": items},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toBatchResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) BatchRewrap(ctx context.Context, req *pb.TransitBatchRewrapRequest) (*pb.TransitBatchResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
items := protoItemsToInterface(req.Items)
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "batch-rewrap", &engine.Request{
|
||||||
|
Operation: "batch-rewrap",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: map[string]interface{}{"key": req.Key, "items": items},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toBatchResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Sign(ctx context.Context, req *pb.TransitSignRequest) (*pb.TransitSignResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "sign", &engine.Request{
|
||||||
|
Operation: "sign",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: map[string]interface{}{"key": req.Key, "input": req.Input},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sig, _ := resp.Data["signature"].(string)
|
||||||
|
return &pb.TransitSignResponse{Signature: sig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Verify(ctx context.Context, req *pb.TransitVerifyRequest) (*pb.TransitVerifyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "verify", &engine.Request{
|
||||||
|
Operation: "verify",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"key": req.Key,
|
||||||
|
"input": req.Input,
|
||||||
|
"signature": req.Signature,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valid, _ := resp.Data["valid"].(bool)
|
||||||
|
return &pb.TransitVerifyResponse{Valid: valid}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) Hmac(ctx context.Context, req *pb.TransitHmacRequest) (*pb.TransitHmacResponse, error) {
|
||||||
|
if req.Mount == "" || req.Key == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and key are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"key": req.Key,
|
||||||
|
"input": req.Input,
|
||||||
|
}
|
||||||
|
if req.Hmac != "" {
|
||||||
|
data["hmac"] = req.Hmac
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "hmac", &engine.Request{
|
||||||
|
Operation: "hmac",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
CheckPolicy: ts.policyChecker(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hmacStr, _ := resp.Data["hmac"].(string)
|
||||||
|
valid, _ := resp.Data["valid"].(bool)
|
||||||
|
return &pb.TransitHmacResponse{Hmac: hmacStr, Valid: valid}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *transitServer) GetPublicKey(ctx context.Context, req *pb.GetTransitPublicKeyRequest) (*pb.GetTransitPublicKeyResponse, error) {
|
||||||
|
if req.Mount == "" || req.Name == "" {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "mount and name are required")
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"name": req.Name}
|
||||||
|
if req.Version != 0 {
|
||||||
|
data["version"] = float64(req.Version)
|
||||||
|
}
|
||||||
|
resp, err := ts.transitHandleRequest(ctx, req.Mount, "get-public-key", &engine.Request{
|
||||||
|
Operation: "get-public-key",
|
||||||
|
CallerInfo: ts.callerInfo(ctx),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pk, _ := resp.Data["public_key"].(string)
|
||||||
|
version, _ := resp.Data["version"].(int)
|
||||||
|
keyType, _ := resp.Data["type"].(string)
|
||||||
|
return &pb.GetTransitPublicKeyResponse{
|
||||||
|
PublicKey: pk,
|
||||||
|
Version: int32(version),
|
||||||
|
Type: keyType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- helpers ---
|
||||||
|
|
||||||
|
func protoItemsToInterface(items []*pb.TransitBatchItem) []interface{} {
|
||||||
|
out := make([]interface{}, len(items))
|
||||||
|
for i, item := range items {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
if item.Plaintext != "" {
|
||||||
|
m["plaintext"] = item.Plaintext
|
||||||
|
}
|
||||||
|
if item.Ciphertext != "" {
|
||||||
|
m["ciphertext"] = item.Ciphertext
|
||||||
|
}
|
||||||
|
if item.Context != "" {
|
||||||
|
m["context"] = item.Context
|
||||||
|
}
|
||||||
|
if item.Reference != "" {
|
||||||
|
m["reference"] = item.Reference
|
||||||
|
}
|
||||||
|
out[i] = m
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBatchResponse(resp *engine.Response) *pb.TransitBatchResponse {
|
||||||
|
raw, _ := resp.Data["results"].([]interface{})
|
||||||
|
results := make([]*pb.TransitBatchResultItem, 0, len(raw))
|
||||||
|
for _, item := range raw {
|
||||||
|
switch r := item.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
pt, _ := r["plaintext"].(string)
|
||||||
|
ct, _ := r["ciphertext"].(string)
|
||||||
|
ref, _ := r["reference"].(string)
|
||||||
|
errStr, _ := r["error"].(string)
|
||||||
|
results = append(results, &pb.TransitBatchResultItem{
|
||||||
|
Plaintext: pt,
|
||||||
|
Ciphertext: ct,
|
||||||
|
Reference: ref,
|
||||||
|
Error: errStr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &pb.TransitBatchResponse{Results: results}
|
||||||
|
}
|
||||||
@@ -47,6 +47,26 @@ func (s *Server) registerRoutes(r chi.Router) {
|
|||||||
|
|
||||||
r.HandleFunc("/v1/policy/rules", s.requireAuth(s.handlePolicyRules))
|
r.HandleFunc("/v1/policy/rules", s.requireAuth(s.handlePolicyRules))
|
||||||
r.HandleFunc("/v1/policy/rule", s.requireAuth(s.handlePolicyRule))
|
r.HandleFunc("/v1/policy/rule", s.requireAuth(s.handlePolicyRule))
|
||||||
|
|
||||||
|
// Transit engine routes.
|
||||||
|
r.Post("/v1/transit/{mount}/keys", s.requireAdmin(s.handleTransitCreateKey))
|
||||||
|
r.Get("/v1/transit/{mount}/keys", s.requireAuth(s.handleTransitListKeys))
|
||||||
|
r.Get("/v1/transit/{mount}/keys/{name}", s.requireAuth(s.handleTransitGetKey))
|
||||||
|
r.Delete("/v1/transit/{mount}/keys/{name}", s.requireAdmin(s.handleTransitDeleteKey))
|
||||||
|
r.Post("/v1/transit/{mount}/keys/{name}/rotate", s.requireAdmin(s.handleTransitRotateKey))
|
||||||
|
r.Post("/v1/transit/{mount}/keys/{name}/config", s.requireAdmin(s.handleTransitUpdateKeyConfig))
|
||||||
|
r.Post("/v1/transit/{mount}/keys/{name}/trim", s.requireAdmin(s.handleTransitTrimKey))
|
||||||
|
r.Post("/v1/transit/{mount}/encrypt/{key}", s.requireAuth(s.handleTransitEncrypt))
|
||||||
|
r.Post("/v1/transit/{mount}/decrypt/{key}", s.requireAuth(s.handleTransitDecrypt))
|
||||||
|
r.Post("/v1/transit/{mount}/rewrap/{key}", s.requireAuth(s.handleTransitRewrap))
|
||||||
|
r.Post("/v1/transit/{mount}/batch/encrypt/{key}", s.requireAuth(s.handleTransitBatchEncrypt))
|
||||||
|
r.Post("/v1/transit/{mount}/batch/decrypt/{key}", s.requireAuth(s.handleTransitBatchDecrypt))
|
||||||
|
r.Post("/v1/transit/{mount}/batch/rewrap/{key}", s.requireAuth(s.handleTransitBatchRewrap))
|
||||||
|
r.Post("/v1/transit/{mount}/sign/{key}", s.requireAuth(s.handleTransitSign))
|
||||||
|
r.Post("/v1/transit/{mount}/verify/{key}", s.requireAuth(s.handleTransitVerify))
|
||||||
|
r.Post("/v1/transit/{mount}/hmac/{key}", s.requireAuth(s.handleTransitHmac))
|
||||||
|
r.Get("/v1/transit/{mount}/keys/{name}/public-key", s.requireAuth(s.handleTransitGetPublicKey))
|
||||||
|
|
||||||
s.registerACMERoutes(r)
|
s.registerACMERoutes(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,11 +628,270 @@ func (s *Server) getCAEngine(mountName string) (*ca.CAEngine, error) {
|
|||||||
return caEng, nil
|
return caEng, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Transit Engine Handlers ---
|
||||||
|
|
||||||
|
func (s *Server) transitRequest(w http.ResponseWriter, r *http.Request, mount, operation string, data map[string]interface{}) {
|
||||||
|
info := TokenInfoFromContext(r.Context())
|
||||||
|
|
||||||
|
policyChecker := func(resource, action string) (string, bool) {
|
||||||
|
pReq := &policy.Request{
|
||||||
|
Username: info.Username,
|
||||||
|
Roles: info.Roles,
|
||||||
|
Resource: resource,
|
||||||
|
Action: action,
|
||||||
|
}
|
||||||
|
eff, matched, pErr := s.policy.Match(r.Context(), pReq)
|
||||||
|
if pErr != nil {
|
||||||
|
return string(policy.EffectDeny), false
|
||||||
|
}
|
||||||
|
return string(eff), matched
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.engines.HandleRequest(r.Context(), mount, &engine.Request{
|
||||||
|
Operation: operation,
|
||||||
|
CallerInfo: &engine.CallerInfo{Username: info.Username, Roles: info.Roles, IsAdmin: info.IsAdmin},
|
||||||
|
CheckPolicy: policyChecker,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
status := http.StatusInternalServerError
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, engine.ErrMountNotFound):
|
||||||
|
status = http.StatusNotFound
|
||||||
|
case strings.Contains(err.Error(), "forbidden"):
|
||||||
|
status = http.StatusForbidden
|
||||||
|
case strings.Contains(err.Error(), "authentication required"):
|
||||||
|
status = http.StatusUnauthorized
|
||||||
|
case strings.Contains(err.Error(), "not found"):
|
||||||
|
status = http.StatusNotFound
|
||||||
|
case strings.Contains(err.Error(), "not allowed"):
|
||||||
|
status = http.StatusForbidden
|
||||||
|
case strings.Contains(err.Error(), "unsupported"):
|
||||||
|
status = http.StatusBadRequest
|
||||||
|
case strings.Contains(err.Error(), "invalid"):
|
||||||
|
status = http.StatusBadRequest
|
||||||
|
}
|
||||||
|
http.Error(w, `{"error":"`+err.Error()+`"}`, status)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJSON(w, http.StatusOK, resp.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitCreateKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
var req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "create-key", map[string]interface{}{"name": req.Name, "type": req.Type})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitDeleteKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
s.transitRequest(w, r, mount, "delete-key", map[string]interface{}{"name": name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitGetKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
s.transitRequest(w, r, mount, "get-key", map[string]interface{}{"name": name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitListKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
s.transitRequest(w, r, mount, "list-keys", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitRotateKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
s.transitRequest(w, r, mount, "rotate-key", map[string]interface{}{"name": name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitUpdateKeyConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
var req struct {
|
||||||
|
MinDecryptionVersion *float64 `json:"min_decryption_version"`
|
||||||
|
AllowDeletion *bool `json:"allow_deletion"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"name": name}
|
||||||
|
if req.MinDecryptionVersion != nil {
|
||||||
|
data["min_decryption_version"] = *req.MinDecryptionVersion
|
||||||
|
}
|
||||||
|
if req.AllowDeletion != nil {
|
||||||
|
data["allow_deletion"] = *req.AllowDeletion
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "update-key-config", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitTrimKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
s.transitRequest(w, r, mount, "trim-key", map[string]interface{}{"name": name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitEncrypt(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Plaintext string `json:"plaintext"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"key": key, "plaintext": req.Plaintext}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "encrypt", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitDecrypt(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Ciphertext string `json:"ciphertext"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"key": key, "ciphertext": req.Ciphertext}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "decrypt", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitRewrap(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Ciphertext string `json:"ciphertext"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"key": key, "ciphertext": req.Ciphertext}
|
||||||
|
if req.Context != "" {
|
||||||
|
data["context"] = req.Context
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "rewrap", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitBatchEncrypt(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Items []interface{} `json:"items"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "batch-encrypt", map[string]interface{}{"key": key, "items": req.Items})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitBatchDecrypt(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Items []interface{} `json:"items"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "batch-decrypt", map[string]interface{}{"key": key, "items": req.Items})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitBatchRewrap(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Items []interface{} `json:"items"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "batch-rewrap", map[string]interface{}{"key": key, "items": req.Items})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitSign(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Input string `json:"input"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "sign", map[string]interface{}{"key": key, "input": req.Input})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitVerify(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Input string `json:"input"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "verify", map[string]interface{}{"key": key, "input": req.Input, "signature": req.Signature})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitHmac(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
key := chi.URLParam(r, "key")
|
||||||
|
var req struct {
|
||||||
|
Input string `json:"input"`
|
||||||
|
HMAC string `json:"hmac"`
|
||||||
|
}
|
||||||
|
if err := readJSON(r, &req); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"key": key, "input": req.Input}
|
||||||
|
if req.HMAC != "" {
|
||||||
|
data["hmac"] = req.HMAC
|
||||||
|
}
|
||||||
|
s.transitRequest(w, r, mount, "hmac", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleTransitGetPublicKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mount := chi.URLParam(r, "mount")
|
||||||
|
name := chi.URLParam(r, "name")
|
||||||
|
s.transitRequest(w, r, mount, "get-public-key", map[string]interface{}{"name": name})
|
||||||
|
}
|
||||||
|
|
||||||
// operationAction maps an engine operation name to a policy action ("read" or "write").
|
// operationAction maps an engine operation name to a policy action ("read" or "write").
|
||||||
func operationAction(op string) string {
|
func operationAction(op string) string {
|
||||||
switch op {
|
switch op {
|
||||||
case "list-issuers", "list-certs", "get-cert", "get-root", "get-chain", "get-issuer":
|
case "list-issuers", "list-certs", "get-cert", "get-root", "get-chain", "get-issuer",
|
||||||
|
"list-keys", "get-key", "get-public-key":
|
||||||
return "read"
|
return "read"
|
||||||
|
case "decrypt", "rewrap", "batch-decrypt", "batch-rewrap":
|
||||||
|
return "decrypt"
|
||||||
default:
|
default:
|
||||||
return "write"
|
return "write"
|
||||||
}
|
}
|
||||||
|
|||||||
291
proto/metacrypt/v2/transit.proto
Normal file
291
proto/metacrypt/v2/transit.proto
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package metacrypt.v2;
|
||||||
|
|
||||||
|
option go_package = "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2;metacryptv2";
|
||||||
|
|
||||||
|
// TransitService provides typed, authenticated access to transit engine
|
||||||
|
// operations: symmetric encryption, signing, HMAC, and versioned key
|
||||||
|
// management. All RPCs require the service to be unsealed.
|
||||||
|
service TransitService {
|
||||||
|
// CreateKey creates a new named encryption key. Admin only.
|
||||||
|
rpc CreateKey(CreateTransitKeyRequest) returns (CreateTransitKeyResponse);
|
||||||
|
|
||||||
|
// DeleteKey permanently removes a named key. Admin only.
|
||||||
|
// Only succeeds if allow_deletion is true on the key config.
|
||||||
|
rpc DeleteKey(DeleteTransitKeyRequest) returns (DeleteTransitKeyResponse);
|
||||||
|
|
||||||
|
// GetKey returns metadata for a named key (no raw material). Auth required.
|
||||||
|
rpc GetKey(GetTransitKeyRequest) returns (GetTransitKeyResponse);
|
||||||
|
|
||||||
|
// ListKeys returns the names of all configured keys. Auth required.
|
||||||
|
rpc ListKeys(ListTransitKeysRequest) returns (ListTransitKeysResponse);
|
||||||
|
|
||||||
|
// RotateKey creates a new version of the named key. Admin only.
|
||||||
|
rpc RotateKey(RotateTransitKeyRequest) returns (RotateTransitKeyResponse);
|
||||||
|
|
||||||
|
// UpdateKeyConfig updates key configuration (e.g. min_decryption_version).
|
||||||
|
// Admin only.
|
||||||
|
rpc UpdateKeyConfig(UpdateTransitKeyConfigRequest) returns (UpdateTransitKeyConfigResponse);
|
||||||
|
|
||||||
|
// TrimKey deletes versions below min_decryption_version. Admin only.
|
||||||
|
rpc TrimKey(TrimTransitKeyRequest) returns (TrimTransitKeyResponse);
|
||||||
|
|
||||||
|
// Encrypt encrypts plaintext with the latest key version. Auth required.
|
||||||
|
rpc Encrypt(TransitEncryptRequest) returns (TransitEncryptResponse);
|
||||||
|
|
||||||
|
// Decrypt decrypts ciphertext. Auth required.
|
||||||
|
rpc Decrypt(TransitDecryptRequest) returns (TransitDecryptResponse);
|
||||||
|
|
||||||
|
// Rewrap re-encrypts ciphertext with the latest key version without
|
||||||
|
// exposing plaintext. Auth required.
|
||||||
|
rpc Rewrap(TransitRewrapRequest) returns (TransitRewrapResponse);
|
||||||
|
|
||||||
|
// BatchEncrypt encrypts multiple items in a single request. Auth required.
|
||||||
|
rpc BatchEncrypt(TransitBatchEncryptRequest) returns (TransitBatchResponse);
|
||||||
|
|
||||||
|
// BatchDecrypt decrypts multiple items in a single request. Auth required.
|
||||||
|
rpc BatchDecrypt(TransitBatchDecryptRequest) returns (TransitBatchResponse);
|
||||||
|
|
||||||
|
// BatchRewrap re-encrypts multiple items in a single request. Auth required.
|
||||||
|
rpc BatchRewrap(TransitBatchRewrapRequest) returns (TransitBatchResponse);
|
||||||
|
|
||||||
|
// Sign signs input data with an asymmetric key. Auth required.
|
||||||
|
rpc Sign(TransitSignRequest) returns (TransitSignResponse);
|
||||||
|
|
||||||
|
// Verify verifies a signature against input data. Auth required.
|
||||||
|
rpc Verify(TransitVerifyRequest) returns (TransitVerifyResponse);
|
||||||
|
|
||||||
|
// Hmac computes or verifies an HMAC. Auth required.
|
||||||
|
rpc Hmac(TransitHmacRequest) returns (TransitHmacResponse);
|
||||||
|
|
||||||
|
// GetPublicKey returns the public key for an asymmetric key. Auth required.
|
||||||
|
rpc GetPublicKey(GetTransitPublicKeyRequest) returns (GetTransitPublicKeyResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CreateKey ---
|
||||||
|
|
||||||
|
message CreateTransitKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
// type is the key algorithm: aes256-gcm, chacha20-poly, ed25519,
|
||||||
|
// ecdsa-p256, ecdsa-p384, hmac-sha256, hmac-sha512.
|
||||||
|
// Defaults to aes256-gcm if empty.
|
||||||
|
string type = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateTransitKeyResponse {
|
||||||
|
string name = 1;
|
||||||
|
string type = 2;
|
||||||
|
int32 version = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DeleteKey ---
|
||||||
|
|
||||||
|
message DeleteTransitKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteTransitKeyResponse {}
|
||||||
|
|
||||||
|
// --- GetKey ---
|
||||||
|
|
||||||
|
message GetTransitKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTransitKeyResponse {
|
||||||
|
string name = 1;
|
||||||
|
string type = 2;
|
||||||
|
int32 current_version = 3;
|
||||||
|
int32 min_decryption_version = 4;
|
||||||
|
bool allow_deletion = 5;
|
||||||
|
repeated int32 versions = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ListKeys ---
|
||||||
|
|
||||||
|
message ListTransitKeysRequest {
|
||||||
|
string mount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListTransitKeysResponse {
|
||||||
|
repeated string keys = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- RotateKey ---
|
||||||
|
|
||||||
|
message RotateTransitKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RotateTransitKeyResponse {
|
||||||
|
string name = 1;
|
||||||
|
int32 version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UpdateKeyConfig ---
|
||||||
|
|
||||||
|
message UpdateTransitKeyConfigRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
int32 min_decryption_version = 3;
|
||||||
|
bool allow_deletion = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateTransitKeyConfigResponse {}
|
||||||
|
|
||||||
|
// --- TrimKey ---
|
||||||
|
|
||||||
|
message TrimTransitKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TrimTransitKeyResponse {
|
||||||
|
int32 trimmed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Encrypt ---
|
||||||
|
|
||||||
|
message TransitEncryptRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
// plaintext is base64-encoded data to encrypt.
|
||||||
|
string plaintext = 3;
|
||||||
|
// context is optional base64-encoded additional authenticated data (AAD).
|
||||||
|
string context = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitEncryptResponse {
|
||||||
|
// ciphertext in format "metacrypt:v{version}:{base64(nonce+ciphertext+tag)}"
|
||||||
|
string ciphertext = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Decrypt ---
|
||||||
|
|
||||||
|
message TransitDecryptRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
string ciphertext = 3;
|
||||||
|
string context = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitDecryptResponse {
|
||||||
|
// plaintext is base64-encoded decrypted data.
|
||||||
|
string plaintext = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Rewrap ---
|
||||||
|
|
||||||
|
message TransitRewrapRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
string ciphertext = 3;
|
||||||
|
string context = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitRewrapResponse {
|
||||||
|
string ciphertext = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Batch ---
|
||||||
|
|
||||||
|
message TransitBatchItem {
|
||||||
|
string plaintext = 1;
|
||||||
|
string ciphertext = 2;
|
||||||
|
string context = 3;
|
||||||
|
string reference = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitBatchResultItem {
|
||||||
|
string plaintext = 1;
|
||||||
|
string ciphertext = 2;
|
||||||
|
string reference = 3;
|
||||||
|
string error = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitBatchEncryptRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
repeated TransitBatchItem items = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitBatchDecryptRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
repeated TransitBatchItem items = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitBatchRewrapRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
repeated TransitBatchItem items = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitBatchResponse {
|
||||||
|
repeated TransitBatchResultItem results = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Sign ---
|
||||||
|
|
||||||
|
message TransitSignRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
// input is base64-encoded data to sign.
|
||||||
|
string input = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitSignResponse {
|
||||||
|
// signature in format "metacrypt:v{version}:{base64(signature_bytes)}"
|
||||||
|
string signature = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Verify ---
|
||||||
|
|
||||||
|
message TransitVerifyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
string input = 3;
|
||||||
|
string signature = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitVerifyResponse {
|
||||||
|
bool valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- HMAC ---
|
||||||
|
|
||||||
|
message TransitHmacRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string key = 2;
|
||||||
|
// input is base64-encoded data to HMAC.
|
||||||
|
string input = 3;
|
||||||
|
// hmac, if set, switches to verify mode.
|
||||||
|
string hmac = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransitHmacResponse {
|
||||||
|
// hmac is set in compute mode.
|
||||||
|
string hmac = 1;
|
||||||
|
// valid is set in verify mode.
|
||||||
|
bool valid = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GetPublicKey ---
|
||||||
|
|
||||||
|
message GetTransitPublicKeyRequest {
|
||||||
|
string mount = 1;
|
||||||
|
string name = 2;
|
||||||
|
int32 version = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTransitPublicKeyResponse {
|
||||||
|
// public_key is base64-encoded PKIX DER public key.
|
||||||
|
string public_key = 1;
|
||||||
|
int32 version = 2;
|
||||||
|
string type = 3;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user