Enchantrix/pkg/keyserver/capability.go
Claude 447f3ccaca
feat: add Keyserver Secure Environment (SE) for key isolation
Introduces an in-process keyserver that holds cryptographic key material
and exposes operations by opaque key ID — callers (including AI agents)
never see raw key bytes.

New packages:
- pkg/keystore: Trix-based encrypted key store with Argon2id master key
- pkg/keyserver: KeyServer interface, composite crypto ops, session/ACL,
  audit logging

New CLI commands:
- trix keystore init/import/generate/list/delete
- trix keyserver start, trix keyserver session create

Specification: RFC-0005-Keyserver-Secure-Environment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:30:31 +00:00

82 lines
2.1 KiB
Go

package keyserver
import (
"fmt"
"strings"
)
// Capability represents a permission to perform a specific operation on a
// specific key (or all keys with wildcard "*").
//
// Format: "operation:keyID" — e.g. "encrypt:abc123" or "decrypt:*"
type Capability struct {
Operation string // encrypt, decrypt, sign, verify, list, derive, delete
KeyID string // specific key ID or "*" for all
}
// Valid operation names for capability strings.
var validOperations = map[string]bool{
"encrypt": true,
"decrypt": true,
"sign": true,
"verify": true,
"list": true,
"derive": true,
"delete": true,
"generate": true,
"import": true,
"wrap": true,
"unwrap": true,
}
// ParseCapability parses a capability string like "encrypt:key-abc".
func ParseCapability(s string) (Capability, error) {
parts := strings.SplitN(s, ":", 2)
if len(parts) != 2 {
return Capability{}, fmt.Errorf("keyserver: invalid capability format %q (expected op:keyID)", s)
}
op := strings.TrimSpace(parts[0])
keyID := strings.TrimSpace(parts[1])
if !validOperations[op] {
return Capability{}, fmt.Errorf("keyserver: unknown operation %q", op)
}
if keyID == "" {
return Capability{}, fmt.Errorf("keyserver: empty key ID in capability %q", s)
}
return Capability{Operation: op, KeyID: keyID}, nil
}
// ParseCapabilities parses a comma-separated list of capability strings.
func ParseCapabilities(s string) ([]Capability, error) {
parts := strings.Split(s, ",")
caps := make([]Capability, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
if p == "" {
continue
}
cap, err := ParseCapability(p)
if err != nil {
return nil, err
}
caps = append(caps, cap)
}
return caps, nil
}
// Matches reports whether this capability grants permission for the given
// operation on the given key.
func (c Capability) Matches(op, keyID string) bool {
if c.Operation != op {
return false
}
return c.KeyID == "*" || c.KeyID == keyID
}
// String returns the canonical string form "operation:keyID".
func (c Capability) String() string {
return c.Operation + ":" + c.KeyID
}