@agenticprimitives/key-custody 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/dist/aad.d.ts +2 -0
  4. package/dist/aad.d.ts.map +1 -0
  5. package/dist/aad.js +19 -0
  6. package/dist/aad.js.map +1 -0
  7. package/dist/account.d.ts +23 -0
  8. package/dist/account.d.ts.map +1 -0
  9. package/dist/account.js +54 -0
  10. package/dist/account.js.map +1 -0
  11. package/dist/derive-subject.d.ts +38 -0
  12. package/dist/derive-subject.d.ts.map +1 -0
  13. package/dist/derive-subject.js +137 -0
  14. package/dist/derive-subject.js.map +1 -0
  15. package/dist/factories.d.ts +30 -0
  16. package/dist/factories.d.ts.map +1 -0
  17. package/dist/factories.js +149 -0
  18. package/dist/factories.js.map +1 -0
  19. package/dist/index.d.ts +13 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +17 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/kms-viem-account.d.ts +4 -0
  24. package/dist/kms-viem-account.d.ts.map +1 -0
  25. package/dist/kms-viem-account.js +72 -0
  26. package/dist/kms-viem-account.js.map +1 -0
  27. package/dist/providers/aws.d.ts +13 -0
  28. package/dist/providers/aws.d.ts.map +1 -0
  29. package/dist/providers/aws.js +14 -0
  30. package/dist/providers/aws.js.map +1 -0
  31. package/dist/providers/gcp.d.ts +103 -0
  32. package/dist/providers/gcp.d.ts.map +1 -0
  33. package/dist/providers/gcp.js +490 -0
  34. package/dist/providers/gcp.js.map +1 -0
  35. package/dist/providers/local.d.ts +60 -0
  36. package/dist/providers/local.d.ts.map +1 -0
  37. package/dist/providers/local.js +246 -0
  38. package/dist/providers/local.js.map +1 -0
  39. package/dist/relay-only.d.ts +3 -0
  40. package/dist/relay-only.d.ts.map +1 -0
  41. package/dist/relay-only.js +19 -0
  42. package/dist/relay-only.js.map +1 -0
  43. package/dist/types.d.ts +134 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +70 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +84 -0
  48. package/spec.md +6 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agentic Trust Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @agenticprimitives/key-custody
2
+
3
+ Pluggable envelope encryption + signers + HMAC providers. Local-AES (dev only), AWS KMS, GCP KMS in v0.
4
+
5
+ **Narrower than you might expect:** session lifecycle is owned by `@agenticprimitives/delegation`. This package provides the crypto primitives; delegation's `SessionManager` wires them into the lifecycle.
6
+
7
+ See [`spec.md`](./spec.md) → [`specs/203-key-custody.md`](../../specs/203-key-custody.md).
8
+
9
+ ## Quick start
10
+
11
+ ```ts
12
+ import { buildKeyProvider, createKmsAccount, canonicalContextBytes } from '@agenticprimitives/key-custody';
13
+
14
+ const provider = buildKeyProvider({ backend: process.env.A2A_KMS_BACKEND });
15
+
16
+ // Generate a wrapped data key for envelope encryption
17
+ const { plaintextDataKey, encryptedDataKey, keyId, keyVersion } =
18
+ await provider.generateSessionDataKey({ aadContext: { /* caller-supplied */ } });
19
+
20
+ // Sign as a viem-compatible signer
21
+ const signer = buildSignerBackend({ backend: 'aws-kms' });
22
+ const kmsAccount = await createKmsAccount(signer);
23
+ ```
24
+
25
+ ## Production guard
26
+
27
+ `local-aes` refuses to boot when `NODE_ENV=production`. AWS and GCP backends have **no local fallback** — they fail-closed on outage. This is intentional.
28
+
29
+ ## Status
30
+
31
+ Pre-alpha. Spec stable.
package/dist/aad.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function canonicalContextBytes(ctx: Record<string, string>): Uint8Array;
2
+ //# sourceMappingURL=aad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aad.d.ts","sourceRoot":"","sources":["../src/aad.ts"],"names":[],"mappings":"AAMA,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,CAY7E"}
package/dist/aad.js ADDED
@@ -0,0 +1,19 @@
1
+ // AAD canonicalization. The caller supplies a Record<string, string>; we sort
2
+ // keys, JSON-encode each value, and produce a deterministic byte string used
3
+ // both as AES-GCM AAD and as KMS EncryptionContext. AAD-bound trip-wire:
4
+ // changing any field invalidates BOTH the AES-GCM tag (when the caller wraps
5
+ // it at the payload layer) AND the HKDF derivation here.
6
+ export function canonicalContextBytes(ctx) {
7
+ const keys = Object.keys(ctx).sort();
8
+ // Format: key1=value1;key2=value2 (values URI-encoded to disambiguate '=' and ';')
9
+ const parts = [];
10
+ for (const k of keys) {
11
+ const v = ctx[k];
12
+ if (typeof v !== 'string') {
13
+ throw new Error(`canonicalContextBytes: value for "${k}" must be a string`);
14
+ }
15
+ parts.push(`${k}=${encodeURIComponent(v)}`);
16
+ }
17
+ return new TextEncoder().encode(parts.join(';'));
18
+ }
19
+ //# sourceMappingURL=aad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aad.js","sourceRoot":"","sources":["../src/aad.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,6EAA6E;AAC7E,yDAAyD;AAEzD,MAAM,UAAU,qBAAqB,CAAC,GAA2B;IAC/D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,mFAAmF;IACnF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,oBAAoB,CAAC,CAAC;QAC9E,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type Hex, type Address } from 'viem';
2
+ import type { KmsAccountBackend } from './types';
3
+ interface KMSSignerShape {
4
+ readonly address: Address;
5
+ readonly keyId: string;
6
+ readonly provider: 'local-aes' | 'aws-kms' | 'gcp-kms';
7
+ signMessage(msg: string | {
8
+ raw: Hex;
9
+ }): Promise<Hex>;
10
+ signTypedData(args: {
11
+ domain: unknown;
12
+ types: unknown;
13
+ primaryType: string;
14
+ message: Record<string, unknown>;
15
+ }): Promise<Hex>;
16
+ }
17
+ export declare function createKmsAccount(backend: KmsAccountBackend, opts?: {
18
+ sessionId?: string;
19
+ chainId?: number;
20
+ provider?: 'local-aes' | 'aws-kms' | 'gcp-kms';
21
+ }): Promise<KMSSignerShape>;
22
+ export {};
23
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAIA,OAAO,EAAyC,KAAK,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,UAAU,cAAc;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IACvD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,aAAa,CAAC,IAAI,EAAE;QAClB,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAClB;AAWD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;CAAE,GAC9F,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
@@ -0,0 +1,54 @@
1
+ // createKmsAccount — viem adapter that turns a KmsAccountBackend into a
2
+ // KMSSigner conforming to connect-auth's Signer interface contract.
3
+ import { keccak_256 } from '@noble/hashes/sha3';
4
+ import { bytesToHex, hexToBytes, hashTypedData } from 'viem';
5
+ function eip191Digest(message) {
6
+ const bytes = typeof message === 'string' ? new TextEncoder().encode(message) : message;
7
+ const prefix = new TextEncoder().encode(`\x19Ethereum Signed Message:\n${bytes.length}`);
8
+ const combined = new Uint8Array(prefix.length + bytes.length);
9
+ combined.set(prefix, 0);
10
+ combined.set(bytes, prefix.length);
11
+ return keccak_256(combined);
12
+ }
13
+ export async function createKmsAccount(backend, opts) {
14
+ const address = await backend.getSignerAddress();
15
+ // Derive from the real backend (audit F-6) — an explicit opts.provider
16
+ // still wins, but the default is the backend's actual kind, never a
17
+ // misleading 'local-aes' for a production GCP/AWS signer.
18
+ const provider = opts?.provider ?? backend.provider;
19
+ return {
20
+ address,
21
+ keyId: `${provider}:${address.toLowerCase()}`,
22
+ provider,
23
+ async signMessage(msg) {
24
+ let digest;
25
+ if (typeof msg === 'string') {
26
+ digest = eip191Digest(msg);
27
+ }
28
+ else {
29
+ // raw hex — treat as already-hashed payload signed verbatim
30
+ digest = hexToBytes(msg.raw);
31
+ if (digest.length !== 32) {
32
+ // EIP-191 of raw bytes
33
+ digest = eip191Digest(digest);
34
+ }
35
+ }
36
+ const { signature } = await backend.signA2AAction({
37
+ digest,
38
+ auditContext: opts?.sessionId ? { sessionId: opts.sessionId } : undefined,
39
+ });
40
+ return bytesToHex(signature);
41
+ },
42
+ async signTypedData(args) {
43
+ // viem.hashTypedData computes the EIP-712 digest exactly the way wallets do.
44
+ const digestHex = hashTypedData(args);
45
+ const digest = hexToBytes(digestHex);
46
+ const { signature } = await backend.signA2AAction({
47
+ digest,
48
+ auditContext: opts?.sessionId ? { sessionId: opts.sessionId } : undefined,
49
+ });
50
+ return bytesToHex(signature);
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,oEAAoE;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAA0B,MAAM,MAAM,CAAC;AAgBrF,SAAS,YAAY,CAAC,OAA4B;IAChD,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACxF,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,iCAAiC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9D,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA0B,EAC1B,IAA+F;IAE/F,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC;IACjD,uEAAuE;IACvE,oEAAoE;IACpE,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAEpD,OAAO;QACL,OAAO;QACP,KAAK,EAAE,GAAG,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE;QAC7C,QAAQ;QAER,KAAK,CAAC,WAAW,CAAC,GAA0B;YAC1C,IAAI,MAAkB,CAAC;YACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,4DAA4D;gBAC5D,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;oBACzB,uBAAuB;oBACvB,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;YACD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC;gBAChD,MAAM;gBACN,YAAY,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;aAC1E,CAAC,CAAC;YACH,OAAO,UAAU,CAAC,SAAS,CAAQ,CAAC;QACtC,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,IAAI;YACtB,6EAA6E;YAC7E,MAAM,SAAS,GAAG,aAAa,CAAC,IAA2C,CAAC,CAAC;YAC7E,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC;gBAChD,MAAM;gBACN,YAAY,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;aAC1E,CAAC,CAAC;YACH,OAAO,UAAU,CAAC,SAAS,CAAQ,CAAC;QACtC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type Hex } from 'viem';
2
+ import type { BuildOpts, KmsAccountBackend } from './types';
3
+ /** The Google (OIDC) subject a custodian key is bound to. */
4
+ export interface SubjectId {
5
+ /** OIDC issuer, e.g. `https://accounts.google.com`. */
6
+ iss: string;
7
+ /** OIDC subject (stable per Google account). */
8
+ sub: string;
9
+ /** Bump to rotate a subject's custodian key (defaults to 0). */
10
+ rotation?: number;
11
+ }
12
+ export interface DeriveSubjectOpts extends BuildOpts {
13
+ subject: SubjectId;
14
+ }
15
+ /**
16
+ * The exact message the per-subject key is derived over. Each component is
17
+ * percent-encoded so the `:` separators are unforgeable (so `(iss,sub:x)` and
18
+ * `(iss:sub,x)` can never derive the same key).
19
+ */
20
+ export declare function subjectCanonicalMessage(subject: SubjectId): string;
21
+ /**
22
+ * Pure derivation: expand a 32-byte master into the per-subject secp256k1
23
+ * private key. Deterministic (same master + subject → same key); distinct
24
+ * subject/rotation → distinct key. Exported for unit tests.
25
+ */
26
+ export declare function deriveSubjectPrivateKeyHex(master: Uint8Array, subject: SubjectId): Hex;
27
+ /**
28
+ * Build the per-subject custodian signer. The returned backend's
29
+ * `getSignerAddress()` is `C_sub`; `signA2AAction` signs 32-byte userOp /
30
+ * EIP-712 digests with the derived key.
31
+ *
32
+ * local-aes: HKDF-derive the key, wrap it in `LocalSecp256k1Signer` (which
33
+ * enforces the production guard — refuses NODE_ENV=production unless
34
+ * `A2A_ALLOW_LOCAL_MASTER_KEY=true`).
35
+ * gcp-kms / aws-kms: not yet built — fail closed (spec 235 §10).
36
+ */
37
+ export declare function deriveSubjectSigner(opts: DeriveSubjectOpts): KmsAccountBackend;
38
+ //# sourceMappingURL=derive-subject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-subject.d.ts","sourceRoot":"","sources":["../src/derive-subject.ts"],"names":[],"mappings":"AA8BA,OAAO,EAA0B,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAc,MAAM,SAAS,CAAC;AAMxE,6DAA6D;AAC7D,MAAM,WAAW,SAAS;IACxB,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,OAAO,EAAE,SAAS,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAUlE;AAkBD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,GAAG,GAAG,CAetF;AAoCD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAa9E"}
@@ -0,0 +1,137 @@
1
+ // deriveSubjectSigner — a per-(iss,sub) custodian signer (spec 235).
2
+ //
3
+ // Given a Google subject `(iss, sub)`, derive a secp256k1 signing key bound to
4
+ // that subject from the server master, and return a `KmsAccountBackend` whose
5
+ // address is the per-subject custodian `C_sub`. demo-a2a uses `C_sub` as the
6
+ // SOLE custodian of the member's Smart Agent, so signing in with Google alone
7
+ // = full custody (the server signs on the member's behalf — see spec 235 §3
8
+ // for the trust model: master compromise = all Google members; per-subject
9
+ // keys bound only the single-leak blast radius).
10
+ //
11
+ // Divergence from smart-agent (spec 235 §2): smart-agent uses ONE shared
12
+ // bootstrap signer + a per-subject CREATE2 *salt*. We derive a per-subject
13
+ // signing KEY so the custodian address itself differs per member — a single
14
+ // leaked derived key cannot custody another member's agent.
15
+ //
16
+ // Derivation (local-aes, the demo backend):
17
+ // canonical = "kms-custodian:v1:<enc(iss)>:<enc(sub)>:<rotation>"
18
+ // okm = HKDF-SHA256(ikm = master, salt = "kms-custodian:v1", info = canonical, 32)
19
+ // priv = (be(okm) mod (n-1)) + 1 // uniform-ish in [1, n-1], never 0, always < n
20
+ // `enc()` is encodeURIComponent so a `:` inside iss/sub can't forge the field
21
+ // separators (key-isolation invariant — spec 235 §9.3).
22
+ //
23
+ // KMS backends (gcp-kms / aws-kms): NOT YET BUILT. The prod providers expose
24
+ // no `generateMac`, so there is no KMS-side per-subject seed today. We FAIL
25
+ // CLOSED (no silent fallback to local-aes — ADR-0013) and point at the
26
+ // follow-up (spec 235 §10: a per-subject KMS HMAC or asymmetric key).
27
+ import { hkdf } from '@noble/hashes/hkdf';
28
+ import { sha256 } from '@noble/hashes/sha256';
29
+ import { secp256k1 } from '@noble/curves/secp256k1';
30
+ import { hexToBytes, bytesToHex } from 'viem';
31
+ import { LocalSecp256k1Signer } from './providers/local';
32
+ const DERIVE_INFO_PREFIX = 'kms-custodian:v1';
33
+ const SECP256K1_N = secp256k1.CURVE.n;
34
+ /**
35
+ * The exact message the per-subject key is derived over. Each component is
36
+ * percent-encoded so the `:` separators are unforgeable (so `(iss,sub:x)` and
37
+ * `(iss:sub,x)` can never derive the same key).
38
+ */
39
+ export function subjectCanonicalMessage(subject) {
40
+ const iss = subject.iss?.trim();
41
+ const sub = subject.sub?.trim();
42
+ if (!iss)
43
+ throw new Error('deriveSubjectSigner: subject.iss is required');
44
+ if (!sub)
45
+ throw new Error('deriveSubjectSigner: subject.sub is required');
46
+ const rotation = subject.rotation ?? 0;
47
+ if (!Number.isInteger(rotation) || rotation < 0) {
48
+ throw new Error('deriveSubjectSigner: subject.rotation must be a non-negative integer');
49
+ }
50
+ return `${DERIVE_INFO_PREFIX}:${encodeURIComponent(iss)}:${encodeURIComponent(sub)}:${rotation}`;
51
+ }
52
+ function beBytesToBigInt(bytes) {
53
+ let n = 0n;
54
+ for (const b of bytes)
55
+ n = (n << 8n) | BigInt(b);
56
+ return n;
57
+ }
58
+ function bigIntTo32Bytes(n) {
59
+ const out = new Uint8Array(32);
60
+ let v = n;
61
+ for (let i = 31; i >= 0; i--) {
62
+ out[i] = Number(v & 0xffn);
63
+ v >>= 8n;
64
+ }
65
+ return out;
66
+ }
67
+ /**
68
+ * Pure derivation: expand a 32-byte master into the per-subject secp256k1
69
+ * private key. Deterministic (same master + subject → same key); distinct
70
+ * subject/rotation → distinct key. Exported for unit tests.
71
+ */
72
+ export function deriveSubjectPrivateKeyHex(master, subject) {
73
+ if (master.length < 32) {
74
+ throw new Error(`deriveSubjectSigner: master must be ≥ 32 bytes; got ${master.length}`);
75
+ }
76
+ const canonical = subjectCanonicalMessage(subject);
77
+ const okm = hkdf(sha256, master, new TextEncoder().encode(DERIVE_INFO_PREFIX), new TextEncoder().encode(canonical), 32);
78
+ // Map uniformly into [1, n-1]: (x mod (n-1)) + 1. Never 0, always < n.
79
+ const priv = (beBytesToBigInt(okm) % (SECP256K1_N - 1n)) + 1n;
80
+ return bytesToHex(bigIntTo32Bytes(priv));
81
+ }
82
+ function loadDerivationMaster(opts) {
83
+ // The master the subject keys are derived from. In the demo this is the
84
+ // server's master signing key (the server IS the trusted custodian for all
85
+ // Google members — spec 235 §3). `config.derivationSecretHex` lets a deploy
86
+ // point at a SEPARATE secret (master-key-separation invariant) without code
87
+ // changes; default is A2A_MASTER_PRIVATE_KEY.
88
+ const hex = opts.config?.derivationSecretHex ?? process.env.A2A_MASTER_PRIVATE_KEY;
89
+ if (!hex) {
90
+ throw new Error('deriveSubjectSigner (local-aes): A2A_MASTER_PRIVATE_KEY (or config.derivationSecretHex) ' +
91
+ 'is required to derive per-subject custodian keys.');
92
+ }
93
+ const cleaned = hex.startsWith('0x') ? hex : `0x${hex}`;
94
+ const bytes = hexToBytes(cleaned);
95
+ if (bytes.length < 32) {
96
+ throw new Error(`deriveSubjectSigner: derivation master must be ≥ 32 bytes; got ${bytes.length}`);
97
+ }
98
+ return bytes;
99
+ }
100
+ function backendOf(opts) {
101
+ if (opts.backend)
102
+ return opts.backend;
103
+ try {
104
+ const env = process.env?.A2A_KMS_BACKEND;
105
+ if (env)
106
+ return env;
107
+ }
108
+ catch {
109
+ /* Workers may throw on process access */
110
+ }
111
+ // No silent local default here — deriving custody keys is security-sensitive.
112
+ // The caller (demo-a2a) sets A2A_KMS_BACKEND explicitly.
113
+ return 'local-aes';
114
+ }
115
+ /**
116
+ * Build the per-subject custodian signer. The returned backend's
117
+ * `getSignerAddress()` is `C_sub`; `signA2AAction` signs 32-byte userOp /
118
+ * EIP-712 digests with the derived key.
119
+ *
120
+ * local-aes: HKDF-derive the key, wrap it in `LocalSecp256k1Signer` (which
121
+ * enforces the production guard — refuses NODE_ENV=production unless
122
+ * `A2A_ALLOW_LOCAL_MASTER_KEY=true`).
123
+ * gcp-kms / aws-kms: not yet built — fail closed (spec 235 §10).
124
+ */
125
+ export function deriveSubjectSigner(opts) {
126
+ const backend = backendOf(opts);
127
+ if (backend === 'local-aes') {
128
+ const master = loadDerivationMaster(opts);
129
+ const privateKeyHex = deriveSubjectPrivateKeyHex(master, opts.subject);
130
+ return new LocalSecp256k1Signer({ privateKeyHex, auditSink: opts.auditSink });
131
+ }
132
+ throw new Error(`deriveSubjectSigner: per-subject derivation is not yet implemented for backend "${backend}". ` +
133
+ `The KMS providers expose no per-subject MAC/key today. Use local-aes for the demo, or build ` +
134
+ `the production path per spec 235 §10 (a per-subject KMS HMAC or asymmetric key). ` +
135
+ `There is no silent fallback to local-aes (ADR-0013).`);
136
+ }
137
+ //# sourceMappingURL=derive-subject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-subject.js","sourceRoot":"","sources":["../src/derive-subject.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { A2AKeyProvider, BuildOpts, KmsAccountBackend } from './types';
2
+ export declare function buildKeyProvider(opts: BuildOpts): A2AKeyProvider;
3
+ export declare function buildSignerBackend(opts: BuildOpts): KmsAccountBackend;
4
+ /**
5
+ * @deprecated Renamed in H7-B.1 to make the lie loud. Use
6
+ * `buildToolExecutorBackendNoIsolation` (and read its JSDoc before you do).
7
+ * Closure of PKG-KEY-CUSTODY-001 / EXT-020.
8
+ */
9
+ export declare function buildToolExecutorBackend(_toolId: string, _opts: BuildOpts): KmsAccountBackend;
10
+ /**
11
+ * **NO per-tool isolation.** Returns the master signer (or the resolved KMS
12
+ * backend) regardless of `toolId`. This is a deliberately ugly name so the
13
+ * caller cannot pretend it's "per-tool" — that capability is not yet built.
14
+ *
15
+ * Use cases (all transitional):
16
+ * - test fixtures
17
+ * - dev-mode demos where a single master signer is acceptable
18
+ * - operator opt-in while per-tool HKDF lands
19
+ *
20
+ * Refuses to run unless `AP_ALLOW_NO_TOOL_ISOLATION=true` in env (or
21
+ * `opts.developmentMode === true` / `opts.environment === 'development'`),
22
+ * AND throws in production environments regardless of the opt-out flag.
23
+ *
24
+ * Closure of PKG-KEY-CUSTODY-001 / EXT-020 / CT-6.
25
+ *
26
+ * For per-OIDC-subject isolation, use {@link deriveSubjectSigner} (spec 235).
27
+ */
28
+ export declare function buildToolExecutorBackendNoIsolation(toolId: string, opts: BuildOpts): KmsAccountBackend;
29
+ export declare function buildMacProvider(audience: string, opts: BuildOpts): A2AKeyProvider;
30
+ //# sourceMappingURL=factories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../src/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAAc,MAAM,SAAS,CAAC;AAwDxF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAYhE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,CAgBrE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAU7F;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,GACd,iBAAiB,CAyBnB;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,cAAc,CAMlF"}
@@ -0,0 +1,149 @@
1
+ import { LocalAesProvider, LocalSecp256k1Signer } from './providers/local';
2
+ import { AwsKmsProvider, AwsKmsSigner } from './providers/aws';
3
+ import { GcpKmsProvider, GcpKmsSigner } from './providers/gcp';
4
+ /**
5
+ * Resolve effective environment for production-default gates (audit H1).
6
+ * 1. Explicit `opts.environment` wins.
7
+ * 2. `developmentMode: true` shorthand → 'development'.
8
+ * 3. `process.env.NODE_ENV` if readable.
9
+ * 4. Default to 'production' — safe-by-default when the runtime is
10
+ * ambiguous. Consumers who want a permissive default MUST opt out.
11
+ */
12
+ function inferEnvironment(opts) {
13
+ if (opts.environment)
14
+ return opts.environment;
15
+ if (opts.developmentMode === true)
16
+ return 'development';
17
+ try {
18
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV) {
19
+ return process.env.NODE_ENV === 'production' ? 'production' : 'development';
20
+ }
21
+ }
22
+ catch {
23
+ /* SES / Workers may throw on process access */
24
+ }
25
+ return 'production';
26
+ }
27
+ /**
28
+ * Backend selection (audit H1). Required-by-default:
29
+ * - `opts.backend` always wins.
30
+ * - Fall back to A2A_KMS_BACKEND env.
31
+ * - In production with neither, THROW. The previous silent fallback
32
+ * to `local-aes` was a footgun — production consumers should fail
33
+ * at construction time, not boot a dev-mode signer.
34
+ * - In development with neither, default to `local-aes` for ergonomics.
35
+ */
36
+ function backendOrEnv(opts) {
37
+ if (opts.backend)
38
+ return opts.backend;
39
+ const envBackend = (() => {
40
+ try {
41
+ return process.env?.A2A_KMS_BACKEND;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ })();
47
+ if (envBackend)
48
+ return envBackend;
49
+ if (inferEnvironment(opts) === 'production') {
50
+ throw new Error('[key-custody] No backend specified for production. Pass `opts.backend` ' +
51
+ '(`aws-kms` / `gcp-kms` for real deploys; `local-aes` for dev) or set ' +
52
+ 'the A2A_KMS_BACKEND env var. There is no implicit fallback in production — ' +
53
+ 'pass `developmentMode: true` to opt into the dev default.');
54
+ }
55
+ return 'local-aes';
56
+ }
57
+ export function buildKeyProvider(opts) {
58
+ switch (backendOrEnv(opts)) {
59
+ case 'local-aes':
60
+ return new LocalAesProvider({ sessionSecretHex: opts.config?.sessionSecretHex });
61
+ case 'aws-kms':
62
+ return new AwsKmsProvider();
63
+ case 'gcp-kms':
64
+ return new GcpKmsProvider({
65
+ cryptoKeyName: opts.config?.cryptoKeyName,
66
+ serviceAccountJson: opts.config?.serviceAccountJson,
67
+ });
68
+ }
69
+ }
70
+ export function buildSignerBackend(opts) {
71
+ switch (backendOrEnv(opts)) {
72
+ case 'local-aes':
73
+ return new LocalSecp256k1Signer({
74
+ privateKeyHex: opts.config?.privateKeyHex,
75
+ auditSink: opts.auditSink,
76
+ });
77
+ case 'aws-kms':
78
+ return new AwsKmsSigner();
79
+ case 'gcp-kms':
80
+ return new GcpKmsSigner({
81
+ cryptoKeyVersionName: opts.config?.cryptoKeyVersionName,
82
+ serviceAccountJson: opts.config?.serviceAccountJson,
83
+ auditSink: opts.auditSink,
84
+ });
85
+ }
86
+ }
87
+ /**
88
+ * @deprecated Renamed in H7-B.1 to make the lie loud. Use
89
+ * `buildToolExecutorBackendNoIsolation` (and read its JSDoc before you do).
90
+ * Closure of PKG-KEY-CUSTODY-001 / EXT-020.
91
+ */
92
+ export function buildToolExecutorBackend(_toolId, _opts) {
93
+ throw new Error('[key-custody] buildToolExecutorBackend was removed in H7-B.1 (PKG-KEY-CUSTODY-001 closure). ' +
94
+ 'The function ignored toolId and returned the master signer — every call signed with the ' +
95
+ 'master key, which contradicted the JSDoc promise of per-tool isolation. ' +
96
+ 'If you actually want master-signer fallback while per-tool HKDF is being built, use ' +
97
+ '`buildToolExecutorBackendNoIsolation(toolId, opts)` AND set ' +
98
+ '`AP_ALLOW_NO_TOOL_ISOLATION=true` (refused in production). ' +
99
+ 'For per-OIDC-subject isolation, use `deriveSubjectSigner` (spec 235).');
100
+ }
101
+ /**
102
+ * **NO per-tool isolation.** Returns the master signer (or the resolved KMS
103
+ * backend) regardless of `toolId`. This is a deliberately ugly name so the
104
+ * caller cannot pretend it's "per-tool" — that capability is not yet built.
105
+ *
106
+ * Use cases (all transitional):
107
+ * - test fixtures
108
+ * - dev-mode demos where a single master signer is acceptable
109
+ * - operator opt-in while per-tool HKDF lands
110
+ *
111
+ * Refuses to run unless `AP_ALLOW_NO_TOOL_ISOLATION=true` in env (or
112
+ * `opts.developmentMode === true` / `opts.environment === 'development'`),
113
+ * AND throws in production environments regardless of the opt-out flag.
114
+ *
115
+ * Closure of PKG-KEY-CUSTODY-001 / EXT-020 / CT-6.
116
+ *
117
+ * For per-OIDC-subject isolation, use {@link deriveSubjectSigner} (spec 235).
118
+ */
119
+ export function buildToolExecutorBackendNoIsolation(toolId, opts) {
120
+ void toolId;
121
+ const env = inferEnvironment(opts);
122
+ if (env === 'production') {
123
+ throw new Error('[key-custody] buildToolExecutorBackendNoIsolation is refused in production. ' +
124
+ 'Per-tool isolation is not implemented; the function would return the master signer. ' +
125
+ 'Build the per-tool HKDF path (mirror `deriveSubjectSigner` from spec 235) before ' +
126
+ 'wiring tool executors in production.');
127
+ }
128
+ let allowFlag = false;
129
+ try {
130
+ allowFlag = process.env?.AP_ALLOW_NO_TOOL_ISOLATION === 'true';
131
+ }
132
+ catch {
133
+ /* SES / Workers may throw */
134
+ }
135
+ if (!allowFlag) {
136
+ throw new Error('[key-custody] buildToolExecutorBackendNoIsolation requires opt-in. ' +
137
+ 'Set AP_ALLOW_NO_TOOL_ISOLATION=true (and ensure you are not in production). ' +
138
+ 'This signer has NO per-tool isolation — every toolId resolves to the master signer.');
139
+ }
140
+ return buildSignerBackend(opts);
141
+ }
142
+ export function buildMacProvider(audience, opts) {
143
+ // Same backend selector; provider returns generateMac.
144
+ // The audience is consumed by generateMac at call time; the provider itself
145
+ // doesn't bind to one audience.
146
+ void audience;
147
+ return buildKeyProvider(opts);
148
+ }
149
+ //# sourceMappingURL=factories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factories.js","sourceRoot":"","sources":["../src/factories.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Address, Hex } from '@agenticprimitives/types';
2
+ export type { Address, Hex };
3
+ export type { A2AKeyProvider, KmsAccountBackend, BuildOpts, KmsBackend, Secret } from './types';
4
+ export { loadSecret, loadSecretFromEnv, unwrapSecret, isSecret } from './types';
5
+ export { buildKeyProvider, buildSignerBackend, buildToolExecutorBackend, buildToolExecutorBackendNoIsolation, buildMacProvider, } from './factories';
6
+ export { deriveSubjectSigner, subjectCanonicalMessage, type SubjectId, type DeriveSubjectOpts, } from './derive-subject';
7
+ export { getRelayOnlySigner } from './relay-only';
8
+ export { createKmsAccount } from './account';
9
+ export { canonicalContextBytes } from './aad';
10
+ export { LocalAesProvider, LocalSecp256k1Signer } from './providers/local';
11
+ export { AwsKmsProvider, AwsKmsSigner } from './providers/aws';
12
+ export { GcpKmsProvider, GcpKmsSigner } from './providers/gcp';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAE7D,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAC7B,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,mCAAmC,EACnC,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAKrB,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // @agenticprimitives/key-custody — public API
2
+ //
3
+ // See ../../specs/203-key-custody.md for the full contract.
4
+ export { loadSecret, loadSecretFromEnv, unwrapSecret, isSecret } from './types';
5
+ export { buildKeyProvider, buildSignerBackend, buildToolExecutorBackend, buildToolExecutorBackendNoIsolation, buildMacProvider, } from './factories';
6
+ // `deriveSubjectPrivateKeyHex` is intentionally NOT re-exported here — it returns
7
+ // a per-subject raw private key (security-sensitive). It stays exported from
8
+ // `./derive-subject` for in-package unit tests but is not part of the public API.
9
+ // See `capability.manifest.json:publicExports` (audit row ARCH-006 / PKG-KEY-CUSTODY-002 closure).
10
+ export { deriveSubjectSigner, subjectCanonicalMessage, } from './derive-subject';
11
+ export { getRelayOnlySigner } from './relay-only';
12
+ export { createKmsAccount } from './account';
13
+ export { canonicalContextBytes } from './aad';
14
+ export { LocalAesProvider, LocalSecp256k1Signer } from './providers/local';
15
+ export { AwsKmsProvider, AwsKmsSigner } from './providers/aws';
16
+ export { GcpKmsProvider, GcpKmsSigner } from './providers/gcp';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,4DAA4D;AAM5D,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,mCAAmC,EACnC,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,kFAAkF;AAClF,6EAA6E;AAC7E,kFAAkF;AAClF,mGAAmG;AACnG,OAAO,EACL,mBAAmB,EACnB,uBAAuB,GAGxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type LocalAccount } from 'viem';
2
+ import type { KmsAccountBackend } from './types';
3
+ export declare function createKmsViemAccount(backend: KmsAccountBackend): Promise<LocalAccount>;
4
+ //# sourceMappingURL=kms-viem-account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kms-viem-account.d.ts","sourceRoot":"","sources":["../src/kms-viem-account.ts"],"names":[],"mappings":"AAqBA,OAAO,EASL,KAAK,YAAY,EAElB,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA0BjD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAwC5F"}