@agenticprimitives/key-custody 0.1.0-alpha.3 → 1.0.0-alpha.11
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.
- package/README.md +22 -5
- package/bin/ap-provision-gcp.mjs +91 -0
- package/dist/account.d.ts +1 -1
- package/dist/account.d.ts.map +1 -1
- package/dist/account.js +1 -1
- package/dist/account.js.map +1 -1
- package/dist/derive-subject.d.ts +1 -1
- package/dist/derive-subject.d.ts.map +1 -1
- package/dist/derive-subject.js +5 -5
- package/dist/derive-subject.js.map +1 -1
- package/dist/factories.d.ts +27 -1
- package/dist/factories.d.ts.map +1 -1
- package/dist/factories.js +29 -5
- package/dist/factories.js.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -9
- package/dist/index.js.map +1 -1
- package/dist/kms/gcp-transport.d.ts +36 -0
- package/dist/kms/gcp-transport.d.ts.map +1 -0
- package/dist/kms/gcp-transport.js +114 -0
- package/dist/kms/gcp-transport.js.map +1 -0
- package/dist/kms/key-map.d.ts +13 -0
- package/dist/kms/key-map.d.ts.map +1 -0
- package/dist/kms/key-map.js +65 -0
- package/dist/kms/key-map.js.map +1 -0
- package/dist/kms/kms-core.d.ts +4 -0
- package/dist/kms/kms-core.d.ts.map +1 -0
- package/dist/kms/kms-core.js +14 -0
- package/dist/kms/kms-core.js.map +1 -0
- package/dist/kms/provision-gcp.d.ts +89 -0
- package/dist/kms/provision-gcp.d.ts.map +1 -0
- package/dist/kms/provision-gcp.js +229 -0
- package/dist/kms/provision-gcp.js.map +1 -0
- package/dist/kms/secp256k1-core.d.ts +46 -0
- package/dist/kms/secp256k1-core.d.ts.map +1 -0
- package/dist/kms/secp256k1-core.js +209 -0
- package/dist/kms/secp256k1-core.js.map +1 -0
- package/dist/kms-viem-account.d.ts +1 -1
- package/dist/kms-viem-account.d.ts.map +1 -1
- package/dist/providers/aws.d.ts +4 -1
- package/dist/providers/aws.d.ts.map +1 -1
- package/dist/providers/aws.js +17 -7
- package/dist/providers/aws.js.map +1 -1
- package/dist/providers/gcp.d.ts +23 -36
- package/dist/providers/gcp.d.ts.map +1 -1
- package/dist/providers/gcp.js +89 -340
- package/dist/providers/gcp.js.map +1 -1
- package/dist/providers/local.d.ts +4 -4
- package/dist/providers/local.d.ts.map +1 -1
- package/dist/providers/local.js +17 -7
- package/dist/providers/local.js.map +1 -1
- package/dist/relay-only.d.ts +1 -1
- package/dist/relay-only.d.ts.map +1 -1
- package/dist/relay-only.js +1 -1
- package/dist/relay-only.js.map +1 -1
- package/dist/relayer-account.d.ts +44 -0
- package/dist/relayer-account.d.ts.map +1 -0
- package/dist/relayer-account.js +146 -0
- package/dist/relayer-account.js.map +1 -0
- package/dist/spend-capped-account.d.ts +71 -0
- package/dist/spend-capped-account.d.ts.map +1 -0
- package/dist/spend-capped-account.js +181 -0
- package/dist/spend-capped-account.js.map +1 -0
- package/package.json +40 -9
package/README.md
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# @agenticprimitives/key-custody
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Custody is not authority.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
In this stack, keys sign — they do not decide. Authority lives in delegations and custody policy; this package is the cryptographic floor underneath them: pluggable envelope encryption, KMS-backed signers, and HMAC providers behind one `A2AKeyProvider` interface. Local-AES and a local secp256k1 signer for development, AWS KMS and GCP KMS for real deployments. Because a signer here is just a signer, a compromised session key is a revocation event, not an identity loss — the Smart Agent address and its custody policy sit above the key, not inside it.
|
|
6
|
+
|
|
7
|
+
**Narrower than you might expect, on purpose:** session lifecycle is owned by `@agenticprimitives/delegation`. This package provides the crypto primitives; delegation's `SessionManager` wires them ([ADR-0002](../../docs/architecture/decisions/0002-session-lifecycle-in-delegation.md)). Payloads are opaque bytes with caller-supplied AAD — bound identically into AES-GCM AAD and KMS EncryptionContext, so tampering trips both.
|
|
8
|
+
|
|
9
|
+
> Part of [agenticprimitives](../../README.md) — the trust substrate for the agent economy: one canonical Smart Agent identity with custody, delegation, naming, credentials, and audit evidence designed as one system.
|
|
6
10
|
|
|
7
11
|
See [`spec.md`](./spec.md) → [`specs/203-key-custody.md`](../../specs/203-key-custody.md).
|
|
8
12
|
|
|
9
13
|
## Quick start
|
|
10
14
|
|
|
11
15
|
```ts
|
|
12
|
-
import { buildKeyProvider, createKmsAccount, canonicalContextBytes } from '@agenticprimitives/key-custody';
|
|
16
|
+
import { buildKeyProvider, buildSignerBackend, createKmsAccount, canonicalContextBytes } from '@agenticprimitives/key-custody';
|
|
13
17
|
|
|
14
18
|
const provider = buildKeyProvider({ backend: process.env.A2A_KMS_BACKEND });
|
|
15
19
|
|
|
@@ -22,10 +26,23 @@ const signer = buildSignerBackend({ backend: 'aws-kms' });
|
|
|
22
26
|
const kmsAccount = await createKmsAccount(signer);
|
|
23
27
|
```
|
|
24
28
|
|
|
29
|
+
Beyond the basics: per-OIDC-subject signer derivation via HKDF (`deriveSubjectSigner`, [spec 235](../../specs/235-google-kms-custody.md)), a relay-only master signer that throws on any signing call (`getRelayOnlySigner`), and HMAC providers under the `/mac` subpath. Every decrypt and signing operation emits an audit row with `keyVersion` and a hashed session ID — the raw session ID is never logged.
|
|
30
|
+
|
|
25
31
|
## Production guard
|
|
26
32
|
|
|
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.
|
|
33
|
+
`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: a key-custody layer that silently downgrades to a weaker backend is not a custody layer.
|
|
34
|
+
|
|
35
|
+
## How it's different
|
|
36
|
+
|
|
37
|
+
Turnkey and Fireblocks are strong custody products: managed key infrastructure with their own policy engines, consoles, and trust models. They are also where your authority model ends up living — the policy that governs a key is the vendor's policy, expressed in the vendor's terms. This package takes the opposite position: KMS backends are interchangeable plumbing (`buildKeyProvider({ backend })`), and the authority model lives one layer up, in on-chain custody policy and EIP-712 delegations that the rest of the substrate enforces and audits. You keep cloud-KMS-grade key protection without making a vendor's policy engine your source of truth for who may do what.
|
|
38
|
+
|
|
39
|
+
## Validate
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pnpm --filter @agenticprimitives/key-custody typecheck
|
|
43
|
+
pnpm --filter @agenticprimitives/key-custody test
|
|
44
|
+
```
|
|
28
45
|
|
|
29
46
|
## Status
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
Testnet/pilot-ready. Production launch is gated on the public checklist in the root README — including third-party contract audit and governance key rotation. Track every security finding live in [`docs/audits/findings.yaml`](../../docs/audits/findings.yaml).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ap-provision-gcp — provision GCP Cloud KMS secp256k1 signing keys for a set of
|
|
3
|
+
// signing identities, grant the runtime service account roles/cloudkms.signer
|
|
4
|
+
// per key, and print the identity → key-version map + derived EVM addresses
|
|
5
|
+
// (spec 276 KCS-D3). Thin Node wrapper over @agenticprimitives/key-custody/provision-gcp.
|
|
6
|
+
//
|
|
7
|
+
// ap-provision-gcp \
|
|
8
|
+
// --project my-proj --location us-east1 --keyring my-ring \
|
|
9
|
+
// --service-account runtime@my-proj.iam.gserviceaccount.com \
|
|
10
|
+
// --identities signer-a,signer-b [--protection HSM] [--dry-run]
|
|
11
|
+
//
|
|
12
|
+
// --dry-run prints the gcloud steps without executing. Requires `gcloud` on PATH
|
|
13
|
+
// (authenticated) for a real run.
|
|
14
|
+
import { execFileSync } from 'node:child_process';
|
|
15
|
+
import { planGcpProvision, executeGcpProvision } from '../dist/kms/provision-gcp.js';
|
|
16
|
+
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
const out = {};
|
|
19
|
+
for (let i = 0; i < argv.length; i++) {
|
|
20
|
+
const a = argv[i];
|
|
21
|
+
if (!a.startsWith('--')) continue;
|
|
22
|
+
const key = a.slice(2);
|
|
23
|
+
if (key === 'dry-run') { out['dry-run'] = true; continue; }
|
|
24
|
+
out[key] = argv[++i];
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function gcloud(argv) {
|
|
30
|
+
return execFileSync('gcloud', argv, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const args = parseArgs(process.argv.slice(2));
|
|
34
|
+
const required = ['project', 'location', 'keyring', 'service-account', 'identities'];
|
|
35
|
+
const missing = required.filter((k) => !args[k]);
|
|
36
|
+
if (missing.length) {
|
|
37
|
+
console.error(`ap-provision-gcp: missing required flag(s): ${missing.map((m) => '--' + m).join(', ')}`);
|
|
38
|
+
console.error('Usage: ap-provision-gcp --project <p> --location <l> --keyring <r> --service-account <email> --identities a,b[,c] [--protection HSM|SOFTWARE] [--dry-run]');
|
|
39
|
+
process.exit(2);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const plan = {
|
|
43
|
+
project: args.project,
|
|
44
|
+
location: args.location,
|
|
45
|
+
keyRing: args.keyring,
|
|
46
|
+
identities: String(args.identities).split(',').map((s) => s.trim()).filter(Boolean),
|
|
47
|
+
runtimeServiceAccount: args['service-account'],
|
|
48
|
+
protectionLevel: args.protection ?? 'HSM',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (args['dry-run']) {
|
|
52
|
+
console.error(`# Dry run — ${plan.identities.length} identity/identities. The following gcloud commands would run:\n`);
|
|
53
|
+
for (const step of planGcpProvision(plan)) {
|
|
54
|
+
console.log(`# ${step.description}`);
|
|
55
|
+
console.log(`gcloud ${step.argv.join(' ')}`);
|
|
56
|
+
}
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const executor = {
|
|
61
|
+
async run(step) {
|
|
62
|
+
try {
|
|
63
|
+
const stdout = gcloud(step.argv);
|
|
64
|
+
return { stdout };
|
|
65
|
+
} catch (e) {
|
|
66
|
+
const stderr = String(e?.stderr ?? e?.message ?? '');
|
|
67
|
+
if (/ALREADY_EXISTS|already exists/i.test(stderr)) return { stdout: '', alreadyExists: true };
|
|
68
|
+
throw new Error(`gcloud ${step.argv.join(' ')} failed:\n${stderr}`);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
async getPublicKeyPem(cryptoKeyVersionName) {
|
|
72
|
+
// .../cryptoKeys/<key>/cryptoKeyVersions/<n>
|
|
73
|
+
const m = /cryptoKeys\/([^/]+)\/cryptoKeyVersions\/(\d+)$/.exec(cryptoKeyVersionName);
|
|
74
|
+
if (!m) throw new Error(`unexpected key version name: ${cryptoKeyVersionName}`);
|
|
75
|
+
return gcloud([
|
|
76
|
+
'kms', 'keys', 'versions', 'get-public-key', m[2],
|
|
77
|
+
'--key', m[1], '--keyring', plan.keyRing, '--location', plan.location, '--project', plan.project,
|
|
78
|
+
]);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
executeGcpProvision(plan, executor)
|
|
83
|
+
.then((result) => {
|
|
84
|
+
console.error(`\n# Provisioned. ${result.alreadyExisted.length ? `Skipped (already existed): ${result.alreadyExisted.join(', ')}` : 'All resources created.'}`);
|
|
85
|
+
console.error('# Verify these addresses match expectations BEFORE wiring env:\n');
|
|
86
|
+
console.log(JSON.stringify({ keyMap: result.keyMap, addresses: result.addresses, granted: result.granted }, null, 2));
|
|
87
|
+
})
|
|
88
|
+
.catch((e) => {
|
|
89
|
+
console.error(`ap-provision-gcp failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
package/dist/account.d.ts
CHANGED
package/dist/account.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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,YAAY,CAAC;AAEpD,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"}
|
package/dist/account.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// createKmsAccount — viem adapter that turns a KmsAccountBackend into a
|
|
2
2
|
// KMSSigner conforming to connect-auth's Signer interface contract.
|
|
3
|
-
import { keccak_256 } from '@noble/hashes/sha3';
|
|
3
|
+
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
4
4
|
import { bytesToHex, hexToBytes, hashTypedData } from 'viem';
|
|
5
5
|
function eip191Digest(message) {
|
|
6
6
|
const bytes = typeof message === 'string' ? new TextEncoder().encode(message) : message;
|
package/dist/account.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,oEAAoE;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,oEAAoE;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,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"}
|
package/dist/derive-subject.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Hex } from 'viem';
|
|
2
|
-
import type { BuildOpts, KmsAccountBackend } from './types';
|
|
2
|
+
import type { BuildOpts, KmsAccountBackend } from './types.js';
|
|
3
3
|
/** The Google (OIDC) subject a custodian key is bound to. */
|
|
4
4
|
export interface SubjectId {
|
|
5
5
|
/** OIDC issuer, e.g. `https://accounts.google.com`. */
|
|
@@ -1 +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,
|
|
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,YAAY,CAAC;AAM3E,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"}
|
package/dist/derive-subject.js
CHANGED
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
// no `generateMac`, so there is no KMS-side per-subject seed today. We FAIL
|
|
25
25
|
// CLOSED (no silent fallback to local-aes — ADR-0013) and point at the
|
|
26
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/
|
|
29
|
-
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
27
|
+
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
28
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
29
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
30
30
|
import { hexToBytes, bytesToHex } from 'viem';
|
|
31
|
-
import { LocalSecp256k1Signer } from './providers/local';
|
|
31
|
+
import { LocalSecp256k1Signer } from './providers/local.js';
|
|
32
32
|
const DERIVE_INFO_PREFIX = 'kms-custodian:v1';
|
|
33
|
-
const SECP256K1_N = secp256k1.
|
|
33
|
+
const SECP256K1_N = secp256k1.Point.Fn.ORDER;
|
|
34
34
|
/**
|
|
35
35
|
* The exact message the per-subject key is derived over. Each component is
|
|
36
36
|
* percent-encoded so the `:` separators are unforgeable (so `(iss,sub:x)` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-subject.js","sourceRoot":"","sources":["../src/derive-subject.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,iDAAiD;AACjD,EAAE;AACF,yEAAyE;AACzE,2EAA2E;AAC3E,4EAA4E;AAC5E,4DAA4D;AAC5D,EAAE;AACF,4CAA4C;AAC5C,oEAAoE;AACpE,2FAA2F;AAC3F,4FAA4F;AAC5F,8EAA8E;AAC9E,wDAAwD;AACxD,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,uEAAuE;AACvE,sEAAsE;AAEtE,OAAO,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"derive-subject.js","sourceRoot":"","sources":["../src/derive-subject.ts"],"names":[],"mappings":"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"}
|
package/dist/factories.d.ts
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuditSink } from '@agenticprimitives/audit';
|
|
2
|
+
import type { A2AKeyProvider, BuildOpts, KmsAccountBackend } from './types.js';
|
|
2
3
|
export declare function buildKeyProvider(opts: BuildOpts): A2AKeyProvider;
|
|
4
|
+
/**
|
|
5
|
+
* Per-person vault KEK selection (spec 278 P3 / VKB-D1, VKB-D2). Returns the
|
|
6
|
+
* envelope provider a vault host should use to wrap/unwrap a SPECIFIC person's
|
|
7
|
+
* vault objects.
|
|
8
|
+
*
|
|
9
|
+
* Fail-closed by design: a person-owned vault MUST resolve to a per-person KEK
|
|
10
|
+
* (`kmsKeyRef`, from that person's `VaultKeyBinding` — provisioned via spec 276
|
|
11
|
+
* `provision-gcp`). There is NO global key for person data. The local-aes path
|
|
12
|
+
* is permitted ONLY for anonymous/seeded test fixtures and ONLY when the caller
|
|
13
|
+
* explicitly opts in (`allowFixtureKey: true`) — never for a real person vault.
|
|
14
|
+
* With neither a `kmsKeyRef` nor an explicit fixture allowance, this THROWS.
|
|
15
|
+
*/
|
|
16
|
+
export interface SelectVaultKeyProviderOpts {
|
|
17
|
+
/** The person's KEK resource name (from their VaultKeyBinding). Selects a per-person GCP KEK. */
|
|
18
|
+
kmsKeyRef?: string;
|
|
19
|
+
/** Service-account JSON for the GCP KEK (required with `kmsKeyRef`). */
|
|
20
|
+
serviceAccountJson?: string;
|
|
21
|
+
/** Audit sink → envelope wrap/unwrap emit `key-custody.envelope.*`. */
|
|
22
|
+
auditSink?: AuditSink;
|
|
23
|
+
/** Set ONLY for anonymous/seeded fixtures; uses local-aes. Never for a real person vault. */
|
|
24
|
+
allowFixtureKey?: boolean;
|
|
25
|
+
/** Fixture master key (local-aes) — used only when `allowFixtureKey` is true. */
|
|
26
|
+
fixtureKeyHex?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function selectVaultKeyProvider(opts: SelectVaultKeyProviderOpts): A2AKeyProvider;
|
|
3
29
|
export declare function buildSignerBackend(opts: BuildOpts): KmsAccountBackend;
|
|
4
30
|
/**
|
|
5
31
|
* @deprecated Renamed in H7-B.1 to make the lie loud. Use
|
package/dist/factories.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../src/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAAc,MAAM,YAAY,CAAC;AAyD3F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,CAehE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,0BAA0B;IACzC,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uEAAuE;IACvE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,6FAA6F;IAC7F,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,0BAA0B,GAAG,cAAc,CAqBvF;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"}
|
package/dist/factories.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LocalAesProvider, LocalSecp256k1Signer } from './providers/local';
|
|
2
|
-
import { AwsKmsProvider, AwsKmsSigner } from './providers/aws';
|
|
3
|
-
import { GcpKmsProvider, GcpKmsSigner } from './providers/gcp';
|
|
1
|
+
import { LocalAesProvider, LocalSecp256k1Signer } from './providers/local.js';
|
|
2
|
+
import { AwsKmsProvider, AwsKmsSigner } from './providers/aws.js';
|
|
3
|
+
import { GcpKmsProvider, GcpKmsSigner } from './providers/gcp.js';
|
|
4
4
|
/**
|
|
5
5
|
* Resolve effective environment for production-default gates (audit H1).
|
|
6
6
|
* 1. Explicit `opts.environment` wins.
|
|
@@ -48,9 +48,10 @@ function backendOrEnv(opts) {
|
|
|
48
48
|
return envBackend;
|
|
49
49
|
if (inferEnvironment(opts) === 'production') {
|
|
50
50
|
throw new Error('[key-custody] No backend specified for production. Pass `opts.backend` ' +
|
|
51
|
-
'(`
|
|
51
|
+
'(`gcp-kms` for real deploys; `local-aes` for dev) or set ' +
|
|
52
52
|
'the A2A_KMS_BACKEND env var. There is no implicit fallback in production — ' +
|
|
53
|
-
'pass `developmentMode: true` to opt into the dev default.'
|
|
53
|
+
'pass `developmentMode: true` to opt into the dev default. ' +
|
|
54
|
+
'(`aws-kms` is reserved but NOT implemented — selecting it fails fast.)');
|
|
54
55
|
}
|
|
55
56
|
return 'local-aes';
|
|
56
57
|
}
|
|
@@ -64,9 +65,32 @@ export function buildKeyProvider(opts) {
|
|
|
64
65
|
return new GcpKmsProvider({
|
|
65
66
|
cryptoKeyName: opts.config?.cryptoKeyName,
|
|
66
67
|
serviceAccountJson: opts.config?.serviceAccountJson,
|
|
68
|
+
// spec 278 P0/P3: thread the audit sink so envelope wrap/unwrap emit
|
|
69
|
+
// `key-custody.envelope.{wrap,unwrap}` on the production path.
|
|
70
|
+
auditSink: opts.auditSink,
|
|
67
71
|
});
|
|
68
72
|
}
|
|
69
73
|
}
|
|
74
|
+
export function selectVaultKeyProvider(opts) {
|
|
75
|
+
if (opts.kmsKeyRef) {
|
|
76
|
+
if (!opts.serviceAccountJson) {
|
|
77
|
+
throw new Error('[key-custody] selectVaultKeyProvider: serviceAccountJson is required with a kmsKeyRef (per-person KEK).');
|
|
78
|
+
}
|
|
79
|
+
return new GcpKmsProvider({
|
|
80
|
+
cryptoKeyName: opts.kmsKeyRef,
|
|
81
|
+
serviceAccountJson: opts.serviceAccountJson,
|
|
82
|
+
auditSink: opts.auditSink,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (opts.allowFixtureKey) {
|
|
86
|
+
// Anonymous / seeded fixtures only (spec 278 VKB-D1 exception). LocalAesProvider
|
|
87
|
+
// keeps its own production guard; this path is testnet/fixture-grade by contract.
|
|
88
|
+
return new LocalAesProvider({ sessionSecretHex: opts.fixtureKeyHex });
|
|
89
|
+
}
|
|
90
|
+
throw new Error('[key-custody] selectVaultKeyProvider: a person-owned vault requires a per-person `kmsKeyRef` ' +
|
|
91
|
+
'(from the VaultKeyBinding). No global key is permitted for person data (spec 278 VKB-D1). ' +
|
|
92
|
+
'For anonymous/seeded fixtures only, pass `allowFixtureKey: true`.');
|
|
93
|
+
}
|
|
70
94
|
export function buildSignerBackend(opts) {
|
|
71
95
|
switch (backendOrEnv(opts)) {
|
|
72
96
|
case 'local-aes':
|
package/dist/factories.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factories.js","sourceRoot":"","sources":["../src/factories.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"factories.js","sourceRoot":"","sources":["../src/factories.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Address, Hex } from '@agenticprimitives/types';
|
|
2
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,
|
|
6
|
-
export { deriveSubjectSigner, subjectCanonicalMessage, type SubjectId, type DeriveSubjectOpts, } from './derive-subject';
|
|
7
|
-
export { getRelayOnlySigner } from './relay-only';
|
|
8
|
-
export { createKmsAccount } from './account';
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
3
|
+
export type { A2AKeyProvider, KmsAccountBackend, BuildOpts, KmsBackend, Secret } from './types.js';
|
|
4
|
+
export { loadSecret, loadSecretFromEnv, unwrapSecret, isSecret } from './types.js';
|
|
5
|
+
export { buildKeyProvider, buildSignerBackend, buildToolExecutorBackendNoIsolation, buildMacProvider, selectVaultKeyProvider, type SelectVaultKeyProviderOpts, } from './factories.js';
|
|
6
|
+
export { deriveSubjectSigner, subjectCanonicalMessage, type SubjectId, type DeriveSubjectOpts, } from './derive-subject.js';
|
|
7
|
+
export { getRelayOnlySigner } from './relay-only.js';
|
|
8
|
+
export { createKmsAccount } from './account.js';
|
|
9
|
+
export { createKmsViemAccount } from './kms-viem-account.js';
|
|
10
|
+
export { createRelayerAccount, type CreateRelayerAccountOpts, } from './relayer-account.js';
|
|
11
|
+
export { createSpendCappedAccount, SpendCapExceededError, type CreateSpendCappedAccountOpts, } from './spend-capped-account.js';
|
|
12
|
+
export { canonicalContextBytes } from './aad.js';
|
|
13
|
+
export { LocalAesProvider, LocalSecp256k1Signer } from './providers/local.js';
|
|
14
|
+
export { GcpKmsProvider, GcpKmsSigner } from './providers/gcp.js';
|
|
13
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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,YAAY,CAAC;AACnG,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAWlB,mCAAmC,EACnC,gBAAgB,EAEhB,sBAAsB,EACtB,KAAK,0BAA0B,GAChC,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAU9E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
// @agenticprimitives/key-custody — public API
|
|
2
2
|
//
|
|
3
3
|
// See ../../specs/203-key-custody.md for the full contract.
|
|
4
|
-
export { loadSecret, loadSecretFromEnv, unwrapSecret, isSecret } from './types';
|
|
5
|
-
export { buildKeyProvider, buildSignerBackend,
|
|
4
|
+
export { loadSecret, loadSecretFromEnv, unwrapSecret, isSecret } from './types.js';
|
|
5
|
+
export { buildKeyProvider, buildSignerBackend,
|
|
6
|
+
// R11.3 / PKG-KEY-CUSTODY-001 follow-up — `buildToolExecutorBackend`
|
|
7
|
+
// is NOT re-exported here. Its v0 implementation is the always-throwing
|
|
8
|
+
// alias that the JSDoc redirects to the explicit
|
|
9
|
+
// `buildToolExecutorBackendNoIsolation` (dev-only opt-in) or
|
|
10
|
+
// `deriveSubjectSigner` (true per-subject isolation, spec 235). Keeping
|
|
11
|
+
// the throwing alias in the public surface is a footgun — a consumer
|
|
12
|
+
// reading the public API thinks per-tool isolation is supported. v1
|
|
13
|
+
// either implements HKDF per-tool isolation or graduates
|
|
14
|
+
// `buildToolExecutorBackendNoIsolation` to the canonical name. Until
|
|
15
|
+
// then, the public surface is the explicit-name one only.
|
|
16
|
+
buildToolExecutorBackendNoIsolation, buildMacProvider,
|
|
17
|
+
// spec 278 P3 — per-person vault KEK selection (fail-closed; no global key for person data).
|
|
18
|
+
selectVaultKeyProvider, } from './factories.js';
|
|
6
19
|
// `deriveSubjectPrivateKeyHex` is intentionally NOT re-exported here — it returns
|
|
7
20
|
// a per-subject raw private key (security-sensitive). It stays exported from
|
|
8
21
|
// `./derive-subject` for in-package unit tests but is not part of the public API.
|
|
9
22
|
// 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 {
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
23
|
+
export { deriveSubjectSigner, subjectCanonicalMessage, } from './derive-subject.js';
|
|
24
|
+
export { getRelayOnlySigner } from './relay-only.js';
|
|
25
|
+
export { createKmsAccount } from './account.js';
|
|
26
|
+
export { createKmsViemAccount } from './kms-viem-account.js';
|
|
27
|
+
export { createRelayerAccount, } from './relayer-account.js';
|
|
28
|
+
export { createSpendCappedAccount, SpendCapExceededError, } from './spend-capped-account.js';
|
|
29
|
+
export { canonicalContextBytes } from './aad.js';
|
|
30
|
+
export { LocalAesProvider, LocalSecp256k1Signer } from './providers/local.js';
|
|
31
|
+
// R11.3 — `AwsKmsProvider` / `AwsKmsSigner` are NOT re-exported here.
|
|
32
|
+
// Their current implementations throw a `not yet implemented in v0;
|
|
33
|
+
// use LocalAesProvider for the demo` message at construction time. A
|
|
34
|
+
// public symbol whose existence implies a capability the runtime can't
|
|
35
|
+
// provide is an ADR-0013 violation (silent fallback in the type system).
|
|
36
|
+
// The `KmsBackend` type retains 'aws-kms' as a future value, but the
|
|
37
|
+
// factory throws a clear error when selected. v1 is GCP-only +
|
|
38
|
+
// local-aes (dev). When AWS lands, re-add the export alongside the
|
|
39
|
+
// LocalAes + Gcp providers.
|
|
40
|
+
export { GcpKmsProvider, GcpKmsSigner } from './providers/gcp.js';
|
|
17
41
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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,
|
|
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,YAAY,CAAC;AAEnF,OAAO,EACL,gBAAgB,EAChB,kBAAkB;AAClB,qEAAqE;AACrE,wEAAwE;AACxE,iDAAiD;AACjD,6DAA6D;AAC7D,wEAAwE;AACxE,qEAAqE;AACrE,oEAAoE;AACpE,yDAAyD;AACzD,qEAAqE;AACrE,0DAA0D;AAC1D,mCAAmC,EACnC,gBAAgB;AAChB,6FAA6F;AAC7F,sBAAsB,GAEvB,MAAM,gBAAgB,CAAC;AACxB,kFAAkF;AAClF,6EAA6E;AAC7E,kFAAkF;AAClF,mGAAmG;AACnG,OAAO,EACL,mBAAmB,EACnB,uBAAuB,GAGxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EACL,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,GAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,sEAAsE;AACtE,oEAAoE;AACpE,qEAAqE;AACrE,uEAAuE;AACvE,yEAAyE;AACzE,qEAAqE;AACrE,+DAA+D;AAC/D,mEAAmE;AACnE,4BAA4B;AAC5B,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Hex } from './secp256k1-core.js';
|
|
2
|
+
export interface ServiceAccount {
|
|
3
|
+
client_email: string;
|
|
4
|
+
/** PEM-encoded PKCS#8 RSA private key. */
|
|
5
|
+
private_key: string;
|
|
6
|
+
project_id?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CachedToken {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
/** Unix seconds at which the token must be refreshed (already minus buffer). */
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function signJwt(serviceAccount: ServiceAccount, scope: string): Promise<string>;
|
|
14
|
+
export declare function fetchAccessToken(serviceAccount: ServiceAccount): Promise<CachedToken>;
|
|
15
|
+
export declare function callKms<T>(token: string, pathRelativeToBase: string, options?: {
|
|
16
|
+
method: 'GET' | 'POST';
|
|
17
|
+
body?: unknown;
|
|
18
|
+
}): Promise<T>;
|
|
19
|
+
export interface GcpKmsTransport {
|
|
20
|
+
/** Fetch the key version's SPKI PEM; asserts the secp256k1 algorithm. */
|
|
21
|
+
getPublicKeyPem(cryptoKeyVersionName: string): Promise<string>;
|
|
22
|
+
/** POST `:asymmetricSign` for a 32-byte digest; returns the DER signature bytes. */
|
|
23
|
+
asymmetricSign(cryptoKeyVersionName: string, digest: Uint8Array): Promise<Uint8Array>;
|
|
24
|
+
}
|
|
25
|
+
/** Build a token-caching Cloud KMS transport from service-account JSON. Peer-dep-free. */
|
|
26
|
+
export declare function createGcpKmsTransport(serviceAccount: ServiceAccount): GcpKmsTransport;
|
|
27
|
+
/** One-shot: sign a 32-byte digest with a Cloud KMS secp256k1 key → Ethereum `(r,s,v)` 0x hex.
|
|
28
|
+
* This is the surface an external consumer imports instead of inlining a KMS signer (spec 276). */
|
|
29
|
+
export declare function gcpSignDigest(opts: {
|
|
30
|
+
serviceAccount: ServiceAccount;
|
|
31
|
+
cryptoKeyVersionName: string;
|
|
32
|
+
digest: Uint8Array;
|
|
33
|
+
/** Pass a cached transport to reuse the access token across calls. */
|
|
34
|
+
transport?: GcpKmsTransport;
|
|
35
|
+
}): Promise<Hex>;
|
|
36
|
+
//# sourceMappingURL=gcp-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-transport.d.ts","sourceRoot":"","sources":["../../src/kms/gcp-transport.ts"],"names":[],"mappings":"AASA,OAAO,EAA4E,KAAK,GAAG,EAAE,MAAM,qBAAqB,CAAC;AASzH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD,wBAAsB,OAAO,CAAC,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB5F;AAED,wBAAsB,gBAAgB,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAoB3F;AAID,wBAAsB,OAAO,CAAC,CAAC,EAC7B,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,MAAM,EAC1B,OAAO,GAAE;IAAE,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAsB,GACtE,OAAO,CAAC,CAAC,CAAC,CAiBZ;AAID,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,eAAe,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,oFAAoF;IACpF,cAAc,CAAC,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACvF;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,cAAc,GAAG,eAAe,CA4BrF;AAED;oGACoG;AACpG,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,cAAc,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B,GAAG,OAAO,CAAC,GAAG,CAAC,CAQf"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// GCP Cloud KMS REST transport — the CONSUMER-SAFE, peer-dependency-free transport (spec 276 KCS-D1).
|
|
2
|
+
//
|
|
3
|
+
// Cloudflare-Workers-compatible: drives the Cloud KMS REST API via fetch +
|
|
4
|
+
// Web Crypto for the service-account JWT-bearer flow. The @google-cloud/kms
|
|
5
|
+
// SDK uses gRPC and won't run on Workers; this avoids gRPC entirely.
|
|
6
|
+
//
|
|
7
|
+
// HARD CONSTRAINT (same as secp256k1-core): only Web/Node built-ins +
|
|
8
|
+
// `secp256k1-core` (itself @noble-only). NO viem / @agenticprimitives/*.
|
|
9
|
+
import { base64UrlEncode, base64Decode, base64Encode, pemToDer, signDigestWithKms } from './secp256k1-core.js';
|
|
10
|
+
// ── Constants ────────────────────────────────────────────────────────
|
|
11
|
+
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
12
|
+
const CLOUDKMS_SCOPE = 'https://www.googleapis.com/auth/cloudkms';
|
|
13
|
+
const CLOUDKMS_BASE = 'https://cloudkms.googleapis.com/v1/';
|
|
14
|
+
const TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
15
|
+
// ── JWT signing + token exchange ─────────────────────────────────────
|
|
16
|
+
export async function signJwt(serviceAccount, scope) {
|
|
17
|
+
const now = Math.floor(Date.now() / 1000);
|
|
18
|
+
const header = { alg: 'RS256', typ: 'JWT' };
|
|
19
|
+
const payload = { iss: serviceAccount.client_email, scope, aud: GOOGLE_TOKEN_URL, iat: now, exp: now + 3600 };
|
|
20
|
+
const encoder = new TextEncoder();
|
|
21
|
+
const headerB64 = base64UrlEncode(encoder.encode(JSON.stringify(header)));
|
|
22
|
+
const payloadB64 = base64UrlEncode(encoder.encode(JSON.stringify(payload)));
|
|
23
|
+
const signingInput = `${headerB64}.${payloadB64}`;
|
|
24
|
+
const keyDer = pemToDer(serviceAccount.private_key);
|
|
25
|
+
// Copy into a fresh ArrayBuffer so the typing satisfies BufferSource
|
|
26
|
+
// (TS lib.dom narrowed Uint8Array.buffer to ArrayBufferLike in 5.7).
|
|
27
|
+
const keyBuffer = new ArrayBuffer(keyDer.byteLength);
|
|
28
|
+
new Uint8Array(keyBuffer).set(keyDer);
|
|
29
|
+
const key = await globalThis.crypto.subtle.importKey('pkcs8', keyBuffer, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['sign']);
|
|
30
|
+
const signature = await globalThis.crypto.subtle.sign({ name: 'RSASSA-PKCS1-v1_5' }, key, encoder.encode(signingInput));
|
|
31
|
+
return `${signingInput}.${base64UrlEncode(new Uint8Array(signature))}`;
|
|
32
|
+
}
|
|
33
|
+
export async function fetchAccessToken(serviceAccount) {
|
|
34
|
+
const assertion = await signJwt(serviceAccount, CLOUDKMS_SCOPE);
|
|
35
|
+
const body = `grant_type=${encodeURIComponent('urn:ietf:params:oauth:grant-type:jwt-bearer')}&assertion=${encodeURIComponent(assertion)}`;
|
|
36
|
+
const res = await fetch(GOOGLE_TOKEN_URL, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
39
|
+
body,
|
|
40
|
+
});
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
const text = await res.text();
|
|
43
|
+
throw new Error(`GCP token exchange failed: HTTP ${res.status}: ${text.slice(0, 300)}`);
|
|
44
|
+
}
|
|
45
|
+
const json = (await res.json());
|
|
46
|
+
if (!json.access_token || typeof json.expires_in !== 'number') {
|
|
47
|
+
throw new Error('GCP token exchange: response missing access_token or expires_in');
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
accessToken: json.access_token,
|
|
51
|
+
expiresAt: Math.floor(Date.now() / 1000) + json.expires_in - TOKEN_EXPIRY_BUFFER_SECONDS,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// ── Cloud KMS REST calls ─────────────────────────────────────────────
|
|
55
|
+
export async function callKms(token, pathRelativeToBase, options = { method: 'GET' }) {
|
|
56
|
+
const url = `${CLOUDKMS_BASE}${pathRelativeToBase}`;
|
|
57
|
+
const init = {
|
|
58
|
+
method: options.method,
|
|
59
|
+
headers: {
|
|
60
|
+
authorization: `Bearer ${token}`,
|
|
61
|
+
...(options.body ? { 'content-type': 'application/json' } : {}),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
if (options.body)
|
|
65
|
+
init.body = JSON.stringify(options.body);
|
|
66
|
+
const res = await fetch(url, init);
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
// Don't leak the Authorization header. URL path is safe to include.
|
|
70
|
+
throw new Error(`Cloud KMS API error: HTTP ${res.status} on ${pathRelativeToBase}: ${text.slice(0, 300)}`);
|
|
71
|
+
}
|
|
72
|
+
return (await res.json());
|
|
73
|
+
}
|
|
74
|
+
/** Build a token-caching Cloud KMS transport from service-account JSON. Peer-dep-free. */
|
|
75
|
+
export function createGcpKmsTransport(serviceAccount) {
|
|
76
|
+
let cached;
|
|
77
|
+
const token = async () => {
|
|
78
|
+
const now = Math.floor(Date.now() / 1000);
|
|
79
|
+
if (cached && cached.expiresAt > now)
|
|
80
|
+
return cached.accessToken;
|
|
81
|
+
cached = await fetchAccessToken(serviceAccount);
|
|
82
|
+
return cached.accessToken;
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
async getPublicKeyPem(keyName) {
|
|
86
|
+
const res = await callKms(await token(), `${keyName}/publicKey`);
|
|
87
|
+
if (res.algorithm !== 'EC_SIGN_SECP256K1_SHA256') {
|
|
88
|
+
throw new Error(`Cloud KMS key ${keyName} has algorithm "${res.algorithm}", but EC_SIGN_SECP256K1_SHA256 is ` +
|
|
89
|
+
`required for Ethereum-compatible signing. Recreate with --default-algorithm=ec-sign-secp256k1-sha256 ` +
|
|
90
|
+
`--protection-level=hsm (secp256k1 requires HSM in GCP).`);
|
|
91
|
+
}
|
|
92
|
+
return res.pem;
|
|
93
|
+
},
|
|
94
|
+
async asymmetricSign(keyName, digest) {
|
|
95
|
+
const res = await callKms(await token(), `${keyName}:asymmetricSign`, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
body: { digest: { sha256: base64Encode(digest) } },
|
|
98
|
+
});
|
|
99
|
+
return base64Decode(res.signature);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** One-shot: sign a 32-byte digest with a Cloud KMS secp256k1 key → Ethereum `(r,s,v)` 0x hex.
|
|
104
|
+
* This is the surface an external consumer imports instead of inlining a KMS signer (spec 276). */
|
|
105
|
+
export async function gcpSignDigest(opts) {
|
|
106
|
+
const transport = opts.transport ?? createGcpKmsTransport(opts.serviceAccount);
|
|
107
|
+
const publicKeyPem = await transport.getPublicKeyPem(opts.cryptoKeyVersionName);
|
|
108
|
+
return signDigestWithKms({
|
|
109
|
+
digest: opts.digest,
|
|
110
|
+
publicKeyPem,
|
|
111
|
+
asymmetricSign: (d) => transport.asymmetricSign(opts.cryptoKeyVersionName, d),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=gcp-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-transport.js","sourceRoot":"","sources":["../../src/kms/gcp-transport.ts"],"names":[],"mappings":"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"}
|