SM Remote (SM Cipher Suite Service)

Verified against commit 942a18727c (2026-09-26, DOC-2 of SPRINT_20260926_001). Re-verify by reading the evidence paths listed in the Evidence section of architecture.md.

Service wiring (image, database and role, compose profile, bundle presence) is generated in the service inventory; this dossier does not restate it.

Stateless cryptographic operations microservice for Chinese national standard algorithms (SM2/SM3/SM4).

Purpose

SM Remote provides Chinese national standard cryptographic algorithms (SM2 signing/verification, SM3 hashing, SM4 encryption/decryption) as a stateless microservice for regional compliance requirements. It enables Stella Ops deployments to satisfy GB/T standards by offering both soft-provider (BouncyCastle) and optional HSM/remote provider modes for production key management.

Status

AttributeValue
Sourcesrc/SmRemote/StellaOps.SmRemote.Service
DeploymentOpt-in compose overlays only; not in the release bundle (devops/release/bundle/docker-compose.yml)
Router service namesmremote
DatabaseNone (stateless)

Two overlays start the service:

OverlayService / imageListenerRouter
devops/compose/docker-compose.crypto-provider.smremote.ymlsmremote, stellaops/smremote:dev, alias smremote.stella-ops.localASPNETCORE_URLS=http://+:8080; host mapping 127.1.0.31:80:8080Enabled (Router__Enabled, Valkey messaging, consumer group smremote)
devops/compose/docker-compose.sm-remote.yml (China profile, standalone or with docker-compose.compliance-china.yml)sm-remote, built from devops/services/sm-remote/Dockerfilehttp://0.0.0.0:56080; host port ${SM_REMOTE_PORT:-56080}No Router settings

SmRemote invokes TryAddStellaOpsLocalBinding in every environment. In a Production container, Docker DNS resolves smremote.stella-ops.local to the container address, so the service binds ports 80 and 443 as well as the configured ASPNETCORE_URLS port 8080. The overlay keeps the published host mapping 127.1.0.31:80 to container port 8080. In-network callers use the port-less http://smremote.stella-ops.local URL and reach container port 80; the local 443 listener uses the configured operator TLS certificate. Gateway access over Router messaging does not depend on these HTTP listeners.

A sample project, devops/compose/samples/smremote/, runs the crypto-provider.smremote service on its own with placeholders for the HSM adapter endpoint, its API key, the key mapping, the vendor contract version and the Authority issuer. It requires an existing operator TLS PFX and password for the Production port 443 listener, mounts only that PFX read-only, keeps the overlay’s 127.1.0.31:80 to 8080 mapping and runs Production. The 2026-09-28 pre-PCD-131 sample probe answered GET http://127.1.0.31/health with 503 “SM Remote vendor adapter failed closed” (adapter_http_error, the placeholder adapter unresolvable), and POST /sign with 401 before any adapter call. Nothing in the sample imitates an HSM. Its README lists the required operator TLS inputs and the HSM placeholders.

Key Features

API Surface

The service exposes minimal-API HTTP endpoints. Routes are reached through the Stella Router under the smremote service name (see Program.cs AddRouterMicroservice(..., serviceName: "smremote", ...)).

Method & RouteAuthScope (policy)Algorithm / Behavior
GET /healthAnonymous—Liveness; returns {status, provider, adapterId?, adapterKind?, contractVersion?}. In remote mode, probes the adapter and returns 503 on contract/HTTP/timeout failure.
GET /statusAnonymous—Capability/availability; returns {available, provider, algorithms, adapterId?, adapterKind?, contractVersion?, keys?}. Default advertised algorithm is SM2.
POST /hashBearersm-remote:hash (SmRemote.Hash)SM3 digest. Returns {algorithmId, hashBase64, hashHex}.
POST /encryptBearersm-remote:encrypt (SmRemote.Encrypt)SM4 in the configured mode (CBC default, GCM; ECB only under ECB-Interop). Soft mode uses a 16-byte keyBase64 and returns ivBase64 (CBC/GCM) and tagBase64 (GCM); remote mode requires keyId.
POST /decryptBearersm-remote:decrypt (SmRemote.Decrypt)SM4 in the configured mode; CBC requires ivBase64, GCM requires ivBase64 and tagBase64. Soft mode uses a 16-byte keyBase64; remote mode requires keyId.
POST /signBearersm-remote:sign (SmRemote.Sign)SM2 signature over payloadBase64. Returns {signature}.
POST /verifyBearersm-remote:verify (SmRemote.Verify)SM2 verification. Returns {valid}.
GET /openapi/v1.jsonAnonymous—Generated OpenAPI document for the routes above, read by the gateway’s OpenAPI aggregate. The committed copy is openapi/v1.json, rendered in api-reference.md.

Scopes are defined canonically in StellaOps.Auth.Abstractions/StellaOpsScopes.cs (SmRemoteHash, SmRemoteEncrypt, SmRemoteDecrypt, SmRemoteSign, SmRemoteVerify) and bound to named policies in Security/SmRemotePolicies.cs. The supported hash algorithm is SM3; the supported symmetric algorithm ids are SM4-CBC, SM4-GCM, SM4-ECB (interop only) and bare SM4 (mapped to the configured mode); the supported signature algorithm is SM2.

Configuration

Provider selection (SmRemote:Provider): cn.sm.remote.http (or remote) for the HSM bridge, cn.sm.soft (or soft) for the local soft provider. In Development/Testing the default is the soft provider; otherwise the default is the remote provider.

Remote (HSM bridge) keys, read by SmRemoteRuntimeOptions.ApplyConfiguration:

Soft / ephemeral runtime gates:

Vendor Adapter Contract

In remote mode the service bridges to an operator-controlled vendor HSM adapter and validates its responses fail-closed. Before sign/verify/encrypt/decrypt it probes the adapter /status and /keys and rejects mismatches (failure classes such as key_mapping_missing, key_usage_mismatch), returning 502/503 problem responses with a failureClass extension. Adapter kinds are validated against sm-hsm, sdf, and pkcs11. The contract is documented in the SM Remote vendor adapter contract.

Dependencies

Upstream

Consumers (verified references in src/)

Storage & Background Workers

The service is stateless and owns no database schema. The only stateful surface is in-process: the EphemeralKeyRegistry (tracks minted ephemeral SM2 keys for this process lifetime) and the EphemeralKeyAuditLog. A single hosted BackgroundService, EphemeralKeyRotationService, sweeps the registry on an interval (default 30s), evicts expired ephemeral keys from the soft provider, and emits audit events. It is a no-op when ephemeral keys are disabled.

Ephemeral Key Lifecycle & Audit

When SMREMOTE_ALLOW_EPHEMERAL_KEYS is enabled (Development/Testing only) and a positive TTL is configured, the first /sign or /verify for an unknown key id mints an ephemeral SM2 key on the soft provider. Each key is stamped with ephemeral, expiresAt, seededBy (RuntimeId), seededAt, and ttl metadata. The audit log records sm-remote.key.seeded on mint and sm-remote.key.rotated on expiry-eviction. The audit log is process-local today (a future sprint may forward to the central audit chain).

Runtime Posture

Development and Testing may use cn.sm.soft with ephemeral key seeding for local deterministic harnesses (ephemeral seeding must be explicitly opted in via SMREMOTE_ALLOW_EPHEMERAL_KEYS=true plus a positive SMREMOTE_EPHEMERAL_KEY_TTL; the implicit-default seeding was removed). Production must disable software and ephemeral modes (SMREMOTE_ALLOW_SOFTWARE_PROVIDER=0, SMREMOTE_ALLOW_EPHEMERAL_KEYS=0) and register a hardware/remote provider adapter before cryptographic authority is available. Startup ValidateOnStart enforces these gates and rejects unsafe production configuration (e.g. soft provider, missing SM_REMOTE_HSM_URL, missing key mappings, or disabled vendor contract validation).