@learncard/sss-key-manager 0.2.6 → 0.3.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.
Files changed (35) hide show
  1. package/README.md +9 -0
  2. package/dist/escrow-authority.d.ts +4 -3
  3. package/dist/escrow-authority.d.ts.map +1 -1
  4. package/dist/escrow-authority.types.d.ts +15 -0
  5. package/dist/escrow-authority.types.d.ts.map +1 -1
  6. package/dist/escrow-crypto.d.ts +19 -1
  7. package/dist/escrow-crypto.d.ts.map +1 -1
  8. package/dist/escrow-enrollment-intent.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/sss-key-manager.cjs.development.js +776 -89
  12. package/dist/sss-key-manager.cjs.development.js.map +3 -3
  13. package/dist/sss-key-manager.cjs.production.min.js +30 -30
  14. package/dist/sss-key-manager.cjs.production.min.js.map +4 -4
  15. package/dist/sss-key-manager.esm.js +778 -89
  16. package/dist/sss-key-manager.esm.js.map +3 -3
  17. package/dist/sss-strategy.d.ts +26 -0
  18. package/dist/sss-strategy.d.ts.map +1 -1
  19. package/dist/types.d.ts +28 -0
  20. package/dist/types.d.ts.map +1 -1
  21. package/package.json +2 -2
  22. package/src/__fixtures__/escrow-authority-brand-names-v1.json +29 -0
  23. package/src/__fixtures__/escrow-carry-contact-contract-v1.json +25 -1
  24. package/src/__fixtures__/escrow-email-brand-contract-v1.json +225 -0
  25. package/src/escrow-authority.test.ts +2 -0
  26. package/src/escrow-authority.ts +24 -7
  27. package/src/escrow-authority.types.ts +27 -0
  28. package/src/escrow-crypto.test.ts +75 -0
  29. package/src/escrow-crypto.ts +43 -1
  30. package/src/escrow-enrollment-intent.ts +2 -1
  31. package/src/index.ts +14 -2
  32. package/src/sss-authority.test.ts +392 -32
  33. package/src/sss-strategy.test.ts +238 -0
  34. package/src/sss-strategy.ts +245 -104
  35. package/src/types.ts +29 -0
@@ -37,6 +37,32 @@ export interface SSSStrategyConfig {
37
37
  escrow?: {
38
38
  enabled: boolean;
39
39
  attestation: EscrowAttestationPolicy;
40
+ /**
41
+ * The escrow authority's tenant label: the enclave's measured
42
+ * `ESCROW_AUTHORITY_TENANT`, which it signs into every authority record and
43
+ * requires in every signed enrollment intent. Used for everything the
44
+ * enclave verifies (intent tenant, authority state, hold, code-delivery and
45
+ * persisted recovery expectations). Everything else (X-Tenant-Id, email
46
+ * branding, same-tenant guards) keeps using {@link SSSStrategyConfig.tenantId}.
47
+ *
48
+ * Defaults to `tenantId` (then `'learncard'`). Set it explicitly when this app
49
+ * shares another tenant's single-tenant enclave, e.g. VetPass on LearnCard's
50
+ * (`'learncard'`). Must match `/^[A-Za-z0-9_-]{1,128}$/`.
51
+ */
52
+ authorityTenant?: string;
53
+ /**
54
+ * Display name sealed into the escrow blob for enclave-sent emails
55
+ * (D21, `recoveryBrand`), e.g. `'VetPass'`. Sealed only when the
56
+ * recovery email and language are (nitro enroll/replace), never on a
57
+ * carry. Unset: the enclave brands emails from its measured tenant label.
58
+ *
59
+ * Set only after every live enclave host runs the brand-aware image: an
60
+ * older image drops the field whenever it re-encrypts the blob.
61
+ * Must pass {@link canonicalEscrowEmailBrand} (ASCII letters, digits,
62
+ * space, `-`, `'`, `&`; 1-32 characters); `createSSSStrategy` throws
63
+ * otherwise.
64
+ */
65
+ emailBrand?: string;
40
66
  };
41
67
  /** Report enrollment failures without logging recovery material. */
42
68
  onEscrowError?: (err: unknown) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"sss-strategy.d.ts","sourceRoot":"","sources":["../src/sss-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACR,wBAAwB,EAaxB,uBAAuB,EAK1B,MAAM,SAAS,CAAC;AAsCjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAyC/D;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,QAAQ,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,iBAAiB,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,iBAAiB;IAC9B,0EAA0E;IAC1E,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,uBAAuB,CAAA;KAAE,CAAC;IAEpE,oEAAoE;IACpE,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAEvC;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAEpE,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,uDAAuD;IACvD,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAE9B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,kBAAkB,CAAC;IAEnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AA0BD,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAiBhD,2FAA2F;AAC3F,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,yBAAyB,CAAC;IAChC,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,gFAAgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;aAErB,MAAM,EAAE,MAAM;aACd,MAAM,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,YAAY;gBADtD,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,YAAY,YAAA;CAK7E;AAED,kFAAkF;AAClF,qBAAa,6BAA8B,SAAQ,KAAK;;CAKvD;AAiLD;;;GAGG;AACH,qBAAa,oCAAqC,SAAQ,KAAK;gBAC/C,OAAO,EAAE,MAAM;CAI9B;AA+ED,2EAA2E;AAC3E,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD,eAAO,MAAM,oCAAoC,GAC7C,WAAW,MAAM,EACjB,uBAAgD,KACjD,MAAM,EAoBR,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,eAAO,MAAM,yBAAyB,GAAI,YAAY,MAAM,EAAE,cAAc,MAAM,KAAG,MACT,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACjC,OAAO,MAAM,KACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CAY9C,CAAC;AAqDF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,WAAW,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAI1E,CAAC;AAOF,uFAAuF;AACvF,eAAO,MAAM,uBAAuB,QAAiB,CAAC;AAGtD,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GACnC,SAAS,mBAAmB,EAC5B,YAAY,MAAM,KACnB,OAAO,CAAC,qBAAqB,EAAE,CA0BjC,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,2BAA2B,GACpC,SAAS,mBAAmB,EAC5B,YAAY,MAAM,KACnB,OAAO,CAAC,IAAI,CAAsD,CAAC;AAEtE,0FAA0F;AAC1F,eAAO,MAAM,2BAA2B,GACpC,SAAS,mBAAmB,EAC5B,YAAY,qBAAqB,EAAE,EACnC,YAAY,MAAM,KACnB,OAAO,CAAC,IAAI,CAGd,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,GACjC,SAAS,mBAAmB,EAC5B,WAAW,qBAAqB,EAChC,YAAY,MAAM,KACnB,OAAO,CAAC,IAAI,CAUd,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,2BAA2B,GACpC,SAAS,mBAAmB,EAC5B,OAAO,MAAM,EACb,YAAY,MAAM,KACnB,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF,UAAU,oBAAoB;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GACtC,SAAS,mBAAmB,EAC5B,WAAW,MAAM,GAAG,SAAS,EAC7B,cAAc,MAAM,OAAO,CAAC,oBAAoB,CAAC,EACjD,aAAa,MAAM,EACnB,mBAAmB,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACnD,mBAAkB,MAAM,IAAe,EACvC,aAAa,CAAC,QAAQ,EAAE,oBAAoB,KAAK,IAAI,EACrD,kBAAkB,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAC9D,OAAO,CAAC;IAAE,QAAQ,EAAE,oBAAoB,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAwGvE,CAAC;AAgJF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,wBAAwB,CA4yGrF;AAED,YAAY,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"sss-strategy.d.ts","sourceRoot":"","sources":["../src/sss-strategy.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -78,6 +78,28 @@ export type EscrowRecoveryStart = EscrowHoldStatus & {
78
78
  export declare class EscrowPinUnavailableError extends Error {
79
79
  constructor();
80
80
  }
81
+ /**
82
+ * What this client saw during one PIN sign-in flow (own-typos rule, E). A flow starts
83
+ * with the first PIN status read before the first attempt and ends when the sign-in
84
+ * completes; a new modal or app start begins a new flow.
85
+ */
86
+ export interface EscrowPinAttemptContext {
87
+ /**
88
+ * Verified wrong entries recorded against the PIN when the flow started, before
89
+ * any attempt here. Undefined when the server could not say (legacy record, failed
90
+ * read): treated as "wrong entries recorded".
91
+ */
92
+ priorWrongAttempts?: number;
93
+ /** Wrong entries this client itself submitted in this flow (mismatch responses). */
94
+ ownWrongAttempts: number;
95
+ /**
96
+ * Salt of the PIN generation the counts belong to (from the flow's first status).
97
+ * A status read during the release that shows another salt (a new PIN, or a
98
+ * same-PIN re-set elsewhere) means the counts describe a different PIN, so they
99
+ * are ignored and the stricter #1905 rule applies.
100
+ */
101
+ pinSalt?: string;
102
+ }
81
103
  /** A failed PIN attempt consumes its hold; another attempt must start a fresh hold. */
82
104
  export declare class EscrowPinMismatchError extends Error {
83
105
  readonly attemptsRemaining: number;
@@ -128,6 +150,12 @@ export type RecoveryInput = {
128
150
  expectedDid?: string;
129
151
  /** Verified recovery-email session; set only when no login is bound yet. */
130
152
  recoverySessionToken?: string;
153
+ /**
154
+ * Own-typos rule (E): wrong entries this client observed in the current PIN
155
+ * sign-in flow. Omitted by older callers, which keeps the stricter rule (any
156
+ * recorded wrong entry blocks the same-PIN re-set).
157
+ */
158
+ pinAttempts?: EscrowPinAttemptContext;
131
159
  } | {
132
160
  method: 'escrow';
133
161
  holdId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/sss-key-manager",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "Shamir Secret Sharing key manager for LearnCard - replaces Web3Auth SFA",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/sss-key-manager.esm.js",
@@ -39,7 +39,7 @@
39
39
  "vitest": "4.1.11"
40
40
  },
41
41
  "dependencies": {
42
- "@learncard/types": "5.24.1",
42
+ "@learncard/types": "6.0.0",
43
43
  "@noble/ed25519": "^2.0.0",
44
44
  "@peculiar/x509": "^2.1.0",
45
45
  "@scure/bip39": "^1.2.1",
@@ -0,0 +1,29 @@
1
+ {
2
+ "description": "Authority label -> fallback email brand. Rust brand_name (escrow-enclave-app/src/authority/email.rs) and TS escrowAuthorityBrandName (learn-card-base/src/config/authConfig.ts) must both map every case exactly; changing either side means updating this file.",
3
+ "cases": [
4
+ {
5
+ "label": "learncard",
6
+ "brand": "LearnCard"
7
+ },
8
+ {
9
+ "label": "scouts",
10
+ "brand": "ScoutPass"
11
+ },
12
+ {
13
+ "label": "vetpass",
14
+ "brand": "vetpass"
15
+ },
16
+ {
17
+ "label": "other",
18
+ "brand": "other"
19
+ },
20
+ {
21
+ "label": "LearnCard",
22
+ "brand": "LearnCard"
23
+ },
24
+ {
25
+ "label": "scoutpass",
26
+ "brand": "scoutpass"
27
+ }
28
+ ]
29
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "P2-d cross-language contract: the enclave authority policy (apply_enrollment_intent, authority.rs) rejects a Carry target blob whose PLAINTEXT already carries a non-null recoveryEmail/recoveryLanguage — on carry the enclave always fills those fields in from the source blob instead — but accepts the identical blob shape for Enroll/Replace (where the signed intent is required to bind a matching contact instead). Rust (policy/authority/tests.rs) builds and submits a real target blob with each case's fields and asserts apply_enrollment_intent's accept/reject outcome through the real enclave policy; TypeScript (escrow-authority.test.ts) asserts the same outcome via resolveEscrowEnrollmentAction plus the same rule the enclave enforces. Each case is independent: did/shareVersion/epoch are illustrative, not cross-referenced. recoveryEmail/recoveryLanguage are always both-null or both-set, matching the blob plaintext's own format invariant.",
2
+ "description": "P2-d cross-language contract: the enclave authority policy (apply_enrollment_intent, authority.rs) rejects a Carry target blob whose PLAINTEXT already carries a non-null recoveryEmail/recoveryLanguage — on carry the enclave always fills those fields in from the source blob instead — but accepts the identical blob shape for Enroll/Replace (where the signed intent is required to bind a matching contact instead). Rust (policy/authority/tests.rs) builds and submits a real target blob with each case's fields and asserts apply_enrollment_intent's accept/reject outcome through the real enclave policy; TypeScript (escrow-authority.test.ts) asserts the same outcome via resolveEscrowEnrollmentAction plus the same rule the enclave enforces. Each case is independent: did/shareVersion/epoch are illustrative, not cross-referenced. recoveryEmail/recoveryLanguage are always both-null or both-set, matching the blob plaintext's own format invariant. D21: blobRecoveryBrand (optional; absent means null) follows the same Carry rule: a Carry target that claims a sealed email brand is refused (the enclave inherits the source's), while Enroll/Replace keep whatever brand the owner sealed (the brand is not in the signed intent).",
3
3
  "cases": [
4
4
  {
5
5
  "name": "enroll accepts a target with contact fields",
@@ -28,6 +28,30 @@
28
28
  "blobRecoveryEmail": null,
29
29
  "blobRecoveryLanguage": null,
30
30
  "expected": "accept"
31
+ },
32
+ {
33
+ "name": "enroll accepts a target with contact fields and a sealed brand",
34
+ "action": "enroll",
35
+ "blobRecoveryEmail": "owner@example.com",
36
+ "blobRecoveryLanguage": "en",
37
+ "blobRecoveryBrand": "VetPass",
38
+ "expected": "accept"
39
+ },
40
+ {
41
+ "name": "replace accepts a target with contact fields and a sealed brand",
42
+ "action": "replace",
43
+ "blobRecoveryEmail": "owner@example.com",
44
+ "blobRecoveryLanguage": "en",
45
+ "blobRecoveryBrand": "VetPass",
46
+ "expected": "accept"
47
+ },
48
+ {
49
+ "name": "carry rejects a target that carries only a sealed brand",
50
+ "action": "carry",
51
+ "blobRecoveryEmail": null,
52
+ "blobRecoveryLanguage": null,
53
+ "blobRecoveryBrand": "VetPass",
54
+ "expected": "reject"
31
55
  }
32
56
  ]
33
57
  }
@@ -0,0 +1,225 @@
1
+ {
2
+ "description": "D21 cross-language contract for the owner-sealed escrow email brand (recoveryBrand). Rust canonical_brand (services/escrow-enclave-app/src/crypto.rs) and TypeScript canonicalEscrowEmailBrand (escrow-crypto.ts) must map every input to the same canonical form, or both reject it (expected: null). Rules: trim and collapse runs of ASCII space (0x20) only; any other whitespace or control character rejects; allowed characters are A-Z a-z 0-9, space, '-', ''' and '&'; first character a letter; 1-32 characters after canonicalization; at most 3 digits in total (not per run); no 'http' or 'www' in any case. Never make these rules stricter without a migration: stored blobs are re-checked on every decrypt.",
3
+ "cases": [
4
+ {
5
+ "name": "plain brand",
6
+ "input": "VetPass",
7
+ "expected": "VetPass"
8
+ },
9
+ {
10
+ "name": "LearnCard",
11
+ "input": "LearnCard",
12
+ "expected": "LearnCard"
13
+ },
14
+ {
15
+ "name": "ScoutPass",
16
+ "input": "ScoutPass",
17
+ "expected": "ScoutPass"
18
+ },
19
+ {
20
+ "name": "trims and collapses ASCII spaces",
21
+ "input": " Learn Card ",
22
+ "expected": "Learn Card"
23
+ },
24
+ {
25
+ "name": "allowed punctuation",
26
+ "input": "Learn-Card's & Co",
27
+ "expected": "Learn-Card's & Co"
28
+ },
29
+ {
30
+ "name": "three digits allowed",
31
+ "input": "Pass 123",
32
+ "expected": "Pass 123"
33
+ },
34
+ {
35
+ "name": "exactly 32 characters",
36
+ "input": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
37
+ "expected": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
38
+ },
39
+ {
40
+ "name": "32 after collapsing",
41
+ "input": " Aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbb ",
42
+ "expected": "Aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbb"
43
+ },
44
+ {
45
+ "name": "33 characters",
46
+ "input": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
47
+ "expected": null
48
+ },
49
+ {
50
+ "name": "empty",
51
+ "input": "",
52
+ "expected": null
53
+ },
54
+ {
55
+ "name": "only spaces",
56
+ "input": " ",
57
+ "expected": null
58
+ },
59
+ {
60
+ "name": "leading digit",
61
+ "input": "1Pass",
62
+ "expected": null
63
+ },
64
+ {
65
+ "name": "leading hyphen",
66
+ "input": "-Pass",
67
+ "expected": null
68
+ },
69
+ {
70
+ "name": "four-digit run",
71
+ "input": "a1234",
72
+ "expected": null
73
+ },
74
+ {
75
+ "name": "code split by spaces",
76
+ "input": "Code 123 456 78",
77
+ "expected": null
78
+ },
79
+ {
80
+ "name": "phone split by hyphens",
81
+ "input": "A 555-123-456",
82
+ "expected": null
83
+ },
84
+ {
85
+ "name": "pin split into pairs",
86
+ "input": "Pin 12-34-56-78",
87
+ "expected": null
88
+ },
89
+ {
90
+ "name": "four digits apart",
91
+ "input": "A1 B2 C3 D4",
92
+ "expected": null
93
+ },
94
+ {
95
+ "name": "three digits apart",
96
+ "input": "A1 B2 C3",
97
+ "expected": "A1 B2 C3"
98
+ },
99
+ {
100
+ "name": "phone look-alike",
101
+ "input": "Call 5551234",
102
+ "expected": null
103
+ },
104
+ {
105
+ "name": "http substring",
106
+ "input": "http",
107
+ "expected": null
108
+ },
109
+ {
110
+ "name": "HTTP any case",
111
+ "input": "MyHttpBrand",
112
+ "expected": null
113
+ },
114
+ {
115
+ "name": "www substring",
116
+ "input": "Www Brand",
117
+ "expected": null
118
+ },
119
+ {
120
+ "name": "carriage return",
121
+ "input": "Vet\rPass",
122
+ "expected": null
123
+ },
124
+ {
125
+ "name": "line feed",
126
+ "input": "Vet\nPass",
127
+ "expected": null
128
+ },
129
+ {
130
+ "name": "CRLF header injection",
131
+ "input": "VetPass\r\nBcc: x",
132
+ "expected": null
133
+ },
134
+ {
135
+ "name": "tab",
136
+ "input": "Vet\tPass",
137
+ "expected": null
138
+ },
139
+ {
140
+ "name": "leading tab is not trimmed",
141
+ "input": "\tVetPass",
142
+ "expected": null
143
+ },
144
+ {
145
+ "name": "NBSP",
146
+ "input": "Vet Pass",
147
+ "expected": null
148
+ },
149
+ {
150
+ "name": "line separator",
151
+ "input": "Vet
Pass",
152
+ "expected": null
153
+ },
154
+ {
155
+ "name": "RLO bidi override",
156
+ "input": "Vet‮Pass",
157
+ "expected": null
158
+ },
159
+ {
160
+ "name": "LRI bidi isolate",
161
+ "input": "Vet⁦Pass",
162
+ "expected": null
163
+ },
164
+ {
165
+ "name": "zero-width space",
166
+ "input": "Vet​Pass",
167
+ "expected": null
168
+ },
169
+ {
170
+ "name": "Cyrillic homoglyph",
171
+ "input": "VеtPass",
172
+ "expected": null
173
+ },
174
+ {
175
+ "name": "accented letter",
176
+ "input": "Café",
177
+ "expected": null
178
+ },
179
+ {
180
+ "name": "less-than",
181
+ "input": "Vet<Pass",
182
+ "expected": null
183
+ },
184
+ {
185
+ "name": "double quote",
186
+ "input": "Vet\"Pass",
187
+ "expected": null
188
+ },
189
+ {
190
+ "name": "backslash",
191
+ "input": "Vet\\Pass",
192
+ "expected": null
193
+ },
194
+ {
195
+ "name": "at sign",
196
+ "input": "Vet@Pass",
197
+ "expected": null
198
+ },
199
+ {
200
+ "name": "dot",
201
+ "input": "vetpass.com",
202
+ "expected": null
203
+ },
204
+ {
205
+ "name": "slash",
206
+ "input": "Vet/Pass",
207
+ "expected": null
208
+ },
209
+ {
210
+ "name": "colon",
211
+ "input": "Vet:Pass",
212
+ "expected": null
213
+ },
214
+ {
215
+ "name": "percent",
216
+ "input": "Vet%Pass",
217
+ "expected": null
218
+ },
219
+ {
220
+ "name": "NUL",
221
+ "input": "Vet\u0000Pass",
222
+ "expected": null
223
+ }
224
+ ]
225
+ }
@@ -288,6 +288,7 @@ describe('violatesCarryContactRule (P2-d cross-language contract)', () => {
288
288
  action: 'enroll' | 'replace' | 'disable' | 'carry';
289
289
  blobRecoveryEmail: string | null;
290
290
  blobRecoveryLanguage: string | null;
291
+ blobRecoveryBrand?: string | null;
291
292
  expected: 'accept' | 'reject';
292
293
  }[]
293
294
  ).map(c => [c.name, c] as const)
@@ -295,6 +296,7 @@ describe('violatesCarryContactRule (P2-d cross-language contract)', () => {
295
296
  const violates = violatesCarryContactRule(testCase.action, {
296
297
  recoveryEmail: testCase.blobRecoveryEmail ?? undefined,
297
298
  recoveryLanguage: testCase.blobRecoveryLanguage ?? undefined,
299
+ recoveryBrand: testCase.blobRecoveryBrand ?? undefined,
298
300
  });
299
301
  expect(violates).toBe(testCase.expected === 'reject');
300
302
  });
@@ -1,6 +1,10 @@
1
1
  import { base64ToBuffer, bufferToBase64, bytesToHex } from './crypto';
2
2
  import { parseEscrowEnvelope } from './escrow-crypto';
3
- import { EscrowEvidenceError } from './escrow-authority.types';
3
+ import {
4
+ ESCROW_AUTHORITY_TENANT_PATTERN,
5
+ EscrowAuthorityTenantMismatchError,
6
+ EscrowEvidenceError,
7
+ } from './escrow-authority.types';
4
8
  import type { HistoricalEscrowEvidence } from './escrow-authority.types';
5
9
  import type { EscrowAttestationPolicy } from './types';
6
10
  import {
@@ -100,6 +104,14 @@ export const verifyEscrowCodeDelivery = async (
100
104
  const requireEvidence = (condition: boolean): void => {
101
105
  if (!condition) fail();
102
106
  };
107
+ /** Only after the signature verified: a well-formed but different signed tenant is a
108
+ * deployment misconfiguration (wrong `escrowAuthorityTenant`), reported specifically. */
109
+ const requireAuthorityTenant = (signedTenant: unknown, expectedTenant: string): void => {
110
+ if (signedTenant === expectedTenant) return;
111
+ if (typeof signedTenant === 'string' && ESCROW_AUTHORITY_TENANT_PATTERN.test(signedTenant))
112
+ throw new EscrowAuthorityTenantMismatchError(expectedTenant, signedTenant);
113
+ fail();
114
+ };
103
115
  const object = (value: unknown): Record<string, unknown> => {
104
116
  if (!value || typeof value !== 'object' || Array.isArray(value)) return fail();
105
117
  return value as Record<string, unknown>;
@@ -335,7 +347,8 @@ export const verifyEscrowAuthorityState = async (
335
347
  const { payload } = await verifyRecord(raw.proof, 'snapshot', identity);
336
348
  if (!Array.isArray(payload) || payload.length !== 2 || payload[0] !== nonce) return fail();
337
349
  const signed = state(payload[1]);
338
- requireEvidence(signed.tenant === tenant && signed.did === did);
350
+ requireEvidence(signed.did === did);
351
+ requireAuthorityTenant(signed.tenant, tenant);
339
352
  requireEvidence(JSON.stringify(signed) === JSON.stringify(state(raw.state)));
340
353
  if (signed.envelope) {
341
354
  requireEvidence(
@@ -497,7 +510,8 @@ export const verifyEscrowHoldRecord = async (
497
510
  keys(commit, ['schemaVersion', 'binding', 'executionId', 'revisions', 'transactionDigest']);
498
511
  const binding = object(commit.binding);
499
512
  keys(binding, ['tenant', 'generation', 'didHash']);
500
- requireEvidence(commit.schemaVersion === 1 && binding.tenant === expected.tenant);
513
+ requireEvidence(commit.schemaVersion === 1);
514
+ requireAuthorityTenant(binding.tenant, expected.tenant);
501
515
  const authorityGeneration = text(binding.generation, 128);
502
516
  if (historical) requireEvidence(authorityGeneration === historical.authorityGeneration);
503
517
  requireEvidence(bytesToHex(bytes(binding.didHash, 32)) === (await hash(utf8(expected.did))));
@@ -608,16 +622,19 @@ export const resolveEscrowEnrollmentAction = (
608
622
  /** P2-d cross-language contract: mirrors the enclave's Carry contact-field
609
623
  * rejection rule (`apply_enrollment_intent` in authority.rs) — true means
610
624
  * the enclave would refuse this target blob. The enclave always fills
611
- * recoveryEmail/recoveryLanguage in from the source blob on carry, so a
612
- * target that already claims either field is refused. Shared by
625
+ * recoveryEmail/recoveryLanguage (and, D21, the sealed recoveryBrand) in from
626
+ * the source blob on carry, so a target that already claims any of them is
627
+ * refused. Shared by
613
628
  * `escrow-carry-contact-contract-v1.json`'s TS and Rust tests, and by any
614
629
  * caller (e.g. a test fake) that wants to fail the same way the real
615
630
  * enclave does instead of accepting a shape it would reject. */
616
631
  export const violatesCarryContactRule = (
617
632
  action: EscrowEnrollmentIntent['action'],
618
- target: Pick<EscrowBlobPlaintext, 'recoveryEmail' | 'recoveryLanguage'> | null
633
+ target: Pick<EscrowBlobPlaintext, 'recoveryEmail' | 'recoveryLanguage' | 'recoveryBrand'> | null
619
634
  ): boolean =>
620
- action === 'carry' && !!target && (!!target.recoveryEmail || !!target.recoveryLanguage);
635
+ action === 'carry' &&
636
+ !!target &&
637
+ (!!target.recoveryEmail || !!target.recoveryLanguage || !!target.recoveryBrand);
621
638
 
622
639
  /** Owner-only mutation selection. Recovery itself never calls this helper.
623
640
  * P9.1 (attack C): `recoveryEmail`/`recoveryLanguage` are always supplied by the
@@ -8,6 +8,33 @@ export class EscrowEvidenceError extends Error {
8
8
  }
9
9
  }
10
10
 
11
+ /** Shape of an escrow authority tenant label (mirrors the enclave's measured label check). */
12
+ export const ESCROW_AUTHORITY_TENANT_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
13
+
14
+ /**
15
+ * Validly signed evidence bound to a different authority tenant than this client expects.
16
+ * The enclave is single-tenant (its measured `ESCROW_AUTHORITY_TENANT` label), so this is
17
+ * a deployment misconfiguration, not a forgery: the app's `escrowAuthorityTenant` does not
18
+ * match the enclave it talks to. Still an {@link EscrowEvidenceError}, so every existing
19
+ * fail-closed path treats it the same way; only the message is specific. Labels are public
20
+ * deployment identifiers, never user data.
21
+ */
22
+ export class EscrowAuthorityTenantMismatchError extends EscrowEvidenceError {
23
+ readonly expectedTenant: string;
24
+ readonly signedTenant: string;
25
+
26
+ constructor(expectedTenant: string, signedTenant: string) {
27
+ super();
28
+ this.name = 'EscrowAuthorityTenantMismatchError';
29
+ this.expectedTenant = expectedTenant;
30
+ this.signedTenant = signedTenant;
31
+ this.message =
32
+ `Escrow authority tenant mismatch: the enclave signed for "${signedTenant}" but this ` +
33
+ `app expects "${expectedTenant}". Set auth.sss.escrowAuthorityTenant to the ` +
34
+ `enclave's ESCROW_AUTHORITY_TENANT.`;
35
+ }
36
+ }
37
+
11
38
  /** Opt-in for previously issued hold evidence only. Measurements are SHA-256
12
39
  * hashes of complete configured PCR0/1/2 tuples, never server-supplied values.
13
40
  * The original authority generation and current attested ledger key remain pinned.
@@ -7,6 +7,7 @@ import {
7
7
  ESCROW_CLIENT_KEY_ID,
8
8
  ESCROW_ENVELOPE_VERSION,
9
9
  ESCROW_RELEASE_INFO,
10
+ canonicalEscrowEmailBrand,
10
11
  decryptEscrowBlob,
11
12
  encryptEscrowBlob,
12
13
  generateEscrowKeyPair,
@@ -17,6 +18,7 @@ import {
17
18
  sealEscrowRelease,
18
19
  } from './escrow-crypto';
19
20
  import type { EscrowEnvelope } from './escrow-crypto';
21
+ import brandContract from './__fixtures__/escrow-email-brand-contract-v1.json';
20
22
 
21
23
  const blob = {
22
24
  recoveryShare: `0001${'ab'.repeat(48)}`,
@@ -379,3 +381,76 @@ describe('escrow parsing', () => {
379
381
  expect(parseEscrowReleasePlaintext(maximum)).toEqual(maximum);
380
382
  });
381
383
  });
384
+
385
+ // D21 cross-language contract: the enclave's `canonical_brand` (crypto.rs)
386
+ // loads the same fixture and must reach the identical result for each case.
387
+ describe('escrow email brand (D21)', () => {
388
+ const cases = brandContract.cases as { name: string; input: string; expected: string | null }[];
389
+ const contact = { recoveryEmail: 'owner@example.com', recoveryLanguage: 'en' };
390
+
391
+ it.each(cases.map(c => [c.name, c] as const))('canonicalizes %s', (_name, testCase): void => {
392
+ expect(canonicalEscrowEmailBrand(testCase.input)).toBe(testCase.expected ?? undefined);
393
+ if (testCase.expected !== null) {
394
+ expect(canonicalEscrowEmailBrand(testCase.expected)).toBe(testCase.expected);
395
+ }
396
+ });
397
+
398
+ it.each(cases.map(c => [c.name, c] as const))(
399
+ 'blob and release parsers keep the canonical brand or omit it, never throw: %s',
400
+ (_name, testCase): void => {
401
+ const parsed = parseEscrowBlobPlaintext({
402
+ ...plaintext,
403
+ ...contact,
404
+ recoveryBrand: testCase.input,
405
+ });
406
+ const released = parseEscrowReleasePlaintext({
407
+ ...releasePlaintext,
408
+ ...contact,
409
+ recoveryBrand: testCase.input,
410
+ });
411
+ if (testCase.expected === null) {
412
+ expect(parsed).not.toHaveProperty('recoveryBrand');
413
+ expect(released).not.toHaveProperty('recoveryBrand');
414
+ } else {
415
+ expect(parsed.recoveryBrand).toBe(testCase.expected);
416
+ expect(released.recoveryBrand).toBe(testCase.expected);
417
+ }
418
+ }
419
+ );
420
+
421
+ it.each([null, 7, ['VetPass'], { name: 'VetPass' }, true])(
422
+ 'drops a mistyped brand %j instead of rejecting the plaintext',
423
+ (recoveryBrand): void => {
424
+ expect(parseEscrowBlobPlaintext({ ...plaintext, ...contact, recoveryBrand })).toEqual({
425
+ ...plaintext,
426
+ ...contact,
427
+ });
428
+ }
429
+ );
430
+
431
+ it('keeps the brand through encryptEscrowBlob/decryptEscrowBlob and sealing (regression guard: the parser used to drop unknown fields)', async (): Promise<void> => {
432
+ const keys = await generateEscrowKeyPair();
433
+ const envelope = await encryptEscrowBlob(
434
+ { ...blob, ...contact, recoveryBrand: ' Vet Pass ' },
435
+ keys.publicKey,
436
+ 'enclave-1'
437
+ );
438
+ expect(await decryptEscrowBlob(envelope, keys.privateKey)).toEqual({
439
+ ...plaintext,
440
+ ...contact,
441
+ recoveryBrand: 'Vet Pass',
442
+ });
443
+ const sealed = await sealEscrowRelease(
444
+ { ...release, ...contact, recoveryBrand: 'VetPass' },
445
+ keys.publicKey
446
+ );
447
+ expect((await openEscrowRelease(sealed, keys.privateKey)).recoveryBrand).toBe('VetPass');
448
+ });
449
+
450
+ it('keeps a brand with no contact (inert), matching the enclave', (): void => {
451
+ expect(parseEscrowBlobPlaintext({ ...plaintext, recoveryBrand: 'VetPass' })).toEqual({
452
+ ...plaintext,
453
+ recoveryBrand: 'VetPass',
454
+ });
455
+ });
456
+ });