@dnsid-ai/key-gcp 0.0.0-stage → 0.36.0
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/LICENSE +203 -0
- package/NOTICE.txt +348 -0
- package/README.md +81 -2
- package/dist/index.cjs +277 -0
- package/dist/index.d.cts +111 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.js +242 -0
- package/package.json +48 -4
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
GcpCloudKmsKeyProvider: () => GcpCloudKmsKeyProvider
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var import_node_crypto = require("crypto");
|
|
37
|
+
var import_protocol = require("@dnsid-ai/protocol");
|
|
38
|
+
var GcpCloudKmsKeyProvider = class _GcpCloudKmsKeyProvider {
|
|
39
|
+
constructor(client, version, publicKey) {
|
|
40
|
+
this.client = client;
|
|
41
|
+
this.version = version;
|
|
42
|
+
if (publicKey) {
|
|
43
|
+
this.activeKid = publicKey.kid;
|
|
44
|
+
this.keys.set(publicKey.kid, { version, jwk: publicKey, state: "active" });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
client;
|
|
48
|
+
version;
|
|
49
|
+
keys = /* @__PURE__ */ new Map();
|
|
50
|
+
activeKid;
|
|
51
|
+
signing = /* @__PURE__ */ new Set();
|
|
52
|
+
activating = false;
|
|
53
|
+
/**
|
|
54
|
+
* Creates one version under an existing ASYMMETRIC_SIGN CryptoKey with a
|
|
55
|
+
* SOFTWARE EC_SIGN_ED25519 template, without opening any prior version.
|
|
56
|
+
* Returns a locally pending provider and immutable reference; activate(kid)
|
|
57
|
+
* explicitly before initial manager injection. Never provisions the parent,
|
|
58
|
+
* writes files, deletes keys, or closes the caller-owned client.
|
|
59
|
+
* Pending generation polls the same version at most 20 times, 250ms apart.
|
|
60
|
+
* Each transport call uses the caller's client timeout configuration.
|
|
61
|
+
* Failed/indeterminate creation may leave an operator-owned remote version;
|
|
62
|
+
* do not blindly retry. Normal load/configuration remains open-only.
|
|
63
|
+
*/
|
|
64
|
+
static async create(client, config) {
|
|
65
|
+
if (config.algorithm !== "EC_SIGN_ED25519") throw new import_protocol.ArgumentError("Google Cloud KMS algorithm must be EC_SIGN_ED25519");
|
|
66
|
+
if (typeof config.parent !== "string" || !/^projects\/[A-Za-z0-9._:-]+\/locations\/[A-Za-z0-9_-]+\/keyRings\/[A-Za-z0-9_-]+\/cryptoKeys\/[A-Za-z0-9_-]+$/.test(config.parent)) {
|
|
67
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS creation requires a CryptoKey parent");
|
|
68
|
+
}
|
|
69
|
+
if (!client.getCryptoKey || !client.createCryptoKeyVersion) throw new import_protocol.ArgumentError("Google Cloud KMS client does not support initial creation");
|
|
70
|
+
const [raw] = await client.getCryptoKey({ name: config.parent });
|
|
71
|
+
const parent = raw;
|
|
72
|
+
if (parent?.name !== config.parent || parent.purpose !== "ASYMMETRIC_SIGN" && parent.purpose !== 5 || !ed25519Software(parent.versionTemplate)) {
|
|
73
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS requires a compatible signing parent/template");
|
|
74
|
+
}
|
|
75
|
+
const provider = new _GcpCloudKmsKeyProvider(client, config.parent);
|
|
76
|
+
const kid = await provider.generatePendingKey(void 0);
|
|
77
|
+
return { provider, kid, keyRef: provider.keys.get(kid).version };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Opens the selected active version and, optionally, an application-saved pending
|
|
81
|
+
* version for recovery. Both bindings are validated; the pending key supports
|
|
82
|
+
* JWK lookup and rotation proof signing but is not the active signer or live
|
|
83
|
+
* inventory. No discovery, generation, or activation occurs. Applications own
|
|
84
|
+
* durable references and recovery checks; activate performs the local transition.
|
|
85
|
+
*/
|
|
86
|
+
static async load(client, config) {
|
|
87
|
+
const version = config.activeKeyVersion;
|
|
88
|
+
validateVersion(version);
|
|
89
|
+
const pendingVersion = config.pendingKeyVersion;
|
|
90
|
+
if (pendingVersion !== void 0) {
|
|
91
|
+
validateVersion(pendingVersion);
|
|
92
|
+
if (pendingVersion === version) throw new import_protocol.ArgumentError("Google Cloud KMS active and pending versions must differ");
|
|
93
|
+
}
|
|
94
|
+
if (config.algorithm !== "EC_SIGN_ED25519") throw new import_protocol.ArgumentError("Google Cloud KMS algorithm must be EC_SIGN_ED25519");
|
|
95
|
+
if (config.retainedKeyVersions?.length) throw new import_protocol.ArgumentError("Google Cloud KMS retained key loading is not supported");
|
|
96
|
+
if (!client) {
|
|
97
|
+
const { KeyManagementServiceClient } = await import("@google-cloud/kms");
|
|
98
|
+
client = new KeyManagementServiceClient();
|
|
99
|
+
}
|
|
100
|
+
const publicKey = await loadPublicKey(client, version);
|
|
101
|
+
const pendingKey = pendingVersion === void 0 ? void 0 : await loadPublicKey(client, pendingVersion);
|
|
102
|
+
if (pendingKey?.kid === publicKey.kid) throw new import_protocol.ArgumentError("Google Cloud KMS pending version has duplicate public key");
|
|
103
|
+
const provider = new _GcpCloudKmsKeyProvider(client, version, publicKey);
|
|
104
|
+
if (pendingKey) provider.keys.set(pendingKey.kid, { version: pendingVersion, jwk: pendingKey, state: "pending" });
|
|
105
|
+
return provider;
|
|
106
|
+
}
|
|
107
|
+
async signingKey() {
|
|
108
|
+
if (!this.activeKid) throw new import_protocol.ArgumentError("Google Cloud KMS has no active key");
|
|
109
|
+
return this.jwk(this.activeKid);
|
|
110
|
+
}
|
|
111
|
+
async jwk(kid) {
|
|
112
|
+
const key = this.keys.get(kid);
|
|
113
|
+
if (!key) throw new import_protocol.ArgumentError("Google Cloud KMS key not found");
|
|
114
|
+
return { ...key.jwk };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns only the current active key ID, or an empty list when no key is active.
|
|
118
|
+
* Pending and superseded keys are excluded from this live key list, even when
|
|
119
|
+
* their public JWKs remain available through `jwk` for historical verification.
|
|
120
|
+
*/
|
|
121
|
+
async listKeyIds() {
|
|
122
|
+
return this.activeKid ? [this.activeKid] : [];
|
|
123
|
+
}
|
|
124
|
+
async sign(payload) {
|
|
125
|
+
if (!this.activeKid) throw new import_protocol.ArgumentError("Google Cloud KMS has no active key");
|
|
126
|
+
return this.signKey(this.activeKid, payload);
|
|
127
|
+
}
|
|
128
|
+
async signKey(kid, payload) {
|
|
129
|
+
if (this.activating) throw new import_protocol.ArgumentError("Google Cloud KMS activation is in progress");
|
|
130
|
+
const key = this.keys.get(kid);
|
|
131
|
+
if (!key || key.state === "superseded") throw new import_protocol.ArgumentError("Google Cloud KMS key is not active or pending");
|
|
132
|
+
const operation = this.signVersion(key.version, payload);
|
|
133
|
+
this.signing.add(operation);
|
|
134
|
+
try {
|
|
135
|
+
return await operation;
|
|
136
|
+
} finally {
|
|
137
|
+
this.signing.delete(operation);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async signVersion(version, payload) {
|
|
141
|
+
const data = new Uint8Array(payload);
|
|
142
|
+
const [raw] = await this.client.asymmetricSign({ name: version, data, dataCrc32c: { value: crc32c(data) } });
|
|
143
|
+
const response = raw;
|
|
144
|
+
if (response?.name !== version) throw new import_protocol.ArgumentError("Google Cloud KMS signature version mismatch");
|
|
145
|
+
if (response.verifiedDataCrc32c !== true) throw new import_protocol.ArgumentError("Google Cloud KMS did not verify data checksum");
|
|
146
|
+
const signature = typeof response.signature === "string" ? Buffer.from(response.signature, "base64") : response.signature;
|
|
147
|
+
if (!(signature instanceof Uint8Array) || signature.byteLength !== 64) throw new import_protocol.ArgumentError("Google Cloud KMS returned invalid Ed25519 signature");
|
|
148
|
+
if (!checksumMatches(signature, response.signatureCrc32c)) throw new import_protocol.ArgumentError("Google Cloud KMS signature checksum mismatch");
|
|
149
|
+
return new Uint8Array(signature);
|
|
150
|
+
}
|
|
151
|
+
async validateKeyGeneration(algorithm) {
|
|
152
|
+
if (algorithm !== "EdDSA") throw new import_protocol.ArgumentError(`Google Cloud KMS generation settings do not support ${algorithm}`);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Explicit operator generation only; defaults to EdDSA and rejects other algorithms before creation.
|
|
156
|
+
* Pending generation polls the exact created version at most 20 times, 250ms apart,
|
|
157
|
+
* using the caller's transport timeouts, just as initial creation does.
|
|
158
|
+
* Returns a locally pending key without changing the active signer. Failures after
|
|
159
|
+
* creation retain the version reference and cause, without retrying or deleting it.
|
|
160
|
+
* Service/integrity failures are not caller-argument errors. Never called by configuration opening.
|
|
161
|
+
*/
|
|
162
|
+
async generateKey(algorithm) {
|
|
163
|
+
return this.generatePendingKey(algorithm);
|
|
164
|
+
}
|
|
165
|
+
async generatePendingKey(algorithm) {
|
|
166
|
+
await this.validateKeyGeneration(algorithm ?? "EdDSA");
|
|
167
|
+
if (!this.client.createCryptoKeyVersion) throw new import_protocol.ArgumentError("Google Cloud KMS client does not support version creation");
|
|
168
|
+
const parent = this.version.includes("/cryptoKeyVersions/") ? this.version.slice(0, this.version.lastIndexOf("/cryptoKeyVersions/")) : this.version;
|
|
169
|
+
const [raw] = await this.client.createCryptoKeyVersion({ parent, cryptoKeyVersion: { state: "ENABLED" } });
|
|
170
|
+
let created = raw;
|
|
171
|
+
const name = created?.name;
|
|
172
|
+
if (typeof name !== "string" || !name.startsWith(parent + "/cryptoKeyVersions/") || !/^[1-9][0-9]*$/.test(name.slice((parent + "/cryptoKeyVersions/").length))) {
|
|
173
|
+
throw new import_protocol.ArgumentError(`Google Cloud KMS created an unexpected key version${typeof name === "string" && name ? `: ${name}` : ""}`);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
for (let poll = 0; ; poll++) {
|
|
177
|
+
if (created?.name !== name || !ed25519Software(created)) throw new import_protocol.ArgumentError("Google Cloud KMS created an unexpected key version");
|
|
178
|
+
if (created.state === "ENABLED" || created.state === 1) break;
|
|
179
|
+
if (created.state !== "PENDING_GENERATION" && created.state !== 5 || poll >= 20 || !this.client.getCryptoKeyVersion) {
|
|
180
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS version is not ready for signing");
|
|
181
|
+
}
|
|
182
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
183
|
+
const [metadata] = await this.client.getCryptoKeyVersion({ name });
|
|
184
|
+
created = metadata;
|
|
185
|
+
}
|
|
186
|
+
const pending = await _GcpCloudKmsKeyProvider.load(this.client, { activeKeyVersion: name, algorithm: "EC_SIGN_ED25519" });
|
|
187
|
+
const jwk = await pending.signingKey();
|
|
188
|
+
if (this.keys.has(jwk.kid)) throw new import_protocol.ArgumentError("Google Cloud KMS generated duplicate public key");
|
|
189
|
+
this.keys.set(jwk.kid, { version: name, jwk: Object.freeze(jwk), state: "pending" });
|
|
190
|
+
return jwk.kid;
|
|
191
|
+
} catch (cause) {
|
|
192
|
+
throw new Error(`Google Cloud KMS created version ${name}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async activate(kid) {
|
|
196
|
+
if (this.activating) throw new import_protocol.ArgumentError("Google Cloud KMS activation is already in progress");
|
|
197
|
+
const key = this.keys.get(kid);
|
|
198
|
+
if (!key || key.state !== "pending") throw new import_protocol.ArgumentError("Google Cloud KMS key is not pending");
|
|
199
|
+
this.activating = true;
|
|
200
|
+
try {
|
|
201
|
+
await Promise.allSettled(this.signing);
|
|
202
|
+
if (this.activeKid) this.keys.get(this.activeKid).state = "superseded";
|
|
203
|
+
key.state = "active";
|
|
204
|
+
this.activeKid = kid;
|
|
205
|
+
} finally {
|
|
206
|
+
this.activating = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Removes local signing eligibility from an active, pending, or already
|
|
211
|
+
* superseded key. Superseding the active key leaves no active signer and an
|
|
212
|
+
* empty live key list; superseding another key does not clear its successor.
|
|
213
|
+
* The public JWK remains available through `jwk` for historical verification.
|
|
214
|
+
* Never disables, destroys, or otherwise mutates the remote CryptoKeyVersion.
|
|
215
|
+
*/
|
|
216
|
+
async supersede(kid) {
|
|
217
|
+
if (this.activating) throw new import_protocol.ArgumentError("Google Cloud KMS activation is in progress");
|
|
218
|
+
const key = this.keys.get(kid);
|
|
219
|
+
if (!key) throw new import_protocol.ArgumentError("Google Cloud KMS key not found");
|
|
220
|
+
key.state = "superseded";
|
|
221
|
+
if (this.activeKid === kid) this.activeKid = void 0;
|
|
222
|
+
}
|
|
223
|
+
/** Alias for local supersession; never disables or destroys a cloud version. */
|
|
224
|
+
async purge(kid) {
|
|
225
|
+
return this.supersede(kid);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
function validateVersion(version) {
|
|
229
|
+
if (typeof version !== "string" || !/^projects\/[A-Za-z0-9._:-]+\/locations\/[A-Za-z0-9_-]+\/keyRings\/[A-Za-z0-9_-]+\/cryptoKeys\/[A-Za-z0-9_-]+\/cryptoKeyVersions\/[1-9][0-9]*$/.test(version)) {
|
|
230
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS requires an immutable CryptoKeyVersion name");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function loadPublicKey(client, version) {
|
|
234
|
+
const [raw] = await client.getPublicKey({ name: version });
|
|
235
|
+
const response = raw;
|
|
236
|
+
if (response?.name !== version) throw new import_protocol.ArgumentError("Google Cloud KMS public key version mismatch");
|
|
237
|
+
if (response.algorithm !== "EC_SIGN_ED25519" && response.algorithm !== 40) throw new import_protocol.ArgumentError("Google Cloud KMS public key algorithm mismatch");
|
|
238
|
+
if (response.protectionLevel !== "SOFTWARE" && response.protectionLevel !== 1) throw new import_protocol.ArgumentError("Google Cloud KMS public key must use SOFTWARE protection");
|
|
239
|
+
if (typeof response.pem !== "string" || !checksumMatches(Buffer.from(response.pem), response.pemCrc32c)) {
|
|
240
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS public PEM checksum mismatch");
|
|
241
|
+
}
|
|
242
|
+
let publicKey;
|
|
243
|
+
try {
|
|
244
|
+
if (!response.pem.startsWith("-----BEGIN PUBLIC KEY-----")) throw new Error();
|
|
245
|
+
const key = (0, import_node_crypto.createPublicKey)({ key: response.pem, format: "pem", type: "spki" });
|
|
246
|
+
if (key.asymmetricKeyType !== "ed25519") throw new Error();
|
|
247
|
+
const exported = key.export({ format: "jwk" });
|
|
248
|
+
publicKey = { kty: "OKP", crv: "Ed25519", x: exported.x, kid: "", alg: "EdDSA", use: "sig" };
|
|
249
|
+
} catch {
|
|
250
|
+
throw new import_protocol.ArgumentError("Google Cloud KMS returned invalid Ed25519 public SPKI");
|
|
251
|
+
}
|
|
252
|
+
publicKey.kid = await (0, import_protocol.jwkThumbprint)(publicKey);
|
|
253
|
+
return Object.freeze(publicKey);
|
|
254
|
+
}
|
|
255
|
+
function checksumMatches(bytes, checksum) {
|
|
256
|
+
const raw = checksum?.value;
|
|
257
|
+
if (raw === void 0 || raw === null) return false;
|
|
258
|
+
const text = String(raw);
|
|
259
|
+
if (!/^[0-9]+$/.test(text)) return false;
|
|
260
|
+
const value = Number(text);
|
|
261
|
+
return Number.isSafeInteger(value) && value >= 0 && value <= 4294967295 && value === crc32c(bytes);
|
|
262
|
+
}
|
|
263
|
+
function crc32c(bytes) {
|
|
264
|
+
let crc = 4294967295;
|
|
265
|
+
for (const byte of bytes) {
|
|
266
|
+
crc ^= byte;
|
|
267
|
+
for (let bit = 0; bit < 8; bit++) crc = crc >>> 1 ^ (crc & 1 ? 2197175160 : 0);
|
|
268
|
+
}
|
|
269
|
+
return (crc ^ 4294967295) >>> 0;
|
|
270
|
+
}
|
|
271
|
+
function ed25519Software(value) {
|
|
272
|
+
return !!value && (value.algorithm === "EC_SIGN_ED25519" || value.algorithm === 40) && (value.protectionLevel === "SOFTWARE" || value.protectionLevel === 1);
|
|
273
|
+
}
|
|
274
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
275
|
+
0 && (module.exports = {
|
|
276
|
+
GcpCloudKmsKeyProvider
|
|
277
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { KeyProvider, DnsIdJWK } from '@dnsid-ai/protocol';
|
|
2
|
+
|
|
3
|
+
interface GcpCloudKmsConfig {
|
|
4
|
+
/** Fully qualified immutable CryptoKeyVersion resource name. */
|
|
5
|
+
activeKeyVersion: string;
|
|
6
|
+
/** Application-saved immutable pending version; never discovered or activated by load. */
|
|
7
|
+
pendingKeyVersion?: string;
|
|
8
|
+
/** Retained-key loading is not supported by this runtime slice. */
|
|
9
|
+
retainedKeyVersions?: string[];
|
|
10
|
+
/** Must be EC_SIGN_ED25519. */
|
|
11
|
+
algorithm: string;
|
|
12
|
+
}
|
|
13
|
+
/** Structural seam implemented by the official KeyManagementServiceClient. */
|
|
14
|
+
interface GcpCloudKmsClient {
|
|
15
|
+
/** Required only for initial creation; reads the existing signing parent/template. */
|
|
16
|
+
getCryptoKey?(request: {
|
|
17
|
+
name: string;
|
|
18
|
+
}): Promise<readonly unknown[]>;
|
|
19
|
+
/** Required when a newly created version is still PENDING_GENERATION. */
|
|
20
|
+
getCryptoKeyVersion?(request: {
|
|
21
|
+
name: string;
|
|
22
|
+
}): Promise<readonly unknown[]>;
|
|
23
|
+
createCryptoKeyVersion?(request: {
|
|
24
|
+
parent: string;
|
|
25
|
+
cryptoKeyVersion: {
|
|
26
|
+
state: 'ENABLED';
|
|
27
|
+
};
|
|
28
|
+
}): Promise<readonly unknown[]>;
|
|
29
|
+
getPublicKey(request: {
|
|
30
|
+
name: string;
|
|
31
|
+
}): Promise<readonly unknown[]>;
|
|
32
|
+
asymmetricSign(request: {
|
|
33
|
+
name: string;
|
|
34
|
+
data: Uint8Array;
|
|
35
|
+
dataCrc32c: {
|
|
36
|
+
value: number;
|
|
37
|
+
};
|
|
38
|
+
}): Promise<readonly unknown[]>;
|
|
39
|
+
}
|
|
40
|
+
/** Opens existing software Ed25519 versions, or explicitly creates pending versions. */
|
|
41
|
+
declare class GcpCloudKmsKeyProvider implements KeyProvider {
|
|
42
|
+
private readonly client;
|
|
43
|
+
private readonly version;
|
|
44
|
+
private readonly keys;
|
|
45
|
+
private activeKid;
|
|
46
|
+
private readonly signing;
|
|
47
|
+
private activating;
|
|
48
|
+
private constructor();
|
|
49
|
+
/**
|
|
50
|
+
* Creates one version under an existing ASYMMETRIC_SIGN CryptoKey with a
|
|
51
|
+
* SOFTWARE EC_SIGN_ED25519 template, without opening any prior version.
|
|
52
|
+
* Returns a locally pending provider and immutable reference; activate(kid)
|
|
53
|
+
* explicitly before initial manager injection. Never provisions the parent,
|
|
54
|
+
* writes files, deletes keys, or closes the caller-owned client.
|
|
55
|
+
* Pending generation polls the same version at most 20 times, 250ms apart.
|
|
56
|
+
* Each transport call uses the caller's client timeout configuration.
|
|
57
|
+
* Failed/indeterminate creation may leave an operator-owned remote version;
|
|
58
|
+
* do not blindly retry. Normal load/configuration remains open-only.
|
|
59
|
+
*/
|
|
60
|
+
static create(client: GcpCloudKmsClient, config: {
|
|
61
|
+
parent: string;
|
|
62
|
+
algorithm: string;
|
|
63
|
+
}): Promise<{
|
|
64
|
+
provider: GcpCloudKmsKeyProvider;
|
|
65
|
+
kid: string;
|
|
66
|
+
keyRef: string;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Opens the selected active version and, optionally, an application-saved pending
|
|
70
|
+
* version for recovery. Both bindings are validated; the pending key supports
|
|
71
|
+
* JWK lookup and rotation proof signing but is not the active signer or live
|
|
72
|
+
* inventory. No discovery, generation, or activation occurs. Applications own
|
|
73
|
+
* durable references and recovery checks; activate performs the local transition.
|
|
74
|
+
*/
|
|
75
|
+
static load(client: GcpCloudKmsClient | undefined, config: GcpCloudKmsConfig): Promise<GcpCloudKmsKeyProvider>;
|
|
76
|
+
signingKey(): Promise<DnsIdJWK>;
|
|
77
|
+
jwk(kid: string): Promise<DnsIdJWK>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns only the current active key ID, or an empty list when no key is active.
|
|
80
|
+
* Pending and superseded keys are excluded from this live key list, even when
|
|
81
|
+
* their public JWKs remain available through `jwk` for historical verification.
|
|
82
|
+
*/
|
|
83
|
+
listKeyIds(): Promise<string[]>;
|
|
84
|
+
sign(payload: Uint8Array): Promise<Uint8Array>;
|
|
85
|
+
signKey(kid: string, payload: Uint8Array): Promise<Uint8Array>;
|
|
86
|
+
private signVersion;
|
|
87
|
+
validateKeyGeneration(algorithm: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Explicit operator generation only; defaults to EdDSA and rejects other algorithms before creation.
|
|
90
|
+
* Pending generation polls the exact created version at most 20 times, 250ms apart,
|
|
91
|
+
* using the caller's transport timeouts, just as initial creation does.
|
|
92
|
+
* Returns a locally pending key without changing the active signer. Failures after
|
|
93
|
+
* creation retain the version reference and cause, without retrying or deleting it.
|
|
94
|
+
* Service/integrity failures are not caller-argument errors. Never called by configuration opening.
|
|
95
|
+
*/
|
|
96
|
+
generateKey(algorithm?: string): Promise<string>;
|
|
97
|
+
private generatePendingKey;
|
|
98
|
+
activate(kid: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Removes local signing eligibility from an active, pending, or already
|
|
101
|
+
* superseded key. Superseding the active key leaves no active signer and an
|
|
102
|
+
* empty live key list; superseding another key does not clear its successor.
|
|
103
|
+
* The public JWK remains available through `jwk` for historical verification.
|
|
104
|
+
* Never disables, destroys, or otherwise mutates the remote CryptoKeyVersion.
|
|
105
|
+
*/
|
|
106
|
+
supersede(kid: string): Promise<void>;
|
|
107
|
+
/** Alias for local supersession; never disables or destroys a cloud version. */
|
|
108
|
+
purge(kid: string): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { type GcpCloudKmsClient, type GcpCloudKmsConfig, GcpCloudKmsKeyProvider };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { KeyProvider, DnsIdJWK } from '@dnsid-ai/protocol';
|
|
2
|
+
|
|
3
|
+
interface GcpCloudKmsConfig {
|
|
4
|
+
/** Fully qualified immutable CryptoKeyVersion resource name. */
|
|
5
|
+
activeKeyVersion: string;
|
|
6
|
+
/** Application-saved immutable pending version; never discovered or activated by load. */
|
|
7
|
+
pendingKeyVersion?: string;
|
|
8
|
+
/** Retained-key loading is not supported by this runtime slice. */
|
|
9
|
+
retainedKeyVersions?: string[];
|
|
10
|
+
/** Must be EC_SIGN_ED25519. */
|
|
11
|
+
algorithm: string;
|
|
12
|
+
}
|
|
13
|
+
/** Structural seam implemented by the official KeyManagementServiceClient. */
|
|
14
|
+
interface GcpCloudKmsClient {
|
|
15
|
+
/** Required only for initial creation; reads the existing signing parent/template. */
|
|
16
|
+
getCryptoKey?(request: {
|
|
17
|
+
name: string;
|
|
18
|
+
}): Promise<readonly unknown[]>;
|
|
19
|
+
/** Required when a newly created version is still PENDING_GENERATION. */
|
|
20
|
+
getCryptoKeyVersion?(request: {
|
|
21
|
+
name: string;
|
|
22
|
+
}): Promise<readonly unknown[]>;
|
|
23
|
+
createCryptoKeyVersion?(request: {
|
|
24
|
+
parent: string;
|
|
25
|
+
cryptoKeyVersion: {
|
|
26
|
+
state: 'ENABLED';
|
|
27
|
+
};
|
|
28
|
+
}): Promise<readonly unknown[]>;
|
|
29
|
+
getPublicKey(request: {
|
|
30
|
+
name: string;
|
|
31
|
+
}): Promise<readonly unknown[]>;
|
|
32
|
+
asymmetricSign(request: {
|
|
33
|
+
name: string;
|
|
34
|
+
data: Uint8Array;
|
|
35
|
+
dataCrc32c: {
|
|
36
|
+
value: number;
|
|
37
|
+
};
|
|
38
|
+
}): Promise<readonly unknown[]>;
|
|
39
|
+
}
|
|
40
|
+
/** Opens existing software Ed25519 versions, or explicitly creates pending versions. */
|
|
41
|
+
declare class GcpCloudKmsKeyProvider implements KeyProvider {
|
|
42
|
+
private readonly client;
|
|
43
|
+
private readonly version;
|
|
44
|
+
private readonly keys;
|
|
45
|
+
private activeKid;
|
|
46
|
+
private readonly signing;
|
|
47
|
+
private activating;
|
|
48
|
+
private constructor();
|
|
49
|
+
/**
|
|
50
|
+
* Creates one version under an existing ASYMMETRIC_SIGN CryptoKey with a
|
|
51
|
+
* SOFTWARE EC_SIGN_ED25519 template, without opening any prior version.
|
|
52
|
+
* Returns a locally pending provider and immutable reference; activate(kid)
|
|
53
|
+
* explicitly before initial manager injection. Never provisions the parent,
|
|
54
|
+
* writes files, deletes keys, or closes the caller-owned client.
|
|
55
|
+
* Pending generation polls the same version at most 20 times, 250ms apart.
|
|
56
|
+
* Each transport call uses the caller's client timeout configuration.
|
|
57
|
+
* Failed/indeterminate creation may leave an operator-owned remote version;
|
|
58
|
+
* do not blindly retry. Normal load/configuration remains open-only.
|
|
59
|
+
*/
|
|
60
|
+
static create(client: GcpCloudKmsClient, config: {
|
|
61
|
+
parent: string;
|
|
62
|
+
algorithm: string;
|
|
63
|
+
}): Promise<{
|
|
64
|
+
provider: GcpCloudKmsKeyProvider;
|
|
65
|
+
kid: string;
|
|
66
|
+
keyRef: string;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Opens the selected active version and, optionally, an application-saved pending
|
|
70
|
+
* version for recovery. Both bindings are validated; the pending key supports
|
|
71
|
+
* JWK lookup and rotation proof signing but is not the active signer or live
|
|
72
|
+
* inventory. No discovery, generation, or activation occurs. Applications own
|
|
73
|
+
* durable references and recovery checks; activate performs the local transition.
|
|
74
|
+
*/
|
|
75
|
+
static load(client: GcpCloudKmsClient | undefined, config: GcpCloudKmsConfig): Promise<GcpCloudKmsKeyProvider>;
|
|
76
|
+
signingKey(): Promise<DnsIdJWK>;
|
|
77
|
+
jwk(kid: string): Promise<DnsIdJWK>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns only the current active key ID, or an empty list when no key is active.
|
|
80
|
+
* Pending and superseded keys are excluded from this live key list, even when
|
|
81
|
+
* their public JWKs remain available through `jwk` for historical verification.
|
|
82
|
+
*/
|
|
83
|
+
listKeyIds(): Promise<string[]>;
|
|
84
|
+
sign(payload: Uint8Array): Promise<Uint8Array>;
|
|
85
|
+
signKey(kid: string, payload: Uint8Array): Promise<Uint8Array>;
|
|
86
|
+
private signVersion;
|
|
87
|
+
validateKeyGeneration(algorithm: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Explicit operator generation only; defaults to EdDSA and rejects other algorithms before creation.
|
|
90
|
+
* Pending generation polls the exact created version at most 20 times, 250ms apart,
|
|
91
|
+
* using the caller's transport timeouts, just as initial creation does.
|
|
92
|
+
* Returns a locally pending key without changing the active signer. Failures after
|
|
93
|
+
* creation retain the version reference and cause, without retrying or deleting it.
|
|
94
|
+
* Service/integrity failures are not caller-argument errors. Never called by configuration opening.
|
|
95
|
+
*/
|
|
96
|
+
generateKey(algorithm?: string): Promise<string>;
|
|
97
|
+
private generatePendingKey;
|
|
98
|
+
activate(kid: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Removes local signing eligibility from an active, pending, or already
|
|
101
|
+
* superseded key. Superseding the active key leaves no active signer and an
|
|
102
|
+
* empty live key list; superseding another key does not clear its successor.
|
|
103
|
+
* The public JWK remains available through `jwk` for historical verification.
|
|
104
|
+
* Never disables, destroys, or otherwise mutates the remote CryptoKeyVersion.
|
|
105
|
+
*/
|
|
106
|
+
supersede(kid: string): Promise<void>;
|
|
107
|
+
/** Alias for local supersession; never disables or destroys a cloud version. */
|
|
108
|
+
purge(kid: string): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { type GcpCloudKmsClient, type GcpCloudKmsConfig, GcpCloudKmsKeyProvider };
|