@learncard/sss-key-manager 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/escrow-attestation.d.ts +2 -9
  2. package/dist/escrow-attestation.d.ts.map +1 -1
  3. package/dist/escrow-authority.d.ts +112 -0
  4. package/dist/escrow-authority.d.ts.map +1 -0
  5. package/dist/escrow-authority.types.d.ts +51 -0
  6. package/dist/escrow-authority.types.d.ts.map +1 -0
  7. package/dist/escrow-crypto.d.ts +9 -1
  8. package/dist/escrow-crypto.d.ts.map +1 -1
  9. package/dist/escrow-enrollment-intent.d.ts +13 -0
  10. package/dist/escrow-enrollment-intent.d.ts.map +1 -0
  11. package/dist/escrow-enrollment-intent.types.d.ts +28 -0
  12. package/dist/escrow-enrollment-intent.types.d.ts.map +1 -0
  13. package/dist/escrow-nitro-attestation.d.ts +2 -0
  14. package/dist/escrow-nitro-attestation.d.ts.map +1 -1
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/sss-key-manager.cjs.development.js +1592 -213
  18. package/dist/sss-key-manager.cjs.development.js.map +4 -4
  19. package/dist/sss-key-manager.cjs.production.min.js +28 -23
  20. package/dist/sss-key-manager.cjs.production.min.js.map +4 -4
  21. package/dist/sss-key-manager.esm.js +1107 -163
  22. package/dist/sss-key-manager.esm.js.map +4 -4
  23. package/dist/sss-strategy.d.ts.map +1 -1
  24. package/dist/types.d.ts +16 -1
  25. package/dist/types.d.ts.map +1 -1
  26. package/package.json +2 -2
  27. package/src/__fixtures__/escrow-authority-v1.json +96 -0
  28. package/src/__fixtures__/escrow-carry-contact-contract-v1.json +33 -0
  29. package/src/__fixtures__/escrow-enrollment-intent-v1.json +26 -0
  30. package/src/__fixtures__/nitro-attestation-real/staging-nsm-document.json +16 -0
  31. package/src/escrow-attestation.ts +10 -9
  32. package/src/escrow-authority.test.ts +643 -0
  33. package/src/escrow-authority.ts +597 -0
  34. package/src/escrow-authority.types.ts +56 -0
  35. package/src/escrow-crypto.ts +39 -1
  36. package/src/escrow-enrollment-intent.test.ts +224 -0
  37. package/src/escrow-enrollment-intent.ts +236 -0
  38. package/src/escrow-enrollment-intent.types.ts +28 -0
  39. package/src/escrow-nitro-attestation.test.ts +72 -0
  40. package/src/escrow-nitro-attestation.ts +34 -3
  41. package/src/index.ts +27 -0
  42. package/src/sss-authority.test.ts +889 -0
  43. package/src/sss-strategy.ts +479 -38
  44. package/src/types.ts +22 -3
@@ -41,12 +41,18 @@ const bytes = (value: unknown, reason: NitroAttestationReason): Uint8Array =>
41
41
  value instanceof Uint8Array && value.length > 0 ? value : fail(reason);
42
42
  const map = (value: unknown, reason: NitroAttestationReason): Map<unknown, unknown> =>
43
43
  value instanceof Map ? value : fail(reason);
44
- const decodeCbor = (value: Uint8Array): unknown => {
44
+ /**
45
+ * `allowIndefinite` is only for the signed NSM payload: real AWS Nitro documents
46
+ * encode it as an indefinite-length map (0xbf). That is safe because the COSE
47
+ * signature below is verified over the original payload bytes, not a re-encoding.
48
+ * Everything else (COSE envelope, protected header, user_data) stays definite-only.
49
+ */
50
+ const decodeCbor = (value: Uint8Array, { allowIndefinite = false } = {}): unknown => {
45
51
  try {
46
52
  return decode(value, {
47
53
  useMaps: true,
48
54
  rejectDuplicateMapKeys: true,
49
- allowIndefinite: false,
55
+ allowIndefinite,
50
56
  allowUndefined: false,
51
57
  allowNaN: false,
52
58
  allowInfinity: false,
@@ -131,6 +137,8 @@ export const verifyNitroAttestationDocument = async (
131
137
  pcrs: Record<number, string>;
132
138
  timestamp: number;
133
139
  moduleId: string;
140
+ ledgerPublicKey?: string;
141
+ measurementHash?: string;
134
142
  }> => {
135
143
  let document: Uint8Array;
136
144
  try {
@@ -155,7 +163,7 @@ export const verifyNitroAttestationDocument = async (
155
163
  const payloadBytes = bytes(payloadValue, 'cose');
156
164
  const signature = bytes(signatureValue, 'signature');
157
165
  if (signature.length !== 96) fail('signature');
158
- const payload = map(decodeCbor(payloadBytes), 'cbor');
166
+ const payload = map(decodeCbor(payloadBytes, { allowIndefinite: true }), 'cbor');
159
167
  const moduleId = payload.get('module_id');
160
168
  const timestamp = payload.get('timestamp');
161
169
  if (typeof moduleId !== 'string' || !moduleId || payload.get('digest') !== 'SHA384')
@@ -275,6 +283,28 @@ export const verifyNitroAttestationDocument = async (
275
283
  } catch {
276
284
  return fail('user-data');
277
285
  }
286
+ const rawLedgerKey = payload.get('public_key');
287
+ let ledgerPublicKey: string | undefined;
288
+ let measurementHash: string | undefined;
289
+ if (rawLedgerKey !== undefined && rawLedgerKey !== null) {
290
+ const ledger = new Uint8Array(bytes(rawLedgerKey, 'user-data'));
291
+ if (ledger.length !== 65 || ledger[0] !== 4) fail('user-data');
292
+ try {
293
+ await crypto.subtle.importKey(
294
+ 'raw',
295
+ ledger,
296
+ { name: 'ECDSA', namedCurve: 'P-256' },
297
+ false,
298
+ ['verify']
299
+ );
300
+ } catch {
301
+ return fail('user-data');
302
+ }
303
+ const tuple = new Uint8Array(144);
304
+ for (let i = 0; i < 3; i++) tuple.set(bytes(rawPcrs.get(i), 'pcr'), i * 48);
305
+ measurementHash = hex(new Uint8Array(await crypto.subtle.digest('SHA-256', tuple)));
306
+ ledgerPublicKey = bufferToBase64(ledger.buffer);
307
+ }
278
308
  return {
279
309
  escrowPublicKeySpkiB64: bufferToBase64(new Uint8Array(spki).buffer),
280
310
  keyId: newFormat?.keyId,
@@ -282,5 +312,6 @@ export const verifyNitroAttestationDocument = async (
282
312
  pcrs,
283
313
  timestamp,
284
314
  moduleId,
315
+ ...(ledgerPublicKey ? { ledgerPublicKey, measurementHash } : {}),
285
316
  };
286
317
  };
package/src/index.ts CHANGED
@@ -76,7 +76,34 @@ export {
76
76
  } from './escrow-crypto';
77
77
 
78
78
  export type { EscrowEnvelope, EscrowBlobPlaintext, EscrowReleasePlaintext } from './escrow-crypto';
79
+ export {
80
+ encodeEscrowEnrollmentIntent,
81
+ signEscrowEnrollmentIntent,
82
+ getEscrowBlobIdentity,
83
+ ESCROW_ENROLLMENT_INTENT_DOMAIN,
84
+ } from './escrow-enrollment-intent';
85
+ export type {
86
+ EscrowEnrollmentIntent,
87
+ SignedEscrowEnrollmentIntent,
88
+ } from './escrow-enrollment-intent.types';
79
89
  export { verifyEnclaveAttestation } from './escrow-attestation';
90
+ export { EscrowEvidenceError } from './escrow-authority.types';
91
+ export type { HistoricalEscrowEvidence } from './escrow-authority.types';
92
+ export type { EscrowRecoveryExpectations } from '@learncard/types';
93
+ export {
94
+ verifyEscrowAuthorityState,
95
+ verifyEscrowEnrollmentCommit,
96
+ createEscrowEnrollmentIntent,
97
+ resolveEscrowEnrollmentAction,
98
+ violatesCarryContactRule,
99
+ } from './escrow-authority';
100
+ export type { EscrowEnrollmentActionInput } from './escrow-authority';
101
+ export type {
102
+ VerifiedEnclaveIdentity,
103
+ EscrowAuthorityRecord,
104
+ EscrowAuthorityState,
105
+ VerifiedEscrowMutation,
106
+ } from './escrow-authority.types';
80
107
  export { verifyNitroAttestationDocument, NitroAttestationError } from './escrow-nitro-attestation';
81
108
  export type { NitroAttestationReason } from './escrow-nitro-attestation';
82
109
  export type { EscrowAttestationPolicy, EscrowHoldStatus, EscrowRecoveryStart } from './types';