Integrations
Reach the authority contract through the interfaces your estate already speaks — Cloud EKM/XKS, PKCS#11, and an MCP gateway for agent tool calls.
An authority fabric nobody can connect to is a library. These are the surfaces that let an existing estate reach it — and, just as importantly, an honest account of what survives each translation and what does not.
External key manager (EKM / XKS)
scsa-ekmd presents a Google Cloud EKM–shaped façade. It binds
127.0.0.1:8081 by default.
| Method | Path |
|---|---|
GET | /v0/health |
GET | /v0/cryptospaces/{cryptospace}/keys/{key} |
POST | /v0/cryptospaces/{cryptospace}/keys/{key} |
A caller who only speaks EKM gets the whole contract. A wrap and an unwrap are
each a canonical operation intent delivered to the same coordinator as the
native path: the same governance binding, the same executor admission, the same
quorum, the same single-use nullifier, the same transparency log, and the same
decision envelope — which the caller can be handed afterwards and check offline
with scsa-verify long after the service is gone.
What protects the blob — stated flatly
Authorization to wrap or unwrap is threshold-gated, governed, journaled and portable. Nobody gets an unwrap without an operation that cleared governance, formed a quorum, spent a nullifier, and produced a signed, logged envelope. That part is entirely real.
Confidentiality of the wrapped blob reduces to this node's recipient key. A party who steals that key and the blob can open it without any quorum. It does not reduce to 3-of-5 seats.
The reason is worth understanding rather than working around. Every SCSA operation
derives a fresh key, because derivation runs over x_auth, which binds the
operation intent digest and therefore the nullifier — two operations never derive
the same key, by design. A stable key-encryption key for the life of a ciphertext
is the other context, x_wrap. The coordinator-driven path only evaluates
x_auth, so a blob cannot be re-derived at unwrap time; it carries its key with
it, sealed to the node's recipient key.
If your threat model requires the blob's confidentiality to rest on the quorum rather than on one node's key, this adapter is not yet the right surface, and you should say so in your risk assessment.
PKCS#11
PKCS#11 is how an existing estate actually reaches a cryptographic authority —
Java's SunPKCS11, OpenSSL's provider, NSS, strongSwan, and effectively every HSM
deployment in production speak it.
The mismatch is real and worth naming: PKCS#11 is a synchronous, key-handle-shaped API over a single local module, and SCSA is a quorum-mediated, evidence-bound, refusal-producing contract over a distributed fabric. Pretending they map cleanly is how this kind of project goes wrong — a client comes away believing it has an HSM with an unusual vendor prefix, and every guarantee is silently absent at the one interface anybody connects through.
What a PKCS#11 caller gets
- A slot, a token, and objects that name authorities.
C_SignandC_UnwrapKeythat really are complete SCSA operations — governance gate, work binding, nullifier reservation, quorum, commit, transparency-log inclusion, release — every single time.- A
CK_RVthat is a true statement at the Cryptoki level, includingCKR_FUNCTION_REJECTEDfor a decision not to proceed. - The coordinator's decision envelope, canonical and byte-identical to what an auditor would verify, retrievable through standard entry points.
CKA_ALWAYS_AUTHENTICATEon every key object — the one field in the standard that says this handle is not a standing capability.
What a PKCS#11 caller cannot get
- A signature verifiable with a standard verifier. SCSA releases a decision, not a bare signature over your data in the shape a generic PKCS#11 consumer expects.
- A refusal reason. Cryptoki has one rejection return value; the seven
families of refusal code collapse into it. The reason lives in the envelope, and
a caller that only reads
CK_RVwill not see it. - A standing key handle. A handle names an authority. It does not carry authority, and every use re-enters the full operation.
Take the envelope if you want the guarantees. The CK_RV alone is a lossy view.
MCP gateway for agent tool calls
scsa-mcp mediates tool use by autonomous agents under the same contract.
It is not a credential broker. A gateway that authenticates an agent and hands back a token — even a short-lived, attested, policy-checked one — has moved the problem rather than solved it. From the moment the token exists, the agent, and anything that has compromised the agent's context (a poisoned web page, a malicious email, another agent's output), holds something that works more than once, for more than one call, against everything the token is accepted for. The authority is back inside the process whose judgement was the thing in question.
Instead, an agent never holds anything reusable. It presents a request and receives, at most, a one-use, executor-bound authorization for exactly one normalized invocation of exactly one measured tool. Every attempt, granted or not, terminates in a signed, offline-verifiable tool decision — not an error string.
Two of the controls are worth calling out because they close injection paths directly:
- Measurement and manifest binding. The MCP server's measurement and the tool manifest digest are inside the capability. A tool whose manifest changed is a different tool, and outstanding capabilities for it stop verifying.
- Normalization before policy. Arguments are resolved to canonical values
before any predicate runs, and anything admitting two readings is
AMBIGUOUS_SEMANTICS (103)rather than a guess. This is enforced by the type system — normalized arguments have no constructor other than the normalizer.
The mandate rules follow the same discipline: MANDATE_EXCEEDED (206) when a
call is outside the agent's tools, resources, counterparties or limits;
DELEGATION_AMPLIFIED (207) when a child authority is not a subset of its parent;
BUDGET_EXHAUSTED (208) when a value, count, destination or time budget is spent.