Skip to content

Latest commit

 

History

History
194 lines (143 loc) · 7.97 KB

File metadata and controls

194 lines (143 loc) · 7.97 KB

softKMS API Reference

softKMS exposes two network APIs plus a CLI:

Surface Default address Audience Auth
gRPC 127.0.0.1:50051 Local admin channel (init/unlock/lock, admin + client ops) Admin passphrase or identity token
REST 0.0.0.0:8080 Client surface (token-scoped) Identity token only (export endpoints also take an admin passphrase in the body)

Keys never leave the daemon; clients receive only results (signatures, ciphertext, public keys). The gRPC channel is intended to stay loopback-only; the REST channel can be exposed (enable TLS).

The canonical schema for the gRPC API is proto/softkms.proto — message field names/types are defined there and are the source of truth. This document describes the surface, auth model, and REST payloads.


Authentication

Identity tokens

Created with softkms identity create (shown once). A token authorizes operations scoped to that identity's own keys (namespace isolation). The server stores only SHA256(token).

gRPC

gRPC requests carry flat fields on the request message (there is no AuthContext/oneof):

  • auth_token — an identity token (scopes the request to that identity), and/or
  • passphrase — the admin passphrase (full access).

If auth_token is non-empty it is used; otherwise the request is treated as admin and the passphrase is verified on every call (an empty/wrong passphrase is rejected with PERMISSION_DENIED, even while the daemon is unlocked).

REST

REST is token-only. Pass the identity token via either header:

Authorization: Bearer <token>
# or
X-SoftKMS-Token: <token>

Exceptions: GET /health and GET /v1/status are unauthenticated; GET /metrics requires an identity token or admin passphrase (gated via validate_auth). POST /v1/keys/:id/verify authenticates optionally; the two export/* endpoints additionally require an admin_passphrase in the JSON body.


Supported key algorithms

ed25519, p256, falcon512, falcon1024.

RSA and ECDSA-secp256k1 are not implemented (the proto Algorithm enum reserves the names, but create/sign/verify reject them). Falcon keys cannot be HD-derived from a seed.


REST API

Base URL: http://127.0.0.1:8080 (or https://… when TLS is enabled). All request/response bodies are JSON. Binary fields (data, signature, ciphertext, plaintext, aad) are base64-encoded.

Unauthenticated

Method Path Description Response
GET /health Liveness 200 body OK
GET /v1/status Readiness (no topology disclosed) { "version", "status", "unlocked" }
GET /metrics Prometheus exposition text format
curl -s http://127.0.0.1:8080/v1/status
# {"version":"0.2.0","status":"ok","unlocked":true}

Keys (token required)

Method Path Body Response
GET /v1/keys { "keys": [KeyInfo, …] }
POST /v1/keys { "algorithm", "label"? } { "key_id", "algorithm", "public_key"?, "created_at", "label" }
GET /v1/keys/:id KeyInfo (owner-checked)
POST /v1/keys/:id/sign { "data": base64 } { "key_id", "signature": base64, "algorithm" }
POST /v1/keys/:id/verify { "data": base64, "signature": base64 } { "valid": bool, "algorithm" }
POST /v1/keys/:id/encrypt { "data": base64, "aad"?: base64 } { "ciphertext": base64 }
POST /v1/keys/:id/decrypt { "ciphertext": base64, "aad"?: base64 } { "plaintext": base64 }
POST /v1/keys/:id/export/ssh { "passphrase", "admin_passphrase", "output_path"? } { "key_id", "output_path", "algorithm" }
POST /v1/keys/:id/export/gpg { "admin_passphrase", "user_id"? } { "key_id", "user_id", "algorithm", "armored_key" }

KeyInfo = { "key_id", "algorithm", "key_type", "label", "created_at", "public_key"?, "owner_identity"? }.

For encrypt/decrypt the ciphertext is base64 of nonce || ciphertext || tag (AES-256-GCM, fresh 96-bit nonce per message).

Symmetric keys (token required)

Method Path Body Response
POST /v1/symmetric-keys { "label"? } { "key_id", "label", "algorithm" } (random AES-256-GCM key)
POST /v1/seeds/:id/derive-symmetric { "path", "label"? } { "key_id", "label", "algorithm" } (deterministic, seed-recoverable)

Identity (token required)

Method Path Response
GET /v1/identities/me { "public_key", "key_type", "client_type", "description"?, "created_at", "last_used", "is_active" }

REST examples

TOKEN="<identity-token>"
H="Authorization: Bearer $TOKEN"

# Create an Ed25519 key
curl -s -H "$H" -H 'Content-Type: application/json' \
  -d '{"algorithm":"ed25519","label":"mykey"}' \
  http://127.0.0.1:8080/v1/keys
# -> {"key_id":"<uuid>","algorithm":"ed25519","public_key":"<b64>","created_at":"…","label":"mykey"}

# Sign (data is base64 — here base64("hello"))
curl -s -H "$H" -H 'Content-Type: application/json' \
  -d "{\"data\":\"$(printf 'hello' | base64)\"}" \
  http://127.0.0.1:8080/v1/keys/<uuid>/sign
# -> {"key_id":"<uuid>","signature":"<b64>","algorithm":"ed25519"}

# List the identity's own keys
curl -s -H "$H" http://127.0.0.1:8080/v1/keys

gRPC API

Two services (see proto/softkms.proto for message schemas):

KeyStore

Lifecycle: Init, Unlock, Lock, Health. Keys: CreateKey, ListKeys, GetKey, DeleteKey, Sign, Verify, RotateKey, ChangePassphrase. Symmetric: Encrypt, Decrypt, DeriveSymmetricKey, GenerateSymmetricKey. HD / seeds: ImportSeed, DeriveP256, DeriveEd25519, ImportXpub, DerivePublic. Export: ExportSshKey, ExportGpgKey. Backup / restore: Backup, Restore. Metrics: GetMetrics.

DeriveKey exists in the proto but is not implemented — it returns UNIMPLEMENTED. Use DeriveEd25519 / DeriveP256 instead. Backup and Restore require admin authentication and write/read a tar.gz tarball to/from a filesystem path.

IdentityService

CreateIdentity, ListIdentities, GetIdentity, RevokeIdentity.

Health / readiness

HealthResponse includes healthy, version, storage_ready, api_ready, initialized, and unlocked (readiness). Init/Health are RPCs on KeyStore (there is no separate health service).

grpcurl example

# Health (no auth)
grpcurl -plaintext 127.0.0.1:50051 softkms.KeyStore/Health

# Create a key as admin (passphrase in the request message)
grpcurl -plaintext -d '{"algorithm":"ed25519","label":"mykey","passphrase":"<admin>"}' \
  127.0.0.1:50051 softkms.KeyStore/CreateKey

# Create a key as an identity (auth_token instead of passphrase)
grpcurl -plaintext -d '{"algorithm":"ed25519","label":"mykey","auth_token":"<token>"}' \
  127.0.0.1:50051 softkms.KeyStore/CreateKey

(Server reflection availability depends on build; otherwise pass -import-path proto -proto softkms.proto.)


Errors

gRPC handlers map domain errors to Status; REST maps them to HTTP codes:

Condition gRPC HTTP
Bad/empty admin passphrase, ownership denied PERMISSION_DENIED 401/403
Key/identity not found NOT_FOUND 404
Invalid argument (bad key id, unsupported algorithm) INVALID_ARGUMENT 400
Keystore not initialized / locked; non-signing key for verify FAILED_PRECONDITION 400/412
Missing/invalid token (REST) 401

Error messages avoid disclosing key material; /v1/status deliberately omits bind addresses and the storage backend.


See also