@push.rocks/smartsecret 1.0.2 → 1.2.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.
@@ -0,0 +1,758 @@
1
+ import * as plugins from './smartsecret.plugins.js';
2
+ import { SmartSecretKeyringError, createSmartSecretKeyringError, } from './smartsecret.keyring.error.js';
3
+ import { SMARTSECRET_KEYRING_MAX_CONTEXT_BYTES, SMARTSECRET_KEYRING_MAX_PAYLOAD_BYTES, SMARTSECRET_KEYRING_MIN_CONTEXT_BYTES, SMARTSECRET_KEYRING_PROFILE, SMARTSECRET_KEYRING_SCHEMA_VERSION, createSmartSecretPayloadDigest, createSmartSecretWrapAad, encodeCanonicalBase64Url, fingerprintToBytes, parseSmartSecretEnvelope, requireEpochMilliseconds, requireFingerprint, requireKekVersion, requireSmartSecretIdentifier, sha256Bytes, timingSafeEqual, wipeCiphertext, } from './smartsecret.keyring.protocol.js';
4
+ const descriptorKeys = [
5
+ 'version',
6
+ 'status',
7
+ 'credentialPath',
8
+ 'expectedFingerprint',
9
+ 'createdAt',
10
+ 'activatedAt',
11
+ 'retiredAt',
12
+ 'revokedAt',
13
+ 'escrowReference',
14
+ 'escrowedAt',
15
+ 'recoveryTestedAt',
16
+ ];
17
+ const requireConfigObject = (valueArg, allowedKeysArg, requiredKeysArg, errorCodeArg = 'CONFIG_INVALID') => {
18
+ try {
19
+ if (valueArg === null || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
20
+ throw createSmartSecretKeyringError(errorCodeArg);
21
+ }
22
+ const prototype = Object.getPrototypeOf(valueArg);
23
+ if (prototype !== Object.prototype && prototype !== null) {
24
+ throw createSmartSecretKeyringError(errorCodeArg);
25
+ }
26
+ const ownKeys = Reflect.ownKeys(valueArg);
27
+ if (ownKeys.length < requiredKeysArg.length
28
+ || ownKeys.length > allowedKeysArg.length
29
+ || ownKeys.some((keyArg) => typeof keyArg !== 'string')) {
30
+ throw createSmartSecretKeyringError(errorCodeArg);
31
+ }
32
+ const keys = ownKeys;
33
+ if (keys.some((keyArg) => !allowedKeysArg.includes(keyArg))
34
+ || requiredKeysArg.some((keyArg) => !keys.includes(keyArg))) {
35
+ throw createSmartSecretKeyringError(errorCodeArg);
36
+ }
37
+ const result = Object.create(null);
38
+ for (const key of keys) {
39
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
40
+ if (!descriptor?.enumerable || !('value' in descriptor)) {
41
+ throw createSmartSecretKeyringError(errorCodeArg);
42
+ }
43
+ result[key] = descriptor.value;
44
+ }
45
+ return result;
46
+ }
47
+ catch (error) {
48
+ if (error instanceof SmartSecretKeyringError) {
49
+ throw error;
50
+ }
51
+ throw createSmartSecretKeyringError(errorCodeArg);
52
+ }
53
+ };
54
+ const requireDescriptorArray = (valueArg) => {
55
+ try {
56
+ if (!Array.isArray(valueArg) || Object.getPrototypeOf(valueArg) !== Array.prototype) {
57
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
58
+ }
59
+ const ownKeys = Reflect.ownKeys(valueArg);
60
+ const lengthDescriptor = Object.getOwnPropertyDescriptor(valueArg, 'length');
61
+ if (!lengthDescriptor
62
+ || !('value' in lengthDescriptor)
63
+ || !Number.isSafeInteger(lengthDescriptor.value)
64
+ || lengthDescriptor.value < 0
65
+ || ownKeys.length !== lengthDescriptor.value + 1) {
66
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
67
+ }
68
+ if (ownKeys.some((keyArg) => typeof keyArg === 'symbol')) {
69
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
70
+ }
71
+ const result = new Array(lengthDescriptor.value);
72
+ for (let index = 0; index < lengthDescriptor.value; index++) {
73
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
74
+ if (!descriptor?.enumerable || !('value' in descriptor)) {
75
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
76
+ }
77
+ result[index] = descriptor.value;
78
+ }
79
+ return result;
80
+ }
81
+ catch (error) {
82
+ if (error instanceof SmartSecretKeyringError) {
83
+ throw error;
84
+ }
85
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
86
+ }
87
+ };
88
+ const requireOptionalTimestamp = (valueArg, keyArg) => {
89
+ if (!Object.hasOwn(valueArg, keyArg)) {
90
+ return undefined;
91
+ }
92
+ return requireEpochMilliseconds(valueArg[keyArg]);
93
+ };
94
+ const normalizeDescriptor = (valueArg) => {
95
+ const value = requireConfigObject(valueArg, descriptorKeys, [
96
+ 'version',
97
+ 'status',
98
+ 'createdAt',
99
+ 'activatedAt',
100
+ ]);
101
+ const version = requireKekVersion(value.version);
102
+ if (value.status !== 'active' && value.status !== 'retired' && value.status !== 'revoked') {
103
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
104
+ }
105
+ const status = value.status;
106
+ const createdAt = requireEpochMilliseconds(value.createdAt);
107
+ const activatedAt = requireEpochMilliseconds(value.activatedAt);
108
+ const retiredAt = requireOptionalTimestamp(value, 'retiredAt');
109
+ const revokedAt = requireOptionalTimestamp(value, 'revokedAt');
110
+ const escrowedAt = requireOptionalTimestamp(value, 'escrowedAt');
111
+ const recoveryTestedAt = requireOptionalTimestamp(value, 'recoveryTestedAt');
112
+ if (createdAt > activatedAt) {
113
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
114
+ }
115
+ if (status === 'active' && (retiredAt !== undefined || revokedAt !== undefined)) {
116
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
117
+ }
118
+ if (status === 'retired' && (retiredAt === undefined || revokedAt !== undefined)) {
119
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
120
+ }
121
+ if (status === 'revoked' && revokedAt === undefined) {
122
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
123
+ }
124
+ if (retiredAt !== undefined && retiredAt < activatedAt) {
125
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
126
+ }
127
+ if (revokedAt !== undefined && revokedAt < (retiredAt ?? activatedAt)) {
128
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
129
+ }
130
+ const hasEscrowReference = Object.hasOwn(value, 'escrowReference');
131
+ const hasEscrowedAt = escrowedAt !== undefined;
132
+ if (hasEscrowReference !== hasEscrowedAt) {
133
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
134
+ }
135
+ let escrowReference;
136
+ if (hasEscrowReference) {
137
+ escrowReference = requireSmartSecretIdentifier(value.escrowReference);
138
+ }
139
+ if (escrowedAt !== undefined && escrowedAt < createdAt) {
140
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
141
+ }
142
+ if (recoveryTestedAt !== undefined) {
143
+ if (escrowedAt === undefined || recoveryTestedAt < escrowedAt) {
144
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
145
+ }
146
+ if (revokedAt !== undefined && recoveryTestedAt > revokedAt) {
147
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
148
+ }
149
+ }
150
+ let credentialPath;
151
+ let expectedFingerprint;
152
+ if (status === 'revoked') {
153
+ if (Object.hasOwn(value, 'credentialPath') || Object.hasOwn(value, 'expectedFingerprint')) {
154
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
155
+ }
156
+ }
157
+ else {
158
+ if (typeof value.credentialPath !== 'string') {
159
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
160
+ }
161
+ credentialPath = value.credentialPath;
162
+ if (!plugins.path.isAbsolute(credentialPath)
163
+ || plugins.path.resolve(credentialPath) !== credentialPath) {
164
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
165
+ }
166
+ expectedFingerprint = requireFingerprint(value.expectedFingerprint);
167
+ }
168
+ return Object.freeze({
169
+ version,
170
+ status,
171
+ ...(credentialPath === undefined ? {} : { credentialPath }),
172
+ ...(expectedFingerprint === undefined ? {} : { expectedFingerprint }),
173
+ createdAt,
174
+ activatedAt,
175
+ ...(retiredAt === undefined ? {} : { retiredAt }),
176
+ ...(revokedAt === undefined ? {} : { revokedAt }),
177
+ ...(escrowReference === undefined ? {} : { escrowReference }),
178
+ ...(escrowedAt === undefined ? {} : { escrowedAt }),
179
+ ...(recoveryTestedAt === undefined ? {} : { recoveryTestedAt }),
180
+ });
181
+ };
182
+ const normalizeConfig = (valueArg) => {
183
+ const value = requireConfigObject(valueArg, ['keyringId', 'keys'], ['keyringId', 'keys']);
184
+ const keyringId = requireSmartSecretIdentifier(value.keyringId);
185
+ const descriptorValues = requireDescriptorArray(value.keys);
186
+ const descriptors = descriptorValues.map((descriptorArg) => normalizeDescriptor(descriptorArg));
187
+ if (descriptors.length === 0) {
188
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
189
+ }
190
+ for (let index = 1; index < descriptors.length; index++) {
191
+ if (descriptors[index - 1].version >= descriptors[index].version) {
192
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
193
+ }
194
+ }
195
+ const active = descriptors.filter((descriptorArg) => descriptorArg.status === 'active');
196
+ if (active.length !== 1) {
197
+ throw createSmartSecretKeyringError('CONFIG_INVALID');
198
+ }
199
+ return {
200
+ keyringId,
201
+ descriptors: Object.freeze(descriptors),
202
+ activeVersion: active[0].version,
203
+ };
204
+ };
205
+ const statsMatch = (leftArg, rightArg) => leftArg.dev === rightArg.dev
206
+ && leftArg.ino === rightArg.ino
207
+ && leftArg.mode === rightArg.mode
208
+ && leftArg.nlink === rightArg.nlink
209
+ && leftArg.uid === rightArg.uid
210
+ && leftArg.gid === rightArg.gid
211
+ && leftArg.rdev === rightArg.rdev
212
+ && leftArg.size === rightArg.size
213
+ && leftArg.mtimeNs === rightArg.mtimeNs
214
+ && leftArg.ctimeNs === rightArg.ctimeNs;
215
+ const statsIdentityMatches = (leftArg, rightArg) => leftArg.dev === rightArg.dev
216
+ && leftArg.ino === rightArg.ino
217
+ && leftArg.mode === rightArg.mode
218
+ && leftArg.uid === rightArg.uid
219
+ && leftArg.gid === rightArg.gid;
220
+ const lstatPathComponents = async (credentialPathArg) => {
221
+ const root = plugins.path.parse(credentialPathArg).root;
222
+ const relative = plugins.path.relative(root, credentialPathArg);
223
+ const components = relative.split(plugins.path.sep).filter(Boolean);
224
+ const result = [];
225
+ let currentPath = root;
226
+ const rootStats = await plugins.fs.promises.lstat(root, { bigint: true });
227
+ if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) {
228
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
229
+ }
230
+ result.push({ path: root, stats: rootStats });
231
+ for (let index = 0; index < components.length; index++) {
232
+ currentPath = plugins.path.join(currentPath, components[index]);
233
+ const stats = await plugins.fs.promises.lstat(currentPath, { bigint: true });
234
+ const isFinal = index === components.length - 1;
235
+ if (stats.isSymbolicLink()
236
+ || (isFinal ? !stats.isFile() : !stats.isDirectory())) {
237
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
238
+ }
239
+ result.push({ path: currentPath, stats });
240
+ }
241
+ return result;
242
+ };
243
+ const loadCredential = async (descriptorArg) => {
244
+ let handle;
245
+ let key;
246
+ let readBuffer;
247
+ let didFail = false;
248
+ try {
249
+ const credentialPath = descriptorArg.credentialPath;
250
+ const beforeComponents = await lstatPathComponents(credentialPath);
251
+ const beforeFinal = beforeComponents[beforeComponents.length - 1].stats;
252
+ if (typeof plugins.fs.constants.O_NOFOLLOW !== 'number') {
253
+ throw createSmartSecretKeyringError('PLATFORM_UNSUPPORTED');
254
+ }
255
+ handle = await plugins.fs.promises.open(credentialPath, plugins.fs.constants.O_RDONLY | plugins.fs.constants.O_NOFOLLOW);
256
+ const beforeFd = await handle.stat({ bigint: true });
257
+ if (!beforeFd.isFile()
258
+ || beforeFd.size !== 32n
259
+ || (beforeFd.mode & 18n) !== 0n
260
+ || !statsMatch(beforeFinal, beforeFd)) {
261
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
262
+ }
263
+ readBuffer = Buffer.alloc(33);
264
+ let totalBytesRead = 0;
265
+ while (totalBytesRead < readBuffer.byteLength) {
266
+ const { bytesRead } = await handle.read(readBuffer, totalBytesRead, readBuffer.byteLength - totalBytesRead, totalBytesRead);
267
+ if (bytesRead === 0) {
268
+ break;
269
+ }
270
+ totalBytesRead += bytesRead;
271
+ }
272
+ if (totalBytesRead !== 32) {
273
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
274
+ }
275
+ const afterFd = await handle.stat({ bigint: true });
276
+ const afterComponents = await lstatPathComponents(credentialPath);
277
+ if (beforeComponents.length !== afterComponents.length) {
278
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
279
+ }
280
+ for (let index = 0; index < beforeComponents.length - 1; index++) {
281
+ if (!statsIdentityMatches(beforeComponents[index].stats, afterComponents[index].stats)) {
282
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
283
+ }
284
+ }
285
+ const afterFinal = afterComponents[afterComponents.length - 1].stats;
286
+ if (!statsMatch(beforeFd, afterFd) || !statsMatch(afterFd, afterFinal)) {
287
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
288
+ }
289
+ key = new Uint8Array(readBuffer.subarray(0, 32));
290
+ const actualFingerprint = sha256Bytes(key);
291
+ const expectedFingerprint = fingerprintToBytes(descriptorArg.expectedFingerprint);
292
+ try {
293
+ if (!timingSafeEqual(actualFingerprint, expectedFingerprint)) {
294
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
295
+ }
296
+ }
297
+ finally {
298
+ actualFingerprint.fill(0);
299
+ expectedFingerprint.fill(0);
300
+ }
301
+ }
302
+ catch {
303
+ didFail = true;
304
+ }
305
+ finally {
306
+ readBuffer?.fill(0);
307
+ if (handle) {
308
+ try {
309
+ await handle.close();
310
+ }
311
+ catch {
312
+ didFail = true;
313
+ }
314
+ }
315
+ }
316
+ if (didFail || !key) {
317
+ key?.fill(0);
318
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
319
+ }
320
+ return key;
321
+ };
322
+ const copyBytes = (valueArg, minimumBytesArg, maximumBytesArg) => {
323
+ if (!(valueArg instanceof Uint8Array)) {
324
+ throw createSmartSecretKeyringError('INVALID_ARGUMENT');
325
+ }
326
+ if (valueArg.byteLength < minimumBytesArg || valueArg.byteLength > maximumBytesArg) {
327
+ throw createSmartSecretKeyringError('SIZE_LIMIT_EXCEEDED');
328
+ }
329
+ return new Uint8Array(valueArg);
330
+ };
331
+ const copyIdentifier = (valueArg) => {
332
+ try {
333
+ return requireSmartSecretIdentifier(valueArg);
334
+ }
335
+ catch {
336
+ throw createSmartSecretKeyringError('INVALID_ARGUMENT');
337
+ }
338
+ };
339
+ const encodeCiphertext = (valueArg) => ({
340
+ nonce: encodeCanonicalBase64Url(valueArg.nonce),
341
+ ciphertext: encodeCanonicalBase64Url(valueArg.ciphertext),
342
+ tag: encodeCanonicalBase64Url(valueArg.tag),
343
+ });
344
+ const wipeParsedEnvelope = (valueArg) => {
345
+ valueArg.contextDigest.fill(0);
346
+ valueArg.kekFingerprint.fill(0);
347
+ wipeCiphertext(valueArg.payload);
348
+ wipeCiphertext(valueArg.wrappedDek);
349
+ };
350
+ /**
351
+ * A Linux-only, immutable KEK snapshot for strict DEK/KEK envelopes.
352
+ * Envelope persistence and compare-and-swap coordination remain consumer responsibilities.
353
+ */
354
+ export class SmartSecretKeyring {
355
+ constructor(keyringId, descriptors, activeVersion, loadedKeys) {
356
+ this.keyringId = keyringId;
357
+ this.descriptors = descriptors;
358
+ this.activeVersion = activeVersion;
359
+ this.loadedKeys = loadedKeys;
360
+ this.destroyed = false;
361
+ }
362
+ static async create(configArg) {
363
+ if (process.platform !== 'linux') {
364
+ throw createSmartSecretKeyringError('PLATFORM_UNSUPPORTED');
365
+ }
366
+ const config = normalizeConfig(configArg);
367
+ const loadedKeys = new Map();
368
+ try {
369
+ for (const descriptor of config.descriptors) {
370
+ if (descriptor.status === 'revoked') {
371
+ continue;
372
+ }
373
+ let key;
374
+ try {
375
+ key = await loadCredential(descriptor);
376
+ loadedKeys.set(descriptor.version, { descriptor, key });
377
+ key = undefined;
378
+ }
379
+ finally {
380
+ key?.fill(0);
381
+ }
382
+ }
383
+ return new SmartSecretKeyring(config.keyringId, config.descriptors, config.activeVersion, loadedKeys);
384
+ }
385
+ catch (error) {
386
+ for (const loaded of loadedKeys.values()) {
387
+ loaded.key.fill(0);
388
+ }
389
+ if (error instanceof SmartSecretKeyringError) {
390
+ throw error;
391
+ }
392
+ throw createSmartSecretKeyringError('CREDENTIAL_FILE_INVALID');
393
+ }
394
+ }
395
+ requireAlive() {
396
+ if (this.destroyed) {
397
+ throw createSmartSecretKeyringError('DESTROYED');
398
+ }
399
+ }
400
+ requireEnvelopeKey(envelopeArg) {
401
+ if (envelopeArg.kek.keyringId !== this.keyringId) {
402
+ throw createSmartSecretKeyringError('KEK_UNAVAILABLE');
403
+ }
404
+ const loaded = this.loadedKeys.get(envelopeArg.kek.version);
405
+ if (!loaded || loaded.descriptor.status === 'revoked') {
406
+ throw createSmartSecretKeyringError('KEK_UNAVAILABLE');
407
+ }
408
+ if (envelopeArg.kek.fingerprint !== loaded.descriptor.expectedFingerprint) {
409
+ throw createSmartSecretKeyringError('KEK_FINGERPRINT_MISMATCH');
410
+ }
411
+ return new Uint8Array(loaded.key);
412
+ }
413
+ inspect() {
414
+ this.requireAlive();
415
+ return {
416
+ keyringId: this.keyringId,
417
+ activeVersion: this.activeVersion,
418
+ keys: this.descriptors.map((descriptorArg) => ({
419
+ version: descriptorArg.version,
420
+ status: descriptorArg.status,
421
+ ...(descriptorArg.expectedFingerprint === undefined
422
+ ? {}
423
+ : { expectedFingerprint: descriptorArg.expectedFingerprint }),
424
+ createdAt: descriptorArg.createdAt,
425
+ activatedAt: descriptorArg.activatedAt,
426
+ ...(descriptorArg.retiredAt === undefined ? {} : { retiredAt: descriptorArg.retiredAt }),
427
+ ...(descriptorArg.revokedAt === undefined ? {} : { revokedAt: descriptorArg.revokedAt }),
428
+ ...(descriptorArg.escrowReference === undefined
429
+ ? {}
430
+ : { escrowReference: descriptorArg.escrowReference }),
431
+ ...(descriptorArg.escrowedAt === undefined ? {} : { escrowedAt: descriptorArg.escrowedAt }),
432
+ ...(descriptorArg.recoveryTestedAt === undefined
433
+ ? {}
434
+ : { recoveryTestedAt: descriptorArg.recoveryTestedAt }),
435
+ })),
436
+ };
437
+ }
438
+ destroy() {
439
+ if (this.destroyed) {
440
+ return;
441
+ }
442
+ this.destroyed = true;
443
+ for (const loaded of this.loadedKeys.values()) {
444
+ loaded.key.fill(0);
445
+ }
446
+ }
447
+ async encryptEnvelope(optionsArg) {
448
+ this.requireAlive();
449
+ const options = requireConfigObject(optionsArg, ['envelopeId', 'plaintext', 'context', 'createdAt'], ['envelopeId', 'plaintext', 'context'], 'INVALID_ARGUMENT');
450
+ const envelopeId = copyIdentifier(options.envelopeId);
451
+ let createdAt;
452
+ try {
453
+ createdAt = options.createdAt === undefined
454
+ ? Date.now()
455
+ : requireEpochMilliseconds(options.createdAt);
456
+ }
457
+ catch {
458
+ throw createSmartSecretKeyringError('INVALID_ARGUMENT');
459
+ }
460
+ let plaintext;
461
+ let context;
462
+ let kek;
463
+ let kekFingerprint;
464
+ let contextDigest;
465
+ let dek;
466
+ let payload;
467
+ let wrappedDek;
468
+ let payloadDigest;
469
+ let wrapAad;
470
+ try {
471
+ plaintext = copyBytes(options.plaintext, 0, SMARTSECRET_KEYRING_MAX_PAYLOAD_BYTES);
472
+ context = copyBytes(options.context, SMARTSECRET_KEYRING_MIN_CONTEXT_BYTES, SMARTSECRET_KEYRING_MAX_CONTEXT_BYTES);
473
+ const active = this.loadedKeys.get(this.activeVersion);
474
+ kek = new Uint8Array(active.key);
475
+ kekFingerprint = fingerprintToBytes(active.descriptor.expectedFingerprint);
476
+ contextDigest = sha256Bytes(context);
477
+ dek = plugins.smartcrypto.generateDek();
478
+ try {
479
+ payload = await plugins.smartcrypto.aesGcmEncrypt({
480
+ key: dek,
481
+ plaintext,
482
+ aad: context,
483
+ });
484
+ payloadDigest = createSmartSecretPayloadDigest(payload);
485
+ wrapAad = createSmartSecretWrapAad({
486
+ envelopeId,
487
+ createdAt,
488
+ contextDigest,
489
+ payloadDigest,
490
+ keyringId: this.keyringId,
491
+ kekVersion: active.descriptor.version,
492
+ kekFingerprint,
493
+ });
494
+ wrappedDek = await plugins.smartcrypto.wrapDek({ dek, kek, wrapAad });
495
+ }
496
+ catch (error) {
497
+ if (error instanceof SmartSecretKeyringError) {
498
+ throw error;
499
+ }
500
+ throw createSmartSecretKeyringError('CRYPTO_OPERATION_FAILED');
501
+ }
502
+ return {
503
+ schemaVersion: SMARTSECRET_KEYRING_SCHEMA_VERSION,
504
+ profile: SMARTSECRET_KEYRING_PROFILE,
505
+ envelopeId,
506
+ createdAt,
507
+ contextDigest: encodeCanonicalBase64Url(contextDigest),
508
+ kek: {
509
+ keyringId: this.keyringId,
510
+ version: active.descriptor.version,
511
+ fingerprint: active.descriptor.expectedFingerprint,
512
+ },
513
+ payload: encodeCiphertext(payload),
514
+ wrappedDek: encodeCiphertext(wrappedDek),
515
+ };
516
+ }
517
+ finally {
518
+ plaintext?.fill(0);
519
+ context?.fill(0);
520
+ contextDigest?.fill(0);
521
+ dek?.fill(0);
522
+ kek?.fill(0);
523
+ kekFingerprint?.fill(0);
524
+ payloadDigest?.fill(0);
525
+ wrapAad?.fill(0);
526
+ wipeCiphertext(payload);
527
+ wipeCiphertext(wrappedDek);
528
+ }
529
+ }
530
+ async decryptEnvelope(optionsArg) {
531
+ this.requireAlive();
532
+ const options = requireConfigObject(optionsArg, ['envelope', 'expectedEnvelopeId', 'context'], ['envelope', 'expectedEnvelopeId', 'context'], 'INVALID_ARGUMENT');
533
+ const expectedEnvelopeId = copyIdentifier(options.expectedEnvelopeId);
534
+ const parsed = parseSmartSecretEnvelope(options.envelope);
535
+ let context;
536
+ let envelopeKey;
537
+ let contextDigest;
538
+ let payloadDigest;
539
+ let wrapAad;
540
+ let dek;
541
+ try {
542
+ context = copyBytes(options.context, SMARTSECRET_KEYRING_MIN_CONTEXT_BYTES, SMARTSECRET_KEYRING_MAX_CONTEXT_BYTES);
543
+ envelopeKey = this.requireEnvelopeKey(parsed.envelope);
544
+ contextDigest = sha256Bytes(context);
545
+ payloadDigest = createSmartSecretPayloadDigest(parsed.payload);
546
+ wrapAad = createSmartSecretWrapAad({
547
+ envelopeId: parsed.envelope.envelopeId,
548
+ createdAt: parsed.envelope.createdAt,
549
+ contextDigest: parsed.contextDigest,
550
+ payloadDigest,
551
+ keyringId: parsed.envelope.kek.keyringId,
552
+ kekVersion: parsed.envelope.kek.version,
553
+ kekFingerprint: parsed.kekFingerprint,
554
+ });
555
+ if (parsed.envelope.envelopeId !== expectedEnvelopeId) {
556
+ throw createSmartSecretKeyringError('ENVELOPE_ID_MISMATCH');
557
+ }
558
+ if (!timingSafeEqual(contextDigest, parsed.contextDigest)) {
559
+ throw createSmartSecretKeyringError('CONTEXT_MISMATCH');
560
+ }
561
+ try {
562
+ dek = await plugins.smartcrypto.unwrapDek({
563
+ wrappedDek: parsed.wrappedDek,
564
+ kek: envelopeKey,
565
+ wrapAad,
566
+ });
567
+ return await plugins.smartcrypto.aesGcmDecrypt({
568
+ key: dek,
569
+ encryptedData: parsed.payload,
570
+ aad: context,
571
+ });
572
+ }
573
+ catch {
574
+ throw createSmartSecretKeyringError('AUTHENTICATION_FAILED');
575
+ }
576
+ }
577
+ finally {
578
+ context?.fill(0);
579
+ contextDigest?.fill(0);
580
+ payloadDigest?.fill(0);
581
+ wrapAad?.fill(0);
582
+ envelopeKey?.fill(0);
583
+ dek?.fill(0);
584
+ wipeParsedEnvelope(parsed);
585
+ }
586
+ }
587
+ async rewrapEnvelope(optionsArg) {
588
+ this.requireAlive();
589
+ const options = requireConfigObject(optionsArg, ['envelope', 'expectedEnvelopeId', 'context', 'targetVersion'], ['envelope', 'expectedEnvelopeId', 'context'], 'INVALID_ARGUMENT');
590
+ const expectedEnvelopeId = copyIdentifier(options.expectedEnvelopeId);
591
+ const parsed = parseSmartSecretEnvelope(options.envelope);
592
+ let context;
593
+ let currentKey;
594
+ let targetKey;
595
+ let targetFingerprint;
596
+ let contextDigest;
597
+ let payloadDigest;
598
+ let currentWrapAad;
599
+ let newWrapAad;
600
+ let wrappedDek;
601
+ try {
602
+ context = copyBytes(options.context, SMARTSECRET_KEYRING_MIN_CONTEXT_BYTES, SMARTSECRET_KEYRING_MAX_CONTEXT_BYTES);
603
+ currentKey = this.requireEnvelopeKey(parsed.envelope);
604
+ if (options.targetVersion !== undefined) {
605
+ let targetVersion;
606
+ try {
607
+ targetVersion = requireKekVersion(options.targetVersion);
608
+ }
609
+ catch {
610
+ throw createSmartSecretKeyringError('TARGET_VERSION_MISMATCH');
611
+ }
612
+ if (targetVersion !== this.activeVersion) {
613
+ throw createSmartSecretKeyringError('TARGET_VERSION_MISMATCH');
614
+ }
615
+ }
616
+ const active = this.loadedKeys.get(this.activeVersion);
617
+ targetKey = new Uint8Array(active.key);
618
+ targetFingerprint = fingerprintToBytes(active.descriptor.expectedFingerprint);
619
+ contextDigest = sha256Bytes(context);
620
+ payloadDigest = createSmartSecretPayloadDigest(parsed.payload);
621
+ currentWrapAad = createSmartSecretWrapAad({
622
+ envelopeId: parsed.envelope.envelopeId,
623
+ createdAt: parsed.envelope.createdAt,
624
+ contextDigest: parsed.contextDigest,
625
+ payloadDigest,
626
+ keyringId: parsed.envelope.kek.keyringId,
627
+ kekVersion: parsed.envelope.kek.version,
628
+ kekFingerprint: parsed.kekFingerprint,
629
+ });
630
+ newWrapAad = createSmartSecretWrapAad({
631
+ envelopeId: parsed.envelope.envelopeId,
632
+ createdAt: parsed.envelope.createdAt,
633
+ contextDigest: parsed.contextDigest,
634
+ payloadDigest,
635
+ keyringId: this.keyringId,
636
+ kekVersion: active.descriptor.version,
637
+ kekFingerprint: targetFingerprint,
638
+ });
639
+ if (parsed.envelope.envelopeId !== expectedEnvelopeId) {
640
+ throw createSmartSecretKeyringError('ENVELOPE_ID_MISMATCH');
641
+ }
642
+ if (!timingSafeEqual(contextDigest, parsed.contextDigest)) {
643
+ throw createSmartSecretKeyringError('CONTEXT_MISMATCH');
644
+ }
645
+ try {
646
+ wrappedDek = await plugins.smartcrypto.rewrapDek({
647
+ wrappedDek: parsed.wrappedDek,
648
+ currentKek: currentKey,
649
+ currentWrapAad,
650
+ newKek: targetKey,
651
+ newWrapAad,
652
+ });
653
+ }
654
+ catch {
655
+ throw createSmartSecretKeyringError('AUTHENTICATION_FAILED');
656
+ }
657
+ return {
658
+ schemaVersion: parsed.envelope.schemaVersion,
659
+ profile: parsed.envelope.profile,
660
+ envelopeId: parsed.envelope.envelopeId,
661
+ createdAt: parsed.envelope.createdAt,
662
+ contextDigest: parsed.envelope.contextDigest,
663
+ kek: {
664
+ keyringId: this.keyringId,
665
+ version: active.descriptor.version,
666
+ fingerprint: active.descriptor.expectedFingerprint,
667
+ },
668
+ payload: { ...parsed.envelope.payload },
669
+ wrappedDek: encodeCiphertext(wrappedDek),
670
+ };
671
+ }
672
+ finally {
673
+ context?.fill(0);
674
+ contextDigest?.fill(0);
675
+ payloadDigest?.fill(0);
676
+ currentWrapAad?.fill(0);
677
+ newWrapAad?.fill(0);
678
+ currentKey?.fill(0);
679
+ targetKey?.fill(0);
680
+ targetFingerprint?.fill(0);
681
+ wipeCiphertext(wrappedDek);
682
+ wipeParsedEnvelope(parsed);
683
+ }
684
+ }
685
+ async recoverySelfTest(versionArg) {
686
+ this.requireAlive();
687
+ let version;
688
+ try {
689
+ version = requireKekVersion(versionArg);
690
+ }
691
+ catch {
692
+ throw createSmartSecretKeyringError('INVALID_ARGUMENT');
693
+ }
694
+ const loaded = this.loadedKeys.get(version);
695
+ if (!loaded || loaded.descriptor.status === 'revoked') {
696
+ throw createSmartSecretKeyringError('KEK_UNAVAILABLE');
697
+ }
698
+ let key;
699
+ let fingerprint;
700
+ let dek;
701
+ let keyringId;
702
+ let length;
703
+ let versionBytes;
704
+ let aad;
705
+ let wrappedDek;
706
+ let unwrappedDek;
707
+ try {
708
+ key = new Uint8Array(loaded.key);
709
+ fingerprint = fingerprintToBytes(loaded.descriptor.expectedFingerprint);
710
+ dek = plugins.smartcrypto.generateDek();
711
+ keyringId = Buffer.from(this.keyringId, 'utf8');
712
+ length = Buffer.allocUnsafe(4);
713
+ length.writeUInt32BE(keyringId.byteLength, 0);
714
+ versionBytes = Buffer.allocUnsafe(8);
715
+ versionBytes.writeBigUInt64BE(BigInt(version), 0);
716
+ aad = Buffer.concat([
717
+ Buffer.from('smartsecret-keyring-recovery-aad-v1', 'ascii'),
718
+ length,
719
+ keyringId,
720
+ versionBytes,
721
+ fingerprint,
722
+ ]);
723
+ try {
724
+ wrappedDek = await plugins.smartcrypto.wrapDek({ dek, kek: key, wrapAad: aad });
725
+ unwrappedDek = await plugins.smartcrypto.unwrapDek({
726
+ wrappedDek,
727
+ kek: key,
728
+ wrapAad: aad,
729
+ });
730
+ }
731
+ catch {
732
+ throw createSmartSecretKeyringError('CRYPTO_OPERATION_FAILED');
733
+ }
734
+ if (!timingSafeEqual(dek, unwrappedDek)) {
735
+ throw createSmartSecretKeyringError('CRYPTO_OPERATION_FAILED');
736
+ }
737
+ return {
738
+ keyringId: this.keyringId,
739
+ version,
740
+ status: loaded.descriptor.status,
741
+ fingerprint: loaded.descriptor.expectedFingerprint,
742
+ testedAt: Date.now(),
743
+ };
744
+ }
745
+ finally {
746
+ key?.fill(0);
747
+ fingerprint?.fill(0);
748
+ dek?.fill(0);
749
+ keyringId?.fill(0);
750
+ length?.fill(0);
751
+ versionBytes?.fill(0);
752
+ aad?.fill(0);
753
+ wipeCiphertext(wrappedDek);
754
+ unwrappedDek?.fill(0);
755
+ }
756
+ }
757
+ }
758
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzZWNyZXQua2V5cmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c2VjcmV0LmtleXJpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLDZCQUE2QixHQUM5QixNQUFNLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sRUFDTCxxQ0FBcUMsRUFDckMscUNBQXFDLEVBQ3JDLHFDQUFxQyxFQUNyQywyQkFBMkIsRUFDM0Isa0NBQWtDLEVBQ2xDLDhCQUE4QixFQUM5Qix3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLGtCQUFrQixFQUNsQix3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLGtCQUFrQixFQUNsQixpQkFBaUIsRUFDakIsNEJBQTRCLEVBQzVCLFdBQVcsRUFDWCxlQUFlLEVBQ2YsY0FBYyxHQUdmLE1BQU0sbUNBQW1DLENBQUM7QUFrRjNDLE1BQU0sY0FBYyxHQUFHO0lBQ3JCLFNBQVM7SUFDVCxRQUFRO0lBQ1IsZ0JBQWdCO0lBQ2hCLHFCQUFxQjtJQUNyQixXQUFXO0lBQ1gsYUFBYTtJQUNiLFdBQVc7SUFDWCxXQUFXO0lBQ1gsaUJBQWlCO0lBQ2pCLFlBQVk7SUFDWixrQkFBa0I7Q0FDVixDQUFDO0FBRVgsTUFBTSxtQkFBbUIsR0FBRyxDQUMxQixRQUFpQixFQUNqQixjQUFpQyxFQUNqQyxlQUFrQyxFQUNsQyxlQUFzRCxnQkFBZ0IsRUFDN0MsRUFBRTtJQUMzQixJQUFJLENBQUM7UUFDSCxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNqRixNQUFNLDZCQUE2QixDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMs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